aboutsummaryrefslogtreecommitdiffstats
path: root/engine
diff options
context:
space:
mode:
Diffstat (limited to 'engine')
-rw-r--r--engine/battle/animations.asm307
-rw-r--r--engine/battle/battle_transitions.asm4
-rw-r--r--engine/battle/common_text.asm16
-rw-r--r--engine/battle/core.asm550
-rw-r--r--engine/battle/draw_hud_pokeball_gfx.asm10
-rw-r--r--engine/battle/effects.asm59
-rw-r--r--engine/battle/end_of_battle.asm4
-rw-r--r--engine/battle/experience.asm22
-rw-r--r--engine/battle/ghost_marowak_anim.asm5
-rw-r--r--engine/battle/init_battle.asm272
-rw-r--r--engine/battle/link_battle_versus_text.asm3
-rw-r--r--engine/battle/misc.asm19
-rw-r--r--engine/battle/move_effects/transform.asm9
-rw-r--r--engine/battle/pikachu_entrance_anim.asm47
-rw-r--r--engine/battle/read_trainer_party.asm101
-rw-r--r--engine/battle/scale_sprites.asm7
-rw-r--r--engine/battle/trainer_ai.asm27
-rw-r--r--engine/battle/wild_encounters.asm7
-rw-r--r--engine/debug/debug_menu.asm1585
-rw-r--r--engine/debug/debug_party.asm117
-rw-r--r--engine/events/black_out.asm2
-rw-r--r--engine/events/card_key.asm8
-rw-r--r--engine/events/diploma.asm104
-rw-r--r--engine/events/diploma2.asm149
-rw-r--r--engine/events/elevator.asm6
-rw-r--r--engine/events/evolve_trade.asm28
-rw-r--r--engine/events/give_pokemon.asm5
-rw-r--r--engine/events/hidden_events/bench_guys.asm12
-rw-r--r--engine/events/hidden_events/bills_house_pc.asm7
-rw-r--r--engine/events/hidden_events/cinnabar_gym_quiz.asm56
-rw-r--r--engine/events/hidden_events/fanclub_pictures.asm23
-rw-r--r--engine/events/hidden_events/museum_fossils.asm28
-rw-r--r--engine/events/hidden_events/museum_fossils2.asm27
-rw-r--r--engine/events/hidden_events/oaks_lab_email.asm3
-rw-r--r--engine/events/hidden_events/route_15_binoculars.asm5
-rw-r--r--engine/events/hidden_events/safari_game.asm3
-rw-r--r--engine/events/hidden_events/school_blackboard.asm3
-rw-r--r--engine/events/hidden_events/vermilion_gym_trash.asm77
-rw-r--r--engine/events/hidden_events/vermilion_gym_trash2.asm108
-rw-r--r--engine/events/hidden_items.asm17
-rw-r--r--engine/events/in_game_trades.asm59
-rw-r--r--engine/events/pikachu_happiness.asm118
-rw-r--r--engine/events/poison.asm41
-rw-r--r--engine/events/pokecenter.asm101
-rw-r--r--engine/events/pokecenter_chansey.asm11
-rw-r--r--engine/events/prize_menu.asm9
-rw-r--r--engine/events/try_pikachu_movement.asm27
-rw-r--r--engine/events/vending_machine.asm3
-rw-r--r--engine/gfx/animated_objects.asm394
-rw-r--r--engine/gfx/bg_map_attributes.asm217
-rw-r--r--engine/gfx/hp_bar.asm4
-rw-r--r--engine/gfx/mon_icons.asm20
-rw-r--r--engine/gfx/palettes.asm532
-rw-r--r--engine/gfx/screen_effects.asm10
-rw-r--r--engine/gfx/sprite_oam.asm163
-rw-r--r--engine/items/inventory.asm5
-rw-r--r--engine/items/item_effects.asm475
-rw-r--r--engine/items/super_rod.asm41
-rw-r--r--engine/items/tms.asm6
-rw-r--r--engine/items/town_map.asm21
-rw-r--r--engine/joypad.asm36
-rw-r--r--engine/link/cable_club.asm52
-rw-r--r--engine/link/cable_club_npc.asm61
-rw-r--r--engine/link/print_waiting_text.asm3
-rw-r--r--engine/menus/display_text_id_init.asm9
-rw-r--r--engine/menus/draw_start_menu.asm8
-rw-r--r--engine/menus/league_pc.asm5
-rw-r--r--engine/menus/link_menu.asm918
-rw-r--r--engine/menus/main_menu.asm463
-rw-r--r--engine/menus/naming_screen.asm29
-rw-r--r--engine/menus/options.asm483
-rw-r--r--engine/menus/party_menu.asm14
-rw-r--r--engine/menus/players_pc.asm7
-rw-r--r--engine/menus/pokedex.asm360
-rw-r--r--engine/menus/save.asm185
-rw-r--r--engine/menus/start_sub_menus.asm38
-rw-r--r--engine/menus/text_box.asm36
-rw-r--r--engine/menus/unused_input.asm129
-rw-r--r--engine/minigame/surfing_pikachu.asm2863
-rw-r--r--engine/movie/credits.asm282
-rw-r--r--engine/movie/evolution.asm8
-rw-r--r--engine/movie/hall_of_fame.asm37
-rw-r--r--engine/movie/intro.asm354
-rw-r--r--engine/movie/intro_yellow.asm1090
-rw-r--r--engine/movie/oak_speech/clear_save.asm4
-rw-r--r--engine/movie/oak_speech/init_player_data.asm5
-rw-r--r--engine/movie/oak_speech/oak_speech.asm45
-rw-r--r--engine/movie/oak_speech/oak_speech2.asm6
-rw-r--r--engine/movie/splash.asm50
-rw-r--r--engine/movie/title.asm456
-rw-r--r--engine/movie/title_rb.asm (renamed from engine/movie/title2.asm)10
-rw-r--r--engine/movie/title_yellow.asm109
-rw-r--r--engine/movie/trade.asm26
-rw-r--r--engine/overworld/advance_player_sprite.asm244
-rw-r--r--engine/overworld/auto_movement.asm52
-rw-r--r--engine/overworld/cut.asm9
-rw-r--r--engine/overworld/cut2.asm2
-rw-r--r--engine/overworld/dungeon_warps.asm15
-rw-r--r--engine/overworld/dust_smoke.asm2
-rw-r--r--engine/overworld/elevator.asm6
-rw-r--r--engine/overworld/emotion_bubbles.asm24
-rw-r--r--engine/overworld/healing_machine.asm25
-rw-r--r--engine/overworld/hidden_events.asm34
-rw-r--r--engine/overworld/ledges.asm21
-rw-r--r--engine/overworld/map_sprites.asm594
-rw-r--r--engine/overworld/movement.asm385
-rw-r--r--engine/overworld/npc_movement_2.asm24
-rw-r--r--engine/overworld/player_animations.asm25
-rw-r--r--engine/overworld/player_state.asm21
-rw-r--r--engine/overworld/specific_script_flags.asm25
-rw-r--r--engine/overworld/sprite_collisions.asm44
-rw-r--r--engine/overworld/tilesets.asm17
-rw-r--r--engine/overworld/toggleable_objects.asm8
-rw-r--r--engine/overworld/turn_sprite.asm25
-rw-r--r--engine/overworld/unused_load_toggleable_object_data.asm46
-rw-r--r--engine/pikachu/pikachu_emotions.asm477
-rw-r--r--engine/pikachu/pikachu_follow.asm1578
-rw-r--r--engine/pikachu/pikachu_movement.asm1048
-rw-r--r--engine/pikachu/pikachu_pcm.asm165
-rw-r--r--engine/pikachu/pikachu_pic_animation.asm852
-rw-r--r--engine/pikachu/pikachu_status.asm260
-rw-r--r--engine/pikachu/respawn_overworld_pikachu.asm6
-rw-r--r--engine/play_time.asm61
-rw-r--r--engine/pokemon/add_mon.asm6
-rw-r--r--engine/pokemon/bills_pc.asm82
-rw-r--r--engine/pokemon/evos_moves.asm186
-rw-r--r--engine/pokemon/learn_move.asm30
-rw-r--r--engine/pokemon/load_mon_data.asm21
-rw-r--r--engine/pokemon/status_screen.asm26
-rw-r--r--engine/printer/printer.asm979
-rw-r--r--engine/printer/printer2.asm973
-rw-r--r--engine/printer/serial.asm632
-rw-r--r--engine/slots/slot_machine.asm21
133 files changed, 19947 insertions, 3384 deletions
diff --git a/engine/battle/animations.asm b/engine/battle/animations.asm
index eac4115a..aafb966e 100644
--- a/engine/battle/animations.asm
+++ b/engine/battle/animations.asm
@@ -15,6 +15,8 @@ DrawFrameBlock:
ld a, [wFBTileCounter]
inc a
ld [wFBTileCounter], a
+ ld a, $2
+ ld [wdef4], a
ld a, [wSubAnimTransform]
dec a
jr z, .flipHorizontalAndVertical ; SUBANIMTYPE_HVFLIP
@@ -46,6 +48,12 @@ DrawFrameBlock:
.finishCopying ; finish copying values to OAM (when subanimation not transformed)
add [hl] ; X offset
ld [de], a ; store X
+ cp 88
+ jr c, .asm_78056
+ ld a, [wdef4]
+ inc a
+ ld [wdef4], a
+.asm_78056
inc hl
inc de
ld a, [hli]
@@ -53,6 +61,9 @@ DrawFrameBlock:
ld [de], a ; store tile ID
inc de
ld a, [hli]
+ ld b, a
+ ld a, [wdef4]
+ or b
ld [de], a ; store flags
inc de
jp .nextTile
@@ -71,6 +82,12 @@ DrawFrameBlock:
ld a, 168
sub b ; flip X coordinate
ld [de], a ; store X
+ cp 88
+ jr c, .asm_78087
+ ld a, [wdef4]
+ inc a
+ ld [wdef4], a
+.asm_78087
inc hl
inc de
ld a, [hli]
@@ -90,7 +107,8 @@ DrawFrameBlock:
jr z, .storeFlags1
ld b, 0
.storeFlags1
- ld a, b
+ ld a, [wdef4]
+ or b
ld [de], a
inc de
jp .nextTile
@@ -107,6 +125,12 @@ DrawFrameBlock:
ld a, 168
sub b ; flip X coordinate
ld [de], a ; store X
+ cp 88
+ jr c, .asm_780c8
+ ld a, [wdef4]
+ inc a
+ ld [wdef4], a
+.asm_780c8
inc hl
inc de
ld a, [hli]
@@ -122,6 +146,9 @@ DrawFrameBlock:
.disableHorizontalFlip
res B_OAM_XFLIP, a
.storeFlags2
+ ld b, a
+ ld a, [wdef4]
+ or b
ld [de], a
inc de
.nextTile
@@ -176,12 +203,10 @@ PlayAnimation:
ld h, [hl]
ld l, a
.animationLoop
- vc_hook Stop_reducing_move_anim_flashing_Thunderbolt
+ vc_hook Stop_reducing_move_anim_flashing_Bubblebeam
ld a, [hli]
- vc_hook_red Stop_reducing_move_anim_flashing_Reflect
- vc_hook_blue Stop_reducing_move_anim_flashing_Self_Destruct
+ vc_hook Stop_reducing_move_anim_flashing_Mega_Punch
cp -1
- vc_hook_blue Stop_reducing_move_anim_flashing_Reflect
jr z, .AnimationOver
cp FIRST_SE_ID ; is this subanimation or a special effect?
jr c, .playSubanimation
@@ -249,58 +274,53 @@ PlayAnimation:
push af
ld a, [wAnimPalette]
ldh [rOBP0], a
+ call UpdateCGBPal_OBP0
call LoadMoveAnimationTiles
- vc_hook Reduce_move_anim_flashing_Mega_Punch_Self_Destruct_Explosion
call LoadSubanimation
call PlaySubanimation
- vc_hook_red Stop_reducing_move_anim_flashing_Mega_Punch
- vc_hook_blue Stop_reducing_move_anim_flashing_Mega_Punch_Explosion
pop af
- vc_hook_red Stop_reducing_move_anim_flashing_Blizzard
+ vc_hook Stop_reducing_move_anim_flashing_Thunderbolt
ldh [rOBP0], a
+ vc_hook Stop_reducing_move_anim_flashing_Explosion
+ call UpdateCGBPal_OBP0
.nextAnimationCommand
- vc_hook_red Stop_reducing_move_anim_flashing_Hyper_Beam
- vc_hook_blue Stop_reducing_move_anim_flashing_Bubblebeam_Hyper_Beam_Blizzard
- pop hl
vc_hook Stop_reducing_move_anim_flashing_Guillotine
+ pop hl
+ vc_hook Stop_reducing_move_anim_flashing_Mega_Kick
jr .animationLoop
.AnimationOver
+ vc_hook Stop_reducing_move_anim_flashing_Blizzard
ret
LoadSubanimation:
- vc_hook Reduce_move_anim_flashing_Guillotine
ld a, [wSubAnimAddrPtr + 1]
- vc_hook Reduce_move_anim_flashing_Mega_Kick
ld h, a
- vc_hook_red Reduce_move_anim_flashing_Blizzard
ld a, [wSubAnimAddrPtr]
- vc_hook_red Reduce_move_anim_flashing_Self_Destruct
ld l, a
ld a, [hli]
ld e, a
- vc_hook Reduce_move_anim_flashing_Explosion
ld a, [hl]
- vc_hook Reduce_move_anim_flashing_Thunderbolt
ld d, a ; de = address of subanimation
+ vc_hook Reduce_move_anim_flashing_Bubblebeam
ld a, [de]
- vc_hook_blue Reduce_move_anim_flashing_Rock_Slide
+ vc_hook Reduce_move_anim_flashing_Mega_Kick
ld b, a
- vc_hook Reduce_move_anim_flashing_Spore
+ vc_hook Reduce_move_anim_flashing_Guillotine
and %00011111
- vc_hook Reduce_move_anim_flashing_Bubblebeam
+ vc_hook Reduce_move_anim_flashing_Mega_Punch_Explosion_Self_Destruct
ld [wSubAnimCounter], a ; number of frame blocks
- vc_hook_red Reduce_move_anim_flashing_Rock_Slide
- vc_hook_blue Reduce_move_anim_flashing_Self_Destruct
+ vc_hook Reduce_move_anim_flashing_Blizzard
ld a, b
+ vc_hook Reduce_move_anim_flashing_Thunderbolt
and %11100000
cp SUBANIMTYPE_ENEMY << 5
- vc_hook_blue Reduce_move_anim_flashing_Blizzard
+ vc_hook Reduce_move_anim_flashing_Reflect
jr nz, .isNotTypeEnemy
; subanim type enemy
call GetSubanimationTransform2
jr .saveTransformation
.isNotTypeEnemy
- vc_hook Reduce_move_anim_flashing_Hyper_Beam
+ vc_hook Reduce_move_anim_flashing_Self_Destruct
call GetSubanimationTransform1
.saveTransformation
; place the upper 3 bits of a into bits 0-2 of a before storing
@@ -331,7 +351,7 @@ LoadSubanimation:
; sets the transform to SUBANIMTYPE_NORMAL if it's the player's turn
; sets the transform to the subanimation type if it's the enemy's turn
GetSubanimationTransform1:
- vc_hook Reduce_move_anim_flashing_Reflect
+ vc_hook Reduce_move_anim_flashing_Explosion
ld b, a
ldh a, [hWhoseTurn]
and a
@@ -392,12 +412,7 @@ MoveAnimationTiles1:
INCBIN "gfx/battle/move_anim_1.2bpp"
SlotMachineTiles2:
-IF DEF(_RED)
- INCBIN "gfx/slots/red_slots_2.2bpp"
-ENDC
-IF DEF(_BLUE)
- INCBIN "gfx/slots/blue_slots_2.2bpp"
-ENDC
+ INCBIN "gfx/slots/slots_2.2bpp"
SlotMachineTiles2End:
MoveAnimation:
@@ -425,19 +440,17 @@ MoveAnimation:
jr nz, .animationsDisabled
call ShareMoveAnimations
call PlayAnimation
- vc_hook_red Stop_reducing_move_anim_flashing_Bubblebeam_Mega_Kick
- vc_hook_blue Stop_reducing_move_anim_flashing_Spore
jr .next
.animationsDisabled
ld c, 30
call DelayFrames
.next
- vc_hook_red Stop_reducing_move_anim_flashing
- vc_hook_blue Stop_reducing_move_anim_flashing_Rock_Slide_Dream_Eater
+ vc_hook Stop_reducing_move_anim_flashing_Reflect
call PlayApplyingAttackAnimation ; shake the screen or flash the pic in and out (to show damage)
.animationFinished
call WaitForSoundToFinish
xor a
+ vc_hook Stop_reducing_move_anim_flashing_Haze_Hyper_Beam
ld [wSubAnimSubEntryAddr], a
ld [wUnusedMoveAnimByte], a
ld [wSubAnimTransform], a
@@ -475,6 +488,7 @@ ShareMoveAnimations:
PlayApplyingAttackAnimation:
; Generic animation that shows after the move's individual animation
; Different animation depending on whether the move has an additional effect and on whose turn it is
+ vc_hook Stop_reducing_move_anim_flashing_Self_Destruct
ld a, [wAnimationType]
and a
ret z
@@ -564,17 +578,42 @@ SetAnimationPalette:
ld b, $f0
.next
ld a, b
+ vc_hook Reduce_move_anim_flashing_Hyper_Beam
ldh [rOBP0], a
ld a, $6c
+ vc_hook Reduce_move_anim_flashing_Haze
ldh [rOBP1], a
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
ret
.notSGB
ld a, $e4
ld [wAnimPalette], a
- vc_hook Reduce_move_anim_flashing_Dream_Eater
ldh [rOBP0], a
ld a, $6c
ldh [rOBP1], a
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
+ ret
+
+Func_78e98:
+ call SaveScreenTilesToBuffer2
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call ClearScreen
+ ld h, HIGH(vBGMap0)
+ call WriteLowerByteOfBGMapAndEnableBGTransfer
+ call Delay3
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call LoadScreenTilesFromBuffer2
+ ld h, HIGH(vBGMap1)
+
+WriteLowerByteOfBGMapAndEnableBGTransfer:
+ ld l, LOW(vBGMap0)
+ call BattleAnimCopyTileMapToVRAM
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
ret
PlaySubanimation:
@@ -690,6 +729,7 @@ DoBallTossSpecialEffects:
ldh a, [rOBP0]
xor %00111100 ; complement colors 1 and 2
ldh [rOBP0], a
+ call UpdateCGBPal_OBP0
.skipFlashingEffect
ld a, [wSubAnimCounter]
cp 11 ; is it the beginning of the subanimation?
@@ -979,6 +1019,7 @@ AnimationFlashScreenLong:
cp 1
jr z, .endOfPalettes
ldh [rBGP], a
+ call UpdateCGBPal_BGP
call FlashScreenLongDelay
jr .innerLoop
.endOfPalettes
@@ -987,7 +1028,6 @@ AnimationFlashScreenLong:
ld [wFlashScreenLongCounter], a
pop hl
jr nz, .loop
- vc_hook_red Stop_reducing_move_anim_flashing_Psychic
ret
; BG palettes
@@ -1042,14 +1082,17 @@ AnimationFlashScreen:
push af ; save initial palette
ld a, %00011011 ; 0, 1, 2, 3 (inverted colors)
ldh [rBGP], a
+ call UpdateCGBPal_BGP
ld c, 2
call DelayFrames
xor a ; white out background
ldh [rBGP], a
+ call UpdateCGBPal_BGP
ld c, 2
call DelayFrames
pop af
ldh [rBGP], a ; restore initial palette
+ call UpdateCGBPal_BGP
ret
AnimationDarkScreenPalette:
@@ -1095,6 +1138,7 @@ SetAnimationBGPalette:
ld a, c
.next
ldh [rBGP], a
+ call UpdateCGBPal_BGP
ret
AnimationUnusedShakeScreen: ; unreferenced
@@ -1141,15 +1185,30 @@ AnimationWaterDropletsEverywhere:
_AnimationWaterDroplets:
ld hl, wShadowOAM
.loop
+ ld a, $1
+ ld [wdef4], a
ld a, [wBaseCoordY]
ld [hli], a ; Y
+ cp 40
+ jr c, .asm_792d7
+ ld a, [wdef4]
+ inc a
+ ld [wdef4], a
+.asm_792d7
ld a, [wBaseCoordX]
add 27
ld [wBaseCoordX], a
ld [hli], a ; X
+ cp 88
+ jr c, .asm_792ee
+ ld a, [wdef4]
+ add $2
+ and $3
+ ld [wdef4], a
+.asm_792ee
ld a, [wDropletTile]
ld [hli], a ; tile
- xor a
+ ld a, [wdef4]
ld [hli], a ; attribute
ld a, [wBaseCoordX]
cp 144
@@ -1292,16 +1351,30 @@ BattleAnimWriteOAMEntry:
; Y coordinate = e (increased by 8 each call, before the write to OAM)
; X coordinate = [wBaseCoordX]
; tile = d
-; attributes = 0
+; attributes = variable (depending on coords)
+ ld a, $1
+ ld [wdef4], a
ld a, e
add 8
ld e, a
ld [hli], a
+ cp 40
+ jr c, .asm_793d8
+ ld a, [wdef4]
+ inc a
+ ld [wdef4], a
+.asm_793d8
ld a, [wBaseCoordX]
ld [hli], a
+ cp 88
+ jr c, .asm_793e8
+ ld a, [wdef4]
+ add $2
+ ld [wdef4], a
+.asm_793e8
ld a, d
ld [hli], a
- xor a
+ ld a, [wdef4]
ld [hli], a
ret
@@ -1506,6 +1579,8 @@ AnimationSpiralBallsInward:
ld a, [hl]
cp $ff
jr z, .done
+ ld a, $2
+ ld [wdef4], a
ld a, [wSpiralBallsBaseY]
add [hl]
ld [de], a ; Y
@@ -1514,9 +1589,20 @@ AnimationSpiralBallsInward:
ld a, [wSpiralBallsBaseX]
add [hl]
ld [de], a ; X
+ cp 88
+ jr c, .asm_79524
+ ld a, $3
+ ld [wdef4], a
+.asm_79524
inc hl
inc de
inc de
+ ld a, [de]
+ and $f0
+ ld b, a
+ ld a, [wdef4]
+ or b
+ ld [de], a
inc de
dec c
jr nz, .innerLoop
@@ -1835,10 +1921,8 @@ _AnimationSlideMonOff:
.PlayerNextTile
ld a, [hl]
add 7
-; This is a bug. The lower right corner tile of the mon back pic is blanked
-; while the mon is sliding off the screen. It should compare with the max tile
-; plus one instead.
- cp $61
+; bugfix: compares against the max tile + 1 as opposed to the max tile
+ cp $62
ret c
ld a, ' '
ret
@@ -1975,18 +2059,24 @@ AnimationSubstitute:
CopyMonsterSpriteData:
ld bc, TILE_SIZE
ld a, BANK(MonsterSprite)
- jp FarCopyData2
+ jp FarCopyData
HideSubstituteShowMonAnim:
ldh a, [hWhoseTurn]
and a
ld hl, wPlayerMonMinimized
+ ld de, wPlayerBattleStatus1
+ ld bc, wPlayerMoveNum
ld a, [wPlayerBattleStatus2]
jr z, .next1
ld hl, wEnemyMonMinimized
+ ld de, wEnemyBattleStatus1
+ ld bc, wEnemyMoveNum
ld a, [wEnemyBattleStatus2]
.next1
push hl
+ push de
+ push bc
; if the substitute broke, slide it down, else slide it offscreen horizontally
bit HAS_SUBSTITUTE_UP, a
jr nz, .substituteStillUp
@@ -1995,12 +2085,65 @@ HideSubstituteShowMonAnim:
.substituteStillUp
call AnimationSlideMonOff
.next2
+ pop bc
+ pop de
+ ld a, [de]
+ bit INVULNERABLE, a
pop hl
+ jr nz, .invulnerable
+ ld a, [bc]
+ cp FLY
+ jr z, .flyOrDig
+ cp DIG
+ jr z, .flyOrDig
+.invulnerable
ld a, [hl]
and a
jp nz, AnimationMinimizeMon
call AnimationFlashMonPic
jp AnimationShowMonPic
+.flyOrDig
+ ldh a, [hWhoseTurn]
+ and a
+ jr nz, .enemy
+ ld a, [wPlayerMonMinimized]
+ and a
+ jr nz, .monIsMinimized
+ ld a, [wBattleMonSpecies]
+ ld [wCurPartySpecies], a
+ ld [wCurSpecies], a
+ call GetMonHeader
+ predef LoadMonBackPic
+ ret
+.enemy
+ ld a, [wEnemyMonMinimized]
+ and a
+ jr nz, .monIsMinimized
+ ld a, [wEnemyMonSpecies]
+ ld [wCurPartySpecies], a
+ ld [wCurSpecies], a
+ call GetMonHeader
+ ld de, vFrontPic
+ jp LoadMonFrontSprite
+.monIsMinimized
+ ld hl, wTempPic
+ push hl
+ xor a
+ ld bc, 7 * 7 * $10
+ call FillMemory
+ pop hl
+ ld de, $194
+ add hl, de
+ ld de, MinimizedMonSprite
+ ld c, MinimizedMonSpriteEnd - MinimizedMonSprite
+.loop
+ ld a, [de]
+ ld [hli], a
+ ld [hli], a
+ inc de
+ dec c
+ jr nz, .loop
+ jp CopyTempPicToMonPic
ReshowSubstituteAnim:
call AnimationSlideMonOff
@@ -2068,6 +2211,23 @@ AnimationHideEnemyMonPic:
ldh [hAutoBGTransferEnabled], a
jp Delay3
+Func_79929:
+ ld hl, wPlayerMonMinimized
+ ldh a, [hWhoseTurn]
+ and a
+ jr z, .playerTurn
+ ld hl, wEnemyMonMinimized
+.playerTurn
+ ld a, [hl]
+ and a
+ jr z, .notMinimized
+ call AnimationMinimizeMon
+ ret
+.notMinimized
+ call AnimationFlashMonPic
+ call AnimationShowMonPic
+ ret
+
InitMultipleObjectsOAM:
; Writes c OAM entries with tile d.
; Sets their Y coordinates to sequential multiples of 8, starting from 0.
@@ -2089,6 +2249,8 @@ InitMultipleObjectsOAM:
jr nz, .loop
ret
+ ret ; unreferenced
+
AnimationHideMonPic:
; Hides the mon's sprite.
ldh a, [hWhoseTurn]
@@ -2189,8 +2351,7 @@ AnimCopyRowRight:
jr nz, AnimCopyRowRight
ret
-; only used by the unreferenced PlayIntroMoveSound
-GetIntroMoveSound:
+GetIntroMoveSound: ; unreferenced
ld a, b
call GetMoveSound
ld b, a
@@ -2311,17 +2472,13 @@ INCLUDE "data/tilemaps.asm"
AnimationLeavesFalling:
; Makes leaves float down from the top of the screen. This is used
; in Razor Leaf's animation.
- ldh a, [rOBP0]
- push af
ld a, [wAnimPalette]
ldh [rOBP0], a
+ call UpdateCGBPal_OBP0
ld d, $37 ; leaf tile
ld a, 3 ; number of leaves
ld [wNumFallingObjects], a
- call AnimationFallingObjects
- pop af
- ldh [rOBP0], a
- ret
+ jp AnimationFallingObjects
AnimationPetalsFalling:
; Makes lots of petals fall down from the top of the screen. It's used in
@@ -2376,6 +2533,8 @@ FallingObjects_UpdateOAMEntry:
; movement byte.
ld hl, wShadowOAM
add hl, de
+ ld a, $1
+ ld [wdef4], a
ld a, [hl]
inc a
inc a
@@ -2384,6 +2543,12 @@ FallingObjects_UpdateOAMEntry:
ld a, SCREEN_HEIGHT_PX + OAM_Y_OFS ; if Y >= 112, put it off-screen
.next
ld [hli], a ; Y
+ cp 40
+ jr c, .asm_79e51
+ ld a, [wdef4]
+ inc a
+ ld [wdef4], a
+.asm_79e51
ld a, [wFallingObjectMovementByte]
ld b, a
ld de, FallingObjects_DeltaXs
@@ -2400,6 +2565,13 @@ FallingObjects_UpdateOAMEntry:
ld a, [de]
add [hl]
ld [hli], a ; X
+ cp 88
+ jr c, .asm_79e75
+ ld a, [wdef4]
+ add $2
+ and $3
+ ld [wdef4], a
+.asm_79e75
inc hl
xor a ; no horizontal flip
jr .next2
@@ -2409,9 +2581,19 @@ FallingObjects_UpdateOAMEntry:
ld a, [hl]
sub b
ld [hli], a ; X
+ cp 88
+ jr c, .asm_79e5c
+ ld a, [wdef4]
+ add $2
+ and $3
+ ld [wdef4], a
+.asm_79e5c
inc hl
ld a, OAM_XFLIP
.next2
+ ld b, a
+ ld a, [wdef4]
+ or b
ld [hl], a ; attribute
ret
@@ -2496,6 +2678,14 @@ AnimationShakeEnemyHUD:
ld hl, vBGMap1 - $20 * 7
call BattleAnimCopyTileMapToVRAM
+; update BGMap attributes
+ ldh a, [hOnCGB]
+ and a
+ jr z, .notCGB
+ ld c, 13
+ farcall LoadBGMapAttributes
+.notCGB
+
; Move the window so that the row below the enemy HUD (in BG map 0) lines up
; with the top row of the window on the screen. This makes it so that the window
; covers everything below the enemy HD with a copy that looks just like what
@@ -2529,13 +2719,18 @@ AnimationShakeEnemyHUD:
ldh [hWY], a
ld hl, vBGMap1
call BattleAnimCopyTileMapToVRAM
+; update BGMap attributes
+ ldh a, [hOnCGB]
+ and a
+ jr z, .notCGB2
+ ld c, 11
+ farcall LoadBGMapAttributes
+.notCGB2
xor a
ldh [hWY], a
call SaveScreenTilesToBuffer1
ld hl, vBGMap0
call BattleAnimCopyTileMapToVRAM
- call ClearScreen
- call Delay3
call LoadScreenTilesFromBuffer1
ld hl, vBGMap1
jp BattleAnimCopyTileMapToVRAM
diff --git a/engine/battle/battle_transitions.asm b/engine/battle/battle_transitions.asm
index a37a5054..cd0af180 100644
--- a/engine/battle/battle_transitions.asm
+++ b/engine/battle/battle_transitions.asm
@@ -171,6 +171,9 @@ BattleTransition_BlackScreen:
ldh [rBGP], a
ldh [rOBP0], a
ldh [rOBP1], a
+ call UpdateCGBPal_BGP
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
ret
; for non-dungeon trainer battles
@@ -334,6 +337,7 @@ BattleTransition_FlashScreen_:
cp 1
jr z, .done
ldh [rBGP], a
+ call UpdateCGBPal_BGP
ld c, 2
call DelayFrames
jr .loop
diff --git a/engine/battle/common_text.asm b/engine/battle/common_text.asm
index 9e954877..8a07b382 100644
--- a/engine/battle/common_text.asm
+++ b/engine/battle/common_text.asm
@@ -8,8 +8,20 @@ PrintBeginningBattleText:
cp POKEMON_TOWER_7F + 1
jr c, .pokemonTower
.notPokemonTower
+ ld a, [wBattleType]
+ cp BATTLE_TYPE_PIKACHU
+ jr nz, .notPikachuBattle
+ callfar IsPlayerPikachuAsleepInParty
+ ldpikacry e, PikachuCry37
+ jr c, .asm_f4026
+ ldpikacry e, PikachuCry11
+.asm_f4026
+ callfar PlayPikachuSoundClip
+ jr .continue
+.notPikachuBattle
ld a, [wEnemyMonSpecies2]
call PlayCry
+.continue
ld hl, WildMonAppearedText
ld a, [wMoveMissed]
and a
@@ -23,9 +35,13 @@ PrintBeginningBattleText:
call DelayFrames
ld hl, TrainerWantsToFightText
.wildBattle
+ ld a, [wBattleType]
+ and a
+ jr nz, .doNotDrawPokeballs
push hl
callfar DrawAllPokeballs
pop hl
+.doNotDrawPokeballs
call PrintText
jr .done
.pokemonTower
diff --git a/engine/battle/core.asm b/engine/battle/core.asm
index fc17ec44..33301e58 100644
--- a/engine/battle/core.asm
+++ b/engine/battle/core.asm
@@ -67,6 +67,9 @@ SlidePlayerAndEnemySilhouettesOnScreen:
ldh [rBGP], a
ldh [rOBP0], a
ldh [rOBP1], a
+ call UpdateCGBPal_BGP
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
.slideSilhouettesLoop ; slide silhouettes of the player's pic and the enemy's pic onto the screen
ld h, b
ld l, $40
@@ -156,10 +159,16 @@ StartBattle:
call DelayFrames
call SaveScreenTilesToBuffer1
.checkAnyPartyAlive
+ ld a, [wBattleType]
+ cp BATTLE_TYPE_RUN
+ jp z, .specialBattle
+ cp BATTLE_TYPE_PIKACHU
+ jp z, .specialBattle
call AnyPartyAlive
ld a, d
and a
jp z, HandlePlayerBlackOut ; jump if no mon is alive
+.specialBattle
call LoadScreenTilesFromBuffer1
ld a, [wBattleType]
and a ; is it a normal battle?
@@ -893,6 +902,11 @@ ReplaceFaintedEnemyMon:
ld hl, wEnemyHPBarColor
ld e, $30
call GetBattleHealthBarColor
+ ldpal a, SHADE_BLACK, SHADE_DARK, SHADE_LIGHT, SHADE_WHITE
+ ldh [rOBP0], a
+ ldh [rOBP1], a
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
callfar DrawEnemyPokeballs
ld a, [wLinkState]
cp LINK_STATE_BATTLING
@@ -958,9 +972,7 @@ TrainerDefeatedText:
PlayBattleVictoryMusic:
push af
- ld a, SFX_STOP_ALL_MUSIC
- ld [wNewSoundID], a
- call PlaySoundWaitForCurrent
+ call StopAllMusic
ld c, BANK(Music_DefeatedTrainer)
pop af
call PlayMusic
@@ -1014,6 +1026,7 @@ RemoveFaintedPlayerMon:
ld a, DISABLE_LOW_HEALTH_ALARM
ld [wLowHealthAlarm], a
call WaitForSoundToFinish
+ xor a
.skipWaitForSound
; a is 0, so this zeroes the enemy's accumulated damage.
ld hl, wEnemyBideAccumulatedDamage
@@ -1038,10 +1051,36 @@ RemoveFaintedPlayerMon:
and a ; was this called by HandleEnemyMonFainted?
ret z ; if so, return
+ ld a, [wPlayerMonNumber]
+ ld [wWhichPokemon], a
+ callfar IsThisPartyMonStarterPikachu
+ jr nc, .notPlayerPikachu
+ ldpikacry e, PikachuCry4
+ callfar PlayPikachuSoundClip
+ jr .printText
+.notPlayerPikachu
ld a, [wBattleMonSpecies]
call PlayCry
+.printText
ld hl, PlayerMonFaintedText
- jp PrintText
+ call PrintText
+ ld a, [wPlayerMonNumber]
+ ld [wWhichPokemon], a
+ ld a, [wBattleMonLevel]
+ ld b, a
+ ld a, [wEnemyMonLevel]
+ sub b ; enemylevel - playerlevel
+ ; are we stronger than the opposing pokemon?
+ jr c, .regularFaint ; if so, deduct happiness regularly
+
+ cp 30 ; is the enemy 30 levels greater than us?
+ jr nc, .carelessTrainer ; if so, punish the player for being careless, as they shouldn't be fighting a very high leveled trainer with such a level difference
+.regularFaint
+ farcall_ModifyPikachuHappiness PIKAHAPPY_FAINTED
+ ret
+.carelessTrainer
+ farcall_ModifyPikachuHappiness PIKAHAPPY_CARELESSTRAINER
+ ret
PlayerMonFaintedText:
text_far _PlayerMonFaintedText
@@ -1098,7 +1137,7 @@ ChooseNextMon:
ld a, [wLinkState]
cp LINK_STATE_BATTLING
jr nz, .notLinkBattle
- inc a ; 1
+ ld a, 1
ld [wActionResultOrTookBattleTurn], a
call LinkBattleExchangeData
.notLinkBattle
@@ -1499,6 +1538,8 @@ TryRunningFromBattle:
ld a, [wBattleType]
cp BATTLE_TYPE_SAFARI
jp z, .canEscape ; jump if it's a safari battle
+ cp BATTLE_TYPE_RUN
+ jp z, .canEscape ; hurry, get away?
ld a, [wLinkState]
cp LINK_STATE_BATTLING
jp z, .canEscape
@@ -1754,19 +1795,46 @@ SendOutMon:
call RunPaletteCommand
ld hl, wEnemyBattleStatus1
res USING_TRAPPING_MOVE, [hl]
+ callfar IsThisPartyMonStarterPikachu
+ jr c, .starterPikachu
ld a, $1
ldh [hWhoseTurn], a
ld a, POOF_ANIM
call PlayMoveAnimation
hlcoord 4, 11
predef AnimateSendingOutMon
+ jr .playRegularCry
+.starterPikachu
+ xor a
+ ldh [hWhoseTurn], a
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ callfar StarterPikachuBattleEntranceAnimation
+ callfar IsPlayerPikachuAsleepInParty
+ ldpikacry e, PikachuCry37
+ jr c, .asm_3cd81
+ ldpikacry e, PikachuCry11
+.asm_3cd81
+ callfar PlayPikachuSoundClip
+ jr .done
+.playRegularCry
ld a, [wCurPartySpecies]
call PlayCry
+.done
call PrintEmptyString
jp SaveScreenTilesToBuffer1
; show 2 stages of the player mon getting smaller before disappearing
AnimateRetreatingPlayerMon:
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wPlayerMonNumber]
+ ld [wWhichPokemon], a
+ callfar IsThisPartyMonStarterPikachu
+ pop bc
+ ld a, b
+ ld [wWhichPokemon], a
+ jr c, .starterPikachu
hlcoord 1, 5
lb bc, 7, 7
call ClearScreenArea
@@ -1790,10 +1858,17 @@ AnimateRetreatingPlayerMon:
call .clearScreenArea
ld a, $4c
ldcoord_a 5, 11
+ jr .clearScreenArea
+.starterPikachu
+ xor a
+ ldh [hWhoseTurn], a
+ callfar AnimationSlideMonOff
+ ret
.clearScreenArea
hlcoord 1, 5
lb bc, 7, 7
- jp ClearScreenArea
+ call ClearScreenArea
+ ret
; Copies player's current pokemon's current HP, party pos, and status into the party
; struct data so it stays after battle or switching
@@ -2015,41 +2090,52 @@ DisplayBattleMenu::
.menuselected
ld [wTextBoxID], a
call DisplayTextBoxID
- ; handle menu input if it's not the old man tutorial
+ ; handle menu input if it's not the old man tutorial or prof. oak pikachu battle
ld a, [wBattleType]
- ASSERT BATTLE_TYPE_OLD_MAN == 1
- dec a
- jp nz, .handleBattleMenuInput
-; the following happens for the old man tutorial
+ cp BATTLE_TYPE_OLD_MAN
+ jr z, .doSimulatedMenuInput
+ cp BATTLE_TYPE_PIKACHU
+ jr z, .doSimulatedMenuInput
+ jp .handleBattleMenuInput
+; the following happens for the old man tutorial and prof. oak pikachu battle
+.doSimulatedMenuInput
; Temporarily save the player name in wLinkEnemyTrainerName.
; Since wLinkEnemyTrainerName == wGrassRate, this affects wild encounters.
; The wGrassRate byte and following wGrassMons buffer are supposed
; to get overwritten when entering a map with wild Pokémon,
; but an oversight prevents this in Cinnabar and Route 21,
; so the infamous MissingNo. glitch can show up.
+ ; However, this has been fixed in Yellow.
ld hl, wPlayerName
ld de, wLinkEnemyTrainerName
ld bc, NAME_LENGTH
call CopyData
ld hl, .oldManName
+ ld a, [wBattleType]
+ dec a
+ jr z, .useOldManName
+ ld hl, .profOakName
+.useOldManName
ld de, wPlayerName
ld bc, NAME_LENGTH
call CopyData
; the following simulates the keystrokes by drawing menus on screen
hlcoord 9, 14
ld [hl], '▶'
- ld c, 80
+ ld c, 20
call DelayFrames
ld [hl], ' '
hlcoord 9, 16
ld [hl], '▶'
- ld c, 50
+ ld c, 20
call DelayFrames
ld [hl], '▷'
ld a, $2 ; select the "ITEM" menu
jp .upperLeftMenuItemWasNotSelected
.oldManName
db "OLD MAN@"
+.profOakName
+ db "PROF.OAK@"
.handleBattleMenuInput
ld a, [wBattleAndStartSavedMenuItem]
ld [wCurrentMenuItem], a
@@ -2132,6 +2218,9 @@ DisplayBattleMenu::
.AButtonPressed
call PlaceUnfilledArrowMenuCursor
ld a, [wBattleType]
+ cp BATTLE_TYPE_RUN
+ jr z, .handleUnusedBattle
+ ld a, [wBattleType]
cp BATTLE_TYPE_SAFARI
ld a, [wCurrentMenuItem]
ld [wBattleAndStartSavedMenuItem], a
@@ -2163,7 +2252,18 @@ DisplayBattleMenu::
.throwSafariBallWasSelected
ld a, SAFARI_BALL
ld [wCurItem], a
- jr UseBagItem
+ jp UseBagItem
+.handleUnusedBattle
+ ld a, [wCurrentMenuItem]
+ cp $3
+ jp z, BattleMenu_RunWasSelected
+ ld hl, .RunAwayText
+ call PrintText
+ jp DisplayBattleMenu
+
+.RunAwayText
+ text_far _RunAwayText
+ text_end
.upperLeftMenuItemWasNotSelected ; a menu item other than the upper left item was selected
cp $2
@@ -2200,18 +2300,22 @@ BagWasSelected:
call DrawHUDsAndHPBars
.next
ld a, [wBattleType]
- dec a ; is it the old man tutorial?
- jr nz, DisplayPlayerBag ; no, it is a normal battle
- ld hl, OldManItemList
+ cp BATTLE_TYPE_OLD_MAN ; is it the old man tutorial?
+ jr z, .simulatedInputBattle
+ cp BATTLE_TYPE_PIKACHU ; is it the prof oak battle with pikachu?
+ jr z, .simulatedInputBattle
+ jr DisplayPlayerBag
+.simulatedInputBattle
+ ld hl, SimulatedInputBattleItemList
ld a, l
ld [wListPointer], a
ld a, h
ld [wListPointer + 1], a
jr DisplayBagMenu
-OldManItemList:
+SimulatedInputBattleItemList:
db 1 ; # items
- db POKE_BALL, 50
+ db POKE_BALL, 1
db -1 ; end
DisplayPlayerBag:
@@ -2371,6 +2475,8 @@ PartyMenuOrRockOrRun:
predef StatusScreen
predef StatusScreen2
; now we need to reload the enemy mon pic
+ ld a, 1
+ ldh [hWhoseTurn], a
ld a, [wEnemyBattleStatus2]
bit HAS_SUBSTITUTE_UP, a ; does the enemy mon have a substitute?
ld hl, AnimationSubstitute
@@ -2490,8 +2596,7 @@ MoveSelectionMenu:
ld hl, wBattleMonMoves
call .loadmoves
hlcoord 4, 12
- ld b, 4
- ld c, 14
+ lb bc, 4, 14
di ; out of pure coincidence, it is possible for vblank to occur between the di and ei
; so it is necessary to put the di ei block to not cause tearing
call TextBoxBorder
@@ -2509,8 +2614,7 @@ MoveSelectionMenu:
ld hl, wEnemyMonMoves
call .loadmoves
hlcoord 0, 7
- ld b, 4
- ld c, 14
+ lb bc, 4, 14
call TextBoxBorder
hlcoord 2, 8
call .writemoves
@@ -2524,8 +2628,7 @@ MoveSelectionMenu:
call AddNTimes
call .loadmoves
hlcoord 4, 7
- ld b, 4
- ld c, 14
+ lb bc, 4, 14
call TextBoxBorder
hlcoord 6, 8
call .writemoves
@@ -2539,8 +2642,6 @@ MoveSelectionMenu:
ld a, [wMoveMenuType]
cp $1
jr z, .selectedmoveknown
- ld a, $1
- jr nc, .selectedmoveknown
ld a, [wPlayerMoveListIndex]
inc a
.selectedmoveknown
@@ -2617,6 +2718,14 @@ SelectMenuItem:
jp nz, SelectMenuItem_CursorDown
bit B_PAD_SELECT, a
jp nz, SwapMovesInMenu
+IF DEF(_DEBUG)
+ bit B_PAD_START, a
+ jp nz, Func_3d4f5
+ bit B_PAD_RIGHT, a
+ jp nz, Func_3d529
+ bit B_PAD_LEFT, a
+ jp nz, Func_3d523
+ENDC
bit B_PAD_B, a
push af
xor a
@@ -2712,6 +2821,58 @@ SelectMenuItem_CursorDown:
ld [wCurrentMenuItem], a
jp SelectMenuItem
+Func_3d4f5:
+IF DEF(_DEBUG)
+ ASSERT B_PAD_START == BIT_TRAINER_BATTLE
+ENDC
+ bit BIT_TRAINER_BATTLE, a
+ ld a, $0
+ jr nz, .asm_3d4fd
+ ld a, $1
+.asm_3d4fd
+ ldh [hWhoseTurn], a
+ call LoadScreenTilesFromBuffer1
+ call Func_3d536
+ ld a, [wTestBattlePlayerSelectedMove]
+ and a
+ jp z, MoveSelectionMenu
+ ld [wAnimationID], a
+ xor a
+ ld [wAnimationType], a
+ predef MoveAnimation
+ callfar Func_78e98
+ jp MoveSelectionMenu
+
+Func_3d523:
+ ld a, [wTestBattlePlayerSelectedMove]
+ dec a
+ jr asm_3d52d
+Func_3d529:
+ ld a, [wTestBattlePlayerSelectedMove]
+ inc a
+asm_3d52d:
+ ld [wTestBattlePlayerSelectedMove], a
+ call Func_3d536
+ jp MoveSelectionMenu
+
+Func_3d536:
+ hlcoord 10, 16
+ lb bc, 2, 10
+ call ClearScreenArea
+ hlcoord 10, 17
+ ld de, wTestBattlePlayerSelectedMove
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ ld a, [wTestBattlePlayerSelectedMove]
+ and a
+ ret z
+ cp STRUGGLE
+ ret nc
+ ld [wNamedObjectIndex], a
+ call GetMoveName
+ hlcoord 13, 17
+ jp PlaceString
+
AnyMoveToSelect:
; return z and Struggle as the selected move if all moves have 0 PP and/or are disabled
ld a, STRUGGLE
@@ -2745,7 +2906,10 @@ AnyMoveToSelect:
or c
jr .handleDisabledMovePPLoop
.allMovesChecked
- and a ; any PP left?
+; bugfix: only check PP value and not PP up bits
+; in case all other moves have no PP left and a move has a PP up used on it
+; and a non-PP up move is disabled
+ and $3f ; any PP left?
ret nz ; return if a move has PP left
.noMovesLeft
ld hl, NoMovesLeftText
@@ -2760,6 +2924,14 @@ NoMovesLeftText:
text_end
SwapMovesInMenu:
+IF DEF(_DEBUG)
+ ld a, [wStatusFlags7]
+ bit BIT_TEST_BATTLE, a
+ jp nz, Func_3d4f5
+ENDC
+ ld a, [wPlayerBattleStatus3]
+ bit TRANSFORMED, a
+ jp nz, MoveSelectionMenu
ld a, [wMenuItemToSwap]
and a
jr z, .noMenuItemSelected
@@ -2839,8 +3011,7 @@ PrintMenuItem:
xor a
ldh [hAutoBGTransferEnabled], a
hlcoord 0, 8
- ld b, 3
- ld c, 9
+ lb bc, 3, 9
call TextBoxBorder
ld a, [wPlayerDisabledMove]
and a
@@ -2907,7 +3078,7 @@ PrintMenuItem:
jp Delay3
DisabledText:
- db "disabled!@"
+ db "Disabled!@"
TypeText:
db "TYPE@"
@@ -3043,7 +3214,7 @@ LinkBattleExchangeData:
jr z, .syncLoop1
vc_hook Wireless_end_exchange
vc_patch Wireless_net_delay_1
-IF DEF(_RED_VC) || DEF(_BLUE_VC)
+IF DEF(_YELLOW_VC)
ld b, 26
ELSE
ld b, 10
@@ -3056,7 +3227,7 @@ ENDC
jr nz, .syncLoop2
vc_hook Wireless_start_send_zero_bytes
vc_patch Wireless_net_delay_2
-IF DEF(_RED_VC) || DEF(_BLUE_VC)
+IF DEF(_YELLOW_VC)
ld b, 26
ELSE
ld b, 10
@@ -4887,7 +5058,7 @@ AttackSubstitute:
ldh a, [hWhoseTurn]
xor $01
ldh [hWhoseTurn], a
- callfar HideSubstituteShowMonAnim ; animate the substitute breaking
+ callfar Func_79929 ; animate the substitute breaking
; flip the turn back to the way it was
ldh a, [hWhoseTurn]
xor $01
@@ -5218,6 +5389,17 @@ AIGetTypeEffectiveness:
inc hl
jr .loop
.done
+ ; 40% chance for Lorelei's Dewgong to ignore type effectiveness?
+ ld a, [wTrainerClass]
+ cp LORELEI
+ jr nz, .ok
+ ld a, [wEnemyMonSpecies]
+ cp DEWGONG
+ jr nz, .ok
+ call BattleRandom
+ cp $66 ; 40 percent
+ ret c
+.ok
ld a, [hl]
ld [wTypeEffectiveness], a ; store damage multiplier
ret
@@ -6201,13 +6383,17 @@ SwapPlayerAndEnemyLevels:
; (for use when scrolling the player sprite and enemy's silhouettes on screen)
LoadPlayerBackPic:
ld a, [wBattleType]
- dec a ; is it the old man tutorial?
- ld de, RedPicBack
- jr nz, .next
ld de, OldManPicBack
+ cp BATTLE_TYPE_OLD_MAN ; is it the old man tutorial?
+ jr z, .next
+ ld de, ProfOakPicBack
+ cp BATTLE_TYPE_PIKACHU ; is it the pikachu battle at the beginning of the game?
+ jr z, .next
+ ld de, RedPicBack
.next
ld a, BANK(RedPicBack)
ASSERT BANK(RedPicBack) == BANK(OldManPicBack)
+ ASSERT BANK(RedPicBack) == BANK(ProfOakPicBack)
call UncompressSpriteFromDE
predef ScaleSpriteByTwo
ld hl, wShadowOAM
@@ -6230,6 +6416,8 @@ LoadPlayerBackPic:
ld [hli], a ; OAM tile number
inc a ; increment tile number
ldh [hOAMTile], a
+ ld a, $2
+ ld [hl], a
inc hl
dec c
jr nz, .innerLoop
@@ -6243,18 +6431,15 @@ LoadPlayerBackPic:
jr nz, .loop
ld de, vBackPic
call InterlaceMergeSpriteBuffers
- ld a, RAMG_SRAM_ENABLE
- ld [rRAMG], a
- xor a
- ld [rRAMB], a
+ ld a, BANK("Sprite Buffers")
+ call OpenSRAM
ld hl, vSprites
ld de, sSpriteBuffer1
ldh a, [hLoadedROMBank]
ld b, a
ld c, PIC_SIZE
call CopyVideoData
- xor a
- ld [rRAMG], a
+ call CloseSRAM
ld a, $31
ldh [hStartTileID], a
hlcoord 1, 5
@@ -6562,7 +6747,7 @@ BattleRandom:
pop hl
vc_hook Unknown_BattleRandom_ret_c
vc_patch BattleRandom_ret
-IF DEF(_RED_VC) || DEF(_BLUE_VC)
+IF DEF(_YELLOW_VC)
ret
ELSE
ret c
@@ -6634,280 +6819,7 @@ HandleExplodingAnimation:
; fallthrough
PlayMoveAnimation:
ld [wAnimationID], a
- vc_hook_red Reduce_move_anim_flashing_Confusion
- call Delay3
- vc_hook_red Reduce_move_anim_flashing_Psychic
- predef_jump MoveAnimation
-
-InitBattle::
- ld a, [wCurOpponent]
- and a
- jr z, DetermineWildOpponent
-
-InitOpponent:
- ld a, [wCurOpponent]
- ld [wCurPartySpecies], a
- ld [wEnemyMonSpecies2], a
- jr InitBattleCommon
-
-DetermineWildOpponent:
- ld a, [wStatusFlags6]
- bit BIT_DEBUG_MODE, a
- jr z, .notDebugMode
- ldh a, [hJoyHeld]
- bit B_PAD_B, a ; disable wild encounters
- ret nz
-.notDebugMode
- ld a, [wNumberOfNoRandomBattleStepsLeft]
- and a
- ret nz
- callfar TryDoWildEncounter
- ret nz
-InitBattleCommon:
- ld a, [wMapPalOffset]
- push af
- ld hl, wLetterPrintingDelayFlags
- ld a, [hl]
- push af
- res BIT_TEXT_DELAY, [hl] ; no delay
- callfar InitBattleVariables
- ld a, [wEnemyMonSpecies2]
- sub OPP_ID_OFFSET
- jp c, InitWildBattle
- ld [wTrainerClass], a
- call GetTrainerInformation
- callfar ReadTrainer
- call DoBattleTransitionAndInitBattleVariables
- call _LoadTrainerPic
- xor a
- ld [wEnemyMonSpecies2], a
- ldh [hStartTileID], a
- dec a
- ld [wAICount], a
- hlcoord 12, 0
- predef CopyUncompressedPicToTilemap
- ld a, $ff
- ld [wEnemyMonPartyPos], a
- ld a, $2
- ld [wIsInBattle], a
- jp _InitBattleCommon
-
-InitWildBattle:
- ld a, $1
- ld [wIsInBattle], a
- call LoadEnemyMonData
- call DoBattleTransitionAndInitBattleVariables
- ld a, [wCurOpponent]
- cp RESTLESS_SOUL
- jr z, .isGhost
- call IsGhostBattle
- jr nz, .isNoGhost
-.isGhost
- ld hl, wMonHSpriteDim
- ld a, $66
- ld [hli], a ; write sprite dimensions
- ld bc, GhostPic
- ld a, c
- ld [hli], a ; write front sprite pointer
- ld [hl], b
- ld hl, wEnemyMonNick ; set name to "GHOST"
- ld_hli_a_string "GHOST@"
- ld a, [wCurPartySpecies]
- push af
- ld a, MON_GHOST
- ld [wCurPartySpecies], a
- ld de, vFrontPic
- call LoadMonFrontSprite ; load ghost sprite
- pop af
- ld [wCurPartySpecies], a
- jr .spriteLoaded
-.isNoGhost
- ld de, vFrontPic
- call LoadMonFrontSprite ; load mon sprite
-.spriteLoaded
- xor a
- ld [wTrainerClass], a
- ldh [hStartTileID], a
- hlcoord 12, 0
- predef CopyUncompressedPicToTilemap
-
-; common code that executes after init battle code specific to trainer or wild battles
-_InitBattleCommon:
- ld b, SET_PAL_BATTLE_BLACK
- call RunPaletteCommand
- call SlidePlayerAndEnemySilhouettesOnScreen
- xor a
- ldh [hAutoBGTransferEnabled], a
- ld hl, .emptyString
- call PrintText
- call SaveScreenTilesToBuffer1
- call ClearScreen
- ld a, HIGH(vBGMap0)
- ldh [hAutoBGTransferDest + 1], a
- ld a, $1
- ldh [hAutoBGTransferEnabled], a
call Delay3
- ld a, HIGH(vBGMap1)
- ldh [hAutoBGTransferDest + 1], a
- call LoadScreenTilesFromBuffer1
- hlcoord 9, 7
- lb bc, 5, 10
- call ClearScreenArea
- hlcoord 1, 0
- lb bc, 4, 10
- call ClearScreenArea
- call ClearSprites
- ld a, [wIsInBattle]
- dec a ; is it a wild battle?
- call z, DrawEnemyHUDAndHPBar ; draw enemy HUD and HP bar if it's a wild battle
- call StartBattle
- callfar EndOfBattle
- pop af
- ld [wLetterPrintingDelayFlags], a
- pop af
- ld [wMapPalOffset], a
- ld a, [wSavedTileAnimations]
- ldh [hTileAnimations], a
- scf
+ predef MoveAnimation
+ callfar Func_78e98
ret
-.emptyString
- db "@"
-
-_LoadTrainerPic:
- ld a, [wTrainerPicPointer]
- ld e, a
- ld a, [wTrainerPicPointer + 1]
- ld d, a ; de contains pointer to trainer pic
- ld a, [wLinkState]
- and a
- ld a, BANK("Trainer Pics")
- jr z, .loadSprite
- ld a, BANK(RedPicFront)
-.loadSprite
- call UncompressSpriteFromDE
- ld de, vFrontPic
- ld a, $77
- ld c, a
- jp LoadUncompressedSpriteData
-
-; unreferenced
-ResetCryModifiers:
- xor a
- ld [wFrequencyModifier], a
- ld [wTempoModifier], a
- jp PlaySound
-
-; animates the mon "growing" out of the pokeball
-AnimateSendingOutMon:
- ld a, [wPredefHL]
- ld h, a
- ld a, [wPredefHL + 1]
- ld l, a
- ldh a, [hStartTileID]
- ldh [hBaseTileID], a
- ld b, $4c
- ld a, [wIsInBattle]
- and a
- jr z, .notInBattle
- add b
- ld [hl], a
- call Delay3
- ld bc, -(SCREEN_WIDTH * 2 + 1)
- add hl, bc
- ld a, 1
- ld [wDownscaledMonSize], a
- lb bc, 3, 3
- predef CopyDownscaledMonTiles
- ld c, 4
- call DelayFrames
- ld bc, -(SCREEN_WIDTH * 2 + 1)
- add hl, bc
- xor a
- ld [wDownscaledMonSize], a
- lb bc, 5, 5
- predef CopyDownscaledMonTiles
- ld c, 5
- call DelayFrames
- ld bc, -(SCREEN_WIDTH * 2 + 1)
- jr .next
-.notInBattle
- ld bc, -(SCREEN_WIDTH * 6 + 3)
-.next
- add hl, bc
- ldh a, [hBaseTileID]
- add $31
- jr CopyUncompressedPicToHL
-
-CopyUncompressedPicToTilemap:
- ld a, [wPredefHL]
- ld h, a
- ld a, [wPredefHL + 1]
- ld l, a
- ldh a, [hStartTileID]
-CopyUncompressedPicToHL::
- lb bc, 7, 7
- ld de, SCREEN_WIDTH
- push af
- ld a, [wSpriteFlipped]
- and a
- jr nz, .flipped
- pop af
-.loop
- push bc
- push hl
-.innerLoop
- ld [hl], a
- add hl, de
- inc a
- dec c
- jr nz, .innerLoop
- pop hl
- inc hl
- pop bc
- dec b
- jr nz, .loop
- ret
-
-.flipped
- push bc
- ld b, 0
- dec c
- add hl, bc
- pop bc
- pop af
-.flippedLoop
- push bc
- push hl
-.flippedInnerLoop
- ld [hl], a
- add hl, de
- inc a
- dec c
- jr nz, .flippedInnerLoop
- pop hl
- dec hl
- pop bc
- dec b
- jr nz, .flippedLoop
- ret
-
-LoadMonBackPic:
-; Assumes the monster's attributes have
-; been loaded with GetMonHeader.
- ld a, [wBattleMonSpecies2]
- ld [wCurPartySpecies], a
- hlcoord 1, 5
- ld b, 7
- ld c, 8
- call ClearScreenArea
- ld hl, wMonHBackSprite - wMonHeader
- call UncompressMonSprite
- predef ScaleSpriteByTwo
- ld de, vBackPic
- call InterlaceMergeSpriteBuffers ; combine the two buffers to a single 2bpp sprite
- ld hl, vSprites
- ld de, vBackPic
- ld c, (2 * SPRITEBUFFERSIZE) / TILE_SIZE ; count of 16-byte chunks to be copied
- ldh a, [hLoadedROMBank]
- ld b, a
- jp CopyVideoData
diff --git a/engine/battle/draw_hud_pokeball_gfx.asm b/engine/battle/draw_hud_pokeball_gfx.asm
index adeaaf62..bf955040 100644
--- a/engine/battle/draw_hud_pokeball_gfx.asm
+++ b/engine/battle/draw_hud_pokeball_gfx.asm
@@ -27,6 +27,8 @@ SetupOwnPartyPokeballs:
ld [hl], a
ld a, 8
ld [wHUDPokeballGfxOffsetX], a
+ xor a
+ ld [wdef4], a
ld hl, wShadowOAM
jp WritePokeballOAMData
@@ -41,6 +43,8 @@ SetupEnemyPartyPokeballs:
ld [hl], $20
ld a, -8
ld [wHUDPokeballGfxOffsetX], a
+ ld a, $1
+ ld [wdef4], a
ld hl, wShadowOAMSprite06
jp WritePokeballOAMData
@@ -104,7 +108,7 @@ WritePokeballOAMData:
ld [hli], a
ld a, [de]
ld [hli], a
- xor a
+ ld a, [wdef4]
ld [hli], a
ld a, [wBaseCoordX]
ld b, a
@@ -174,6 +178,8 @@ SetupPlayerAndEnemyPokeballs:
ld [hl], $40
ld a, 8
ld [wHUDPokeballGfxOffsetX], a
+ xor a
+ ld [wdef4], a
ld hl, wShadowOAM
call WritePokeballOAMData
ld hl, wEnemyMons
@@ -183,6 +189,8 @@ SetupPlayerAndEnemyPokeballs:
ld a, $50
ld [hli], a
ld [hl], $68
+ ld a, $1
+ ld [wdef4], a
ld hl, wShadowOAMSprite06
jp WritePokeballOAMData
diff --git a/engine/battle/effects.asm b/engine/battle/effects.asm
index 20e792d8..185b7dad 100644
--- a/engine/battle/effects.asm
+++ b/engine/battle/effects.asm
@@ -60,6 +60,16 @@ SleepEffect:
call BattleRandom
and SLP_MASK
jr z, .setSleepCounter
+ ld b, a
+ ld a, [wUnknownSerialFlag_d499]
+ and a
+ jr z, .asm_3f1ba ; XXX stadium stuff?
+ ld a, b
+ and $3
+ jr z, .setSleepCounter
+ ld b, a
+.asm_3f1ba
+ ld a, b
ld [de], a
call PlayCurrentMoveAnimation2
ld hl, FellAsleepText
@@ -211,6 +221,16 @@ FreezeBurnParalyzeEffect:
cp b ; do target type 2 and move type match?
ret z ; return if they match
ld a, [wPlayerMoveEffect]
+ cp FREEZE_SIDE_EFFECT2 ; more stadium stuff
+ jr nz, .asm_3f2c7
+ ld a, [wUnknownSerialFlag_d499]
+ and a
+ ld a, FREEZE_SIDE_EFFECT1
+ ld b, 30 percent + 1
+ jr z, .regular_effectiveness
+ ld b, 10 percent + 1
+ jr .regular_effectiveness
+.asm_3f2c7
cp PARALYZE_SIDE_EFFECT1 + 1
ld b, 10 percent + 1
jr c, .regular_effectiveness
@@ -266,6 +286,16 @@ FreezeBurnParalyzeEffect:
cp b
ret z
ld a, [wEnemyMoveEffect]
+ cp FREEZE_SIDE_EFFECT2 ; more stadium stuff
+ jr nz, .asm_3f341
+ ld a, [wUnknownSerialFlag_d499]
+ and a
+ ld a, FREEZE_SIDE_EFFECT1
+ ld b, 30 percent + 1
+ jr z, .regular_effectiveness2
+ ld b, 10 percent + 1
+ jr .regular_effectiveness2
+.asm_3f341
cp PARALYZE_SIDE_EFFECT1 + 1
ld b, 10 percent + 1
jr c, .regular_effectiveness2
@@ -287,17 +317,23 @@ FreezeBurnParalyzeEffect:
ld a, 1 << PAR
ld [wBattleMonStatus], a
call QuarterSpeedDueToParalysis
+ ld a, SHAKE_SCREEN_ANIM
+ call PlayBattleAnimation2
jp PrintMayNotAttackText
.burn2
ld a, 1 << BRN
ld [wBattleMonStatus], a
call HalveAttackDueToBurn
+ ld a, SHAKE_SCREEN_ANIM
+ call PlayBattleAnimation2
ld hl, BurnedText
jp PrintText
.freeze2
; hyper beam bits aren't reset for opponent's side
ld a, 1 << FRZ
ld [wBattleMonStatus], a
+ ld a, SHAKE_SCREEN_ANIM
+ call PlayBattleAnimation2
ld hl, FrozenText
jp PrintText
@@ -476,9 +512,9 @@ UpdateStatDone:
bit HAS_SUBSTITUTE_UP, [hl]
push af
push bc
+ push de
ld hl, HideSubstituteShowMonAnim
ld b, BANK(HideSubstituteShowMonAnim)
- push de
call nz, Bankswitch
pop de
.notMinimize
@@ -979,6 +1015,9 @@ FlinchSideEffect:
ld hl, wPlayerBattleStatus1
ld de, wEnemyMoveEffect
.flinchSideEffect
+ ld a, [wLinkState]
+ cp LINK_STATE_BATTLING
+ call z, ClearHyperBeam
ld a, [de]
cp FLINCH_SIDE_EFFECT1
ld b, 10 percent + 1 ; chance of flinch (FLINCH_SIDE_EFFECT1)
@@ -1020,10 +1059,27 @@ ChargeEffect:
set INVULNERABLE, [hl] ; mon is now invulnerable to typical attacks (fly/dig)
ld b, SLIDE_DOWN_ANIM
.notDigOrFly
+ push de
+ push bc
+ inc hl ; battle status 2
+ push hl
+ ld a, [hl]
+ bit HAS_SUBSTITUTE_UP, a
+ ld hl, HideSubstituteShowMonAnim
+ ld b, BANK(HideSubstituteShowMonAnim)
+ call nz, Bankswitch
+ pop hl
+ pop bc
xor a
ld [wAnimationType], a
ld a, b
call PlayBattleAnimation
+ ld a, [hl]
+ bit HAS_SUBSTITUTE_UP, a
+ ld hl, ReshowSubstituteAnim
+ ld b, BANK(ReshowSubstituteAnim)
+ call nz, Bankswitch
+ pop de
ld a, [de]
ld [wChargeMoveNum], a
ld hl, ChargeMoveEffectText
@@ -1495,6 +1551,7 @@ PlayBattleAnimationGotID:
push de
push bc
predef MoveAnimation
+ callfar Func_78e98
pop bc
pop de
pop hl
diff --git a/engine/battle/end_of_battle.asm b/engine/battle/end_of_battle.asm
index 2feb50bd..2ae3f71f 100644
--- a/engine/battle/end_of_battle.asm
+++ b/engine/battle/end_of_battle.asm
@@ -10,6 +10,8 @@ EndOfBattle:
ld a, [wEnemyMonStatus]
ld [hl], a
call ClearScreen
+ ld b, SET_PAL_OVERWORLD
+ call RunPaletteCommand
callfar DisplayLinkBattleVersusTextBox
ld a, [wBattleResult]
cp $1
@@ -43,6 +45,8 @@ EndOfBattle:
xor a
ld [wForceEvolution], a
predef EvolutionAfterBattle
+ ld d, $82
+ callfar UpdatePikachuMoodAfterBattle
.resetVariables
xor a
ld [wLowHealthAlarm], a ;disable low health alarm
diff --git a/engine/battle/experience.asm b/engine/battle/experience.asm
index f9f47f82..55d8d782 100644
--- a/engine/battle/experience.asm
+++ b/engine/battle/experience.asm
@@ -43,7 +43,7 @@ GainExperience:
inc de
jr .nextBaseStat
.maxStatExp ; if the upper byte also overflowed, then we have hit the max stat exp
- ld a, $ff
+ dec a ; ld a, $ff; a is 0 from previous check
ld [de], a
inc de
ld [de], a
@@ -233,13 +233,19 @@ GainExperience:
.recalcStatChanges
xor a ; battle mon
ld [wCalculateWhoseStats], a
- callfar CalculateModifiedStats
- callfar ApplyBurnAndParalysisPenaltiesToPlayer
- callfar ApplyBadgeStatBoosts
- callfar DrawPlayerHUDAndHPBar
- callfar PrintEmptyString
+ ld hl, CalculateModifiedStats
+ call CallBattleCore
+ ld hl, ApplyBurnAndParalysisPenaltiesToPlayer
+ call CallBattleCore
+ ld hl, ApplyBadgeStatBoosts
+ call CallBattleCore
+ ld hl, DrawPlayerHUDAndHPBar
+ call CallBattleCore
+ ld hl, PrintEmptyString
+ call CallBattleCore
call SaveScreenTilesToBuffer1
.printGrewLevelText
+ farcall_ModifyPikachuHappiness PIKAHAPPY_LEVELUP
ld hl, GrewLevelText
call PrintText
xor a ; PLAYER_PARTY_DATA
@@ -339,6 +345,10 @@ BoostExp:
ldh [hQuotient + 2], a
ret
+CallBattleCore:
+ ld b, BANK(BattleCore)
+ jp Bankswitch
+
GainedText:
text_far _GainedText
text_asm
diff --git a/engine/battle/ghost_marowak_anim.asm b/engine/battle/ghost_marowak_anim.asm
index efda9f8f..ab5f9017 100644
--- a/engine/battle/ghost_marowak_anim.asm
+++ b/engine/battle/ghost_marowak_anim.asm
@@ -2,6 +2,7 @@ MarowakAnim:
; animate the ghost being unveiled as a Marowak
ld a, $e4
ldh [rOBP1], a
+ call UpdateCGBPal_OBP1
call CopyMonPicFromBGToSpriteVRAM ; cover the BG ghost pic with a sprite ghost pic that looks the same
; now that the ghost pic is being displayed using sprites, clear the ghost pic from the BG tilemap
hlcoord 12, 0
@@ -27,6 +28,7 @@ MarowakAnim:
sla a
sla a
ldh [rOBP1], a
+ call UpdateCGBPal_OBP1
jr nz, .fadeOutGhostLoop
call ClearSprites
call CopyMonPicFromBGToSpriteVRAM ; copy Marowak pic from BG to sprite VRAM
@@ -40,6 +42,7 @@ MarowakAnim:
srl b
rra
ldh [rOBP1], a
+ call UpdateCGBPal_OBP1
ld a, b
and a
jr nz, .fadeInMarowakLoop
@@ -74,7 +77,7 @@ CopyMonPicFromBGToSpriteVRAM:
ld [hli], a
ld a, d
ld [hli], a
- ld a, OAM_PAL1
+ ld a, OAM_PAL1 | OAM_HIGH_PALS
ld [hli], a
inc d
dec c
diff --git a/engine/battle/init_battle.asm b/engine/battle/init_battle.asm
new file mode 100644
index 00000000..15dbb3d1
--- /dev/null
+++ b/engine/battle/init_battle.asm
@@ -0,0 +1,272 @@
+InitBattle::
+ ld a, [wCurOpponent]
+ and a
+ jr z, DetermineWildOpponent
+
+InitOpponent:
+ ld a, [wCurOpponent]
+ ld [wCurPartySpecies], a
+ ld [wEnemyMonSpecies2], a
+ jr InitBattleCommon
+
+DetermineWildOpponent:
+ ld a, [wStatusFlags6]
+ bit BIT_DEBUG_MODE, a
+ jr z, .notDebugMode
+ ldh a, [hJoyHeld]
+ bit B_PAD_B, a ; disable wild encounters
+ ret nz
+.notDebugMode
+ ld a, [wNumberOfNoRandomBattleStepsLeft]
+ and a
+ ret nz
+ callfar TryDoWildEncounter
+ ret nz
+InitBattleCommon:
+ ld a, [wMapPalOffset]
+ push af
+ ld hl, wLetterPrintingDelayFlags
+ ld a, [hl]
+ push af
+ res BIT_TEXT_DELAY, [hl] ; no delay
+ call InitBattleVariables
+ ld a, [wEnemyMonSpecies2]
+ sub OPP_ID_OFFSET
+ jp c, InitWildBattle
+ ld [wTrainerClass], a
+ call GetTrainerInformation
+ callfar ReadTrainer
+ callfar DoBattleTransitionAndInitBattleVariables
+ call _LoadTrainerPic
+ xor a
+ ld [wEnemyMonSpecies2], a
+ ldh [hStartTileID], a
+ dec a
+ ld [wAICount], a
+ hlcoord 12, 0
+ predef CopyUncompressedPicToTilemap
+ ld a, $ff
+ ld [wEnemyMonPartyPos], a
+ ld a, $2
+ ld [wIsInBattle], a
+
+; Is this a major story battle?
+ ld a, [wLoneAttackNo]
+ and a
+ jp z, _InitBattleCommon
+ farcall_ModifyPikachuHappiness PIKAHAPPY_GYMLEADER ; useless since already in bank3d
+ jp _InitBattleCommon
+
+InitWildBattle:
+ ld a, $1
+ ld [wIsInBattle], a
+ callfar LoadEnemyMonData
+ callfar DoBattleTransitionAndInitBattleVariables
+ ld a, [wCurOpponent]
+ cp RESTLESS_SOUL
+ jr z, .isGhost
+ callfar IsGhostBattle
+ jr nz, .isNoGhost
+.isGhost
+ ld hl, wMonHSpriteDim
+ ld a, $66
+ ld [hli], a ; write sprite dimensions
+ ld bc, GhostPic
+ ld a, c
+ ld [hli], a ; write front sprite pointer
+ ld [hl], b
+ ld hl, wEnemyMonNick ; set name to "GHOST"
+ ld_hli_a_string "GHOST@"
+ ld a, [wCurPartySpecies]
+ push af
+ ld a, MON_GHOST
+ ld [wCurPartySpecies], a
+ ld de, vFrontPic
+ call LoadMonFrontSprite ; load ghost sprite
+ pop af
+ ld [wCurPartySpecies], a
+ jr .spriteLoaded
+.isNoGhost
+ ld de, vFrontPic
+ call LoadMonFrontSprite ; load mon sprite
+.spriteLoaded
+ xor a
+ ld [wTrainerClass], a
+ ldh [hStartTileID], a
+ hlcoord 12, 0
+ predef CopyUncompressedPicToTilemap
+
+; common code that executes after init battle code specific to trainer or wild battles
+_InitBattleCommon:
+ ld b, SET_PAL_BATTLE_BLACK
+ call RunPaletteCommand
+ callfar SlidePlayerAndEnemySilhouettesOnScreen
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ld hl, .emptyString
+ call PrintText
+ call SaveScreenTilesToBuffer1
+ call ClearScreen
+ ld a, HIGH(vBGMap0)
+ ldh [hAutoBGTransferDest + 1], a
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call Delay3
+ ld a, HIGH(vBGMap1)
+ ldh [hAutoBGTransferDest + 1], a
+ call LoadScreenTilesFromBuffer1
+ hlcoord 9, 7
+ lb bc, 5, 10
+ call ClearScreenArea
+ hlcoord 1, 0
+ lb bc, 4, 10
+ call ClearScreenArea
+ call ClearSprites
+ ld a, [wIsInBattle]
+ dec a ; is it a wild battle?
+ ld hl, DrawEnemyHUDAndHPBar
+ ld b, BANK(DrawEnemyHUDAndHPBar)
+ call z, Bankswitch ; draw enemy HUD and HP bar if it's a wild battle
+ callfar StartBattle
+ callfar EndOfBattle
+ pop af
+ ld [wLetterPrintingDelayFlags], a
+ pop af
+ ld [wMapPalOffset], a
+ ld a, [wSavedTileAnimations]
+ ldh [hTileAnimations], a
+ scf
+ ret
+.emptyString
+ db "@"
+
+_LoadTrainerPic:
+ ld a, [wTrainerPicPointer]
+ ld e, a
+ ld a, [wTrainerPicPointer + 1]
+ ld d, a ; de contains pointer to trainer pic
+ ld a, [wLinkState]
+ and a
+ ld a, BANK("Trainer Pics")
+ jr z, .loadSprite
+ ld a, BANK(RedPicFront)
+.loadSprite
+ call UncompressSpriteFromDE
+ ld de, vFrontPic
+ ld a, $77
+ ld c, a
+ jp LoadUncompressedSpriteData
+
+LoadMonBackPic:
+; Assumes the monster's attributes have
+; been loaded with GetMonHeader.
+ ld a, [wBattleMonSpecies2]
+ ld [wCurPartySpecies], a
+ hlcoord 1, 5
+ lb bc, 7, 8
+ call ClearScreenArea
+ ld hl, wMonHBackSprite - wMonHeader
+ call UncompressMonSprite
+ predef ScaleSpriteByTwo
+ ld de, vBackPic
+ call InterlaceMergeSpriteBuffers ; combine the two buffers to a single 2bpp sprite
+ ld hl, vSprites
+ ld de, vBackPic
+ ld c, (2 * SPRITEBUFFERSIZE) / 16 ; count of 16-byte chunks to be copied
+ ldh a, [hLoadedROMBank]
+ ld b, a
+ jp CopyVideoData
+
+; animates the mon "growing" out of the pokeball
+AnimateSendingOutMon:
+ ld a, [wPredefHL]
+ ld h, a
+ ld a, [wPredefHL + 1]
+ ld l, a
+ ldh a, [hStartTileID]
+ ldh [hBaseTileID], a
+ ld b, $4c
+ ld a, [wIsInBattle]
+ and a
+ jr z, .notInBattle
+ add b
+ ld [hl], a
+ call Delay3
+ ld bc, -(SCREEN_WIDTH * 2 + 1)
+ add hl, bc
+ ld a, 1
+ ld [wDownscaledMonSize], a
+ lb bc, 3, 3
+ predef CopyDownscaledMonTiles
+ ld c, 4
+ call DelayFrames
+ ld bc, -(SCREEN_WIDTH * 2 + 1)
+ add hl, bc
+ xor a
+ ld [wDownscaledMonSize], a
+ lb bc, 5, 5
+ predef CopyDownscaledMonTiles
+ ld c, 5
+ call DelayFrames
+ ld bc, -(SCREEN_WIDTH * 2 + 1)
+ jr .next
+.notInBattle
+ ld bc, -(SCREEN_WIDTH * 6 + 3)
+.next
+ add hl, bc
+ ldh a, [hBaseTileID]
+ add $31
+ jr CopyUncompressedPicToHL
+
+CopyUncompressedPicToTilemap:
+ ld a, [wPredefHL]
+ ld h, a
+ ld a, [wPredefHL + 1]
+ ld l, a
+ ldh a, [hStartTileID]
+CopyUncompressedPicToHL::
+ lb bc, 7, 7
+ ld de, SCREEN_WIDTH
+ push af
+ ld a, [wSpriteFlipped]
+ and a
+ jr nz, .flipped
+ pop af
+.loop
+ push bc
+ push hl
+.innerLoop
+ ld [hl], a
+ add hl, de
+ inc a
+ dec c
+ jr nz, .innerLoop
+ pop hl
+ inc hl
+ pop bc
+ dec b
+ jr nz, .loop
+ ret
+
+.flipped
+ push bc
+ ld b, 0
+ dec c
+ add hl, bc
+ pop bc
+ pop af
+.flippedLoop
+ push bc
+ push hl
+.flippedInnerLoop
+ ld [hl], a
+ add hl, de
+ inc a
+ dec c
+ jr nz, .flippedInnerLoop
+ pop hl
+ dec hl
+ pop bc
+ dec b
+ jr nz, .flippedLoop
+ ret
diff --git a/engine/battle/link_battle_versus_text.asm b/engine/battle/link_battle_versus_text.asm
index 89201f4a..40c1aad9 100644
--- a/engine/battle/link_battle_versus_text.asm
+++ b/engine/battle/link_battle_versus_text.asm
@@ -2,8 +2,7 @@
DisplayLinkBattleVersusTextBox:
call LoadTextBoxTilePatterns
hlcoord 3, 4
- ld b, 7
- ld c, 12
+ lb bc, 7, 12
call TextBoxBorder
hlcoord 4, 5
ld de, wPlayerName
diff --git a/engine/battle/misc.asm b/engine/battle/misc.asm
index 3deebc61..45135a71 100644
--- a/engine/battle/misc.asm
+++ b/engine/battle/misc.asm
@@ -101,22 +101,3 @@ InitList:
ld a, b
ld [wItemPrices + 1], a
ret
-
-; get species of mon e in list [wMonDataLocation] for LoadMonData
-GetMonSpecies:
- ld hl, wPartySpecies
- ld a, [wMonDataLocation]
- and a
- jr z, .getSpecies
- dec a
- jr z, .enemyParty
- ld hl, wBoxSpecies
- jr .getSpecies
-.enemyParty
- ld hl, wEnemyPartySpecies
-.getSpecies
- ld d, 0
- add hl, de
- ld a, [hl]
- ld [wCurPartySpecies], a
- ret
diff --git a/engine/battle/move_effects/transform.asm b/engine/battle/move_effects/transform.asm
index 95e17833..e8bafe04 100644
--- a/engine/battle/move_effects/transform.asm
+++ b/engine/battle/move_effects/transform.asm
@@ -106,18 +106,11 @@ TransformEffect_:
and a
jr z, .lessThanFourMoves
ld a, 5
- ld [de], a
- inc de
- dec b
- jr nz, .copyPPLoop
- jr .copyStats
.lessThanFourMoves
-; 0 PP for blank moves
- xor a
ld [de], a
inc de
dec b
- jr nz, .lessThanFourMoves
+ jr nz, .copyPPLoop
.copyStats
; original (unmodified) stats and stat mods
pop hl
diff --git a/engine/battle/pikachu_entrance_anim.asm b/engine/battle/pikachu_entrance_anim.asm
new file mode 100644
index 00000000..8af65cee
--- /dev/null
+++ b/engine/battle/pikachu_entrance_anim.asm
@@ -0,0 +1,47 @@
+StarterPikachuBattleEntranceAnimation:
+ hlcoord 0, 5
+ ld c, 0
+.loop1
+ inc c
+ ld a, c
+ cp 9
+ ret z
+ ld d, 7 * 13
+ push bc
+ push hl
+.loop2
+ call .PlaceColumn
+ dec hl
+ ld a, d
+ sub 7
+ ld d, a
+ dec c
+ jr nz, .loop2
+ ld c, 2
+ call DelayFrames
+ pop hl
+ pop bc
+ inc hl
+ jr .loop1
+
+.PlaceColumn:
+ push hl
+ push de
+ push bc
+ ld e, 7
+.loop3
+ ld a, d
+ cp 7 * 7
+ jr nc, .okay
+ ld a, $7f
+.okay
+ ld [hl], a
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ inc d
+ dec e
+ jr nz, .loop3
+ pop bc
+ pop de
+ pop hl
+ ret
diff --git a/engine/battle/read_trainer_party.asm b/engine/battle/read_trainer_party.asm
index 1e173690..f4a2bef9 100644
--- a/engine/battle/read_trainer_party.asm
+++ b/engine/battle/read_trainer_party.asm
@@ -15,8 +15,8 @@ ReadTrainer:
ld [hl], a
; get the pointer to trainer data for this class
- ld a, [wCurOpponent]
- sub OPP_ID_OFFSET + 1 ; convert value from pokemon to trainer
+ ld a, [wTrainerClass] ; get trainer class
+ dec a
add a
ld hl, TrainerDataPointers
ld c, a
@@ -53,7 +53,7 @@ ReadTrainer:
.LoopTrainerData
ld a, [hli]
and a ; have we reached the end of the trainer data?
- jr z, .FinishUp
+ jp z, .AddAdditionalMoveData
ld [wCurPartySpecies], a
ld a, ENEMY_PARTY_DATA
ld [wMonDataLocation], a
@@ -68,7 +68,7 @@ ReadTrainer:
; - if [wLoneAttackNo] != 0, one pokemon on the team has a special move
ld a, [hli]
and a ; have we reached the end of the trainer data?
- jr z, .AddLoneMove
+ jr z, .AddAdditionalMoveData
ld [wCurEnemyLevel], a
ld a, [hli]
ld [wCurPartySpecies], a
@@ -78,69 +78,48 @@ ReadTrainer:
call AddPartyMon
pop hl
jr .SpecialTrainer
-.AddLoneMove
-; does the trainer have a single monster with a different move?
- ld a, [wLoneAttackNo] ; Brock is 01, Misty is 02, Erika is 04, etc
+.AddAdditionalMoveData
+; does the trainer have additional move data?
+ ld a, [wTrainerClass]
+ ld b, a
+ ld a, [wTrainerNo]
+ ld c, a
+ ld hl, SpecialTrainerMoves
+.loopAdditionalMoveData
+ ld a, [hli]
+ cp $ff
+ jr z, .FinishUp
+ cp b
+ jr nz, .loopSkipTrainer
+ ld a, [hli]
+ cp c
+ jr nz, .loopSkipTrainer
+ ld d, h
+ ld e, l
+.writeAdditionalMoveDataLoop
+ ld a, [de]
+ inc de
and a
- jr z, .AddTeamMove
+ jp z, .FinishUp
+ dec a
+ ld hl, wEnemyMon1Moves
+ ld bc, PARTYMON_STRUCT_LENGTH
+ call AddNTimes
+ ld a, [de]
+ inc de
dec a
- add a
ld c, a
ld b, 0
- ld hl, LoneMoves
add hl, bc
+ ld a, [de]
+ inc de
+ ld [hl], a
+ jr .writeAdditionalMoveDataLoop
+.loopSkipTrainer
ld a, [hli]
- ld d, [hl]
- ld hl, wEnemyMon1Moves + 2
- ld bc, PARTYMON_STRUCT_LENGTH
- call AddNTimes
- ld [hl], d
- jr .FinishUp
-.AddTeamMove
-; check if our trainer's team has special moves
-
-; get trainer class number
- ld a, [wCurOpponent]
- sub OPP_ID_OFFSET
- ld b, a
- ld hl, TeamMoves
-
-; iterate through entries in TeamMoves, checking each for our trainer class
-.IterateTeamMoves
- ld a, [hli]
- cp b
- jr z, .GiveTeamMoves ; is there a match?
- inc hl ; if not, go to the next entry
- inc a
- jr nz, .IterateTeamMoves
-
-; no matches found. is this trainer champion rival?
- ld a, b
- cp RIVAL3
- jr z, .ChampionRival
- jr .FinishUp ; nope
-.GiveTeamMoves
- ld a, [hl]
- ld [wEnemyMon5Moves + 2], a
- jr .FinishUp
-.ChampionRival ; give moves to his team
-
-; pidgeot
- ld a, SKY_ATTACK
- ld [wEnemyMon1Moves + 2], a
-
-; starter
- ld a, [wRivalStarter]
- cp STARTER3
- ld b, MEGA_DRAIN
- jr z, .GiveStarterMove
- cp STARTER1
- ld b, FIRE_BLAST
- jr z, .GiveStarterMove
- ld b, BLIZZARD ; must be squirtle
-.GiveStarterMove
- ld a, b
- ld [wEnemyMon6Moves + 2], a
+ and a
+ jr nz, .loopSkipTrainer
+ jr .loopAdditionalMoveData
.FinishUp
; clear wAmountMoneyWon addresses
xor a
diff --git a/engine/battle/scale_sprites.asm b/engine/battle/scale_sprites.asm
index 9e24c89d..4666f696 100644
--- a/engine/battle/scale_sprites.asm
+++ b/engine/battle/scale_sprites.asm
@@ -2,6 +2,13 @@
; assumes that input sprite chunks are 4x4 tiles, and the rightmost and bottommost 4 pixels will be ignored
; resulting in a 7*7 tile output sprite chunk
ScaleSpriteByTwo:
+ ld a, BANK("Sprite Buffers")
+ call OpenSRAM
+ call .ScaleSpriteByTwo
+ call CloseSRAM
+ ret
+
+.ScaleSpriteByTwo:
ld de, sSpriteBuffer1 + (4*4*8) - 5 ; last byte of input data, last 4 rows already skipped
ld hl, sSpriteBuffer0 + SPRITEBUFFERSIZE - 1 ; end of destination buffer
call ScaleLastSpriteColumnByTwo ; last tile column is special case
diff --git a/engine/battle/trainer_ai.asm b/engine/battle/trainer_ai.asm
index b9447779..d97ee076 100644
--- a/engine/battle/trainer_ai.asm
+++ b/engine/battle/trainer_ai.asm
@@ -288,13 +288,19 @@ INCLUDE "data/trainers/special_moves.asm"
INCLUDE "data/trainers/parties.asm"
TrainerAI:
- and a
ld a, [wIsInBattle]
dec a
- ret z ; if not a trainer, we're done here
+ jr z, .done ; if not a trainer, we're done here
ld a, [wLinkState]
cp LINK_STATE_BATTLING
- ret z ; if in a link battle, we're done as well
+ jr z, .done ; if in a link battle, we're done as well
+ ld a, [wEnemyBattleStatus1]
+ and 1 << CHARGING_UP | 1 << THRASHING_ABOUT | 1 << STORING_ENERGY
+ jr nz, .done ; don't follow trainer ai if opponent is in a locked state
+ ld a, [wEnemyBattleStatus2]
+ and 1 << USING_RAGE
+ jr nz, .done ; don't follow trainer ai if opponent is locked in rage
+ ; note that this doesn't check for hyper beam recharge which can cause problems
ld a, [wTrainerClass] ; what trainer class is this?
dec a
ld c, a
@@ -305,7 +311,7 @@ TrainerAI:
add hl, bc
ld a, [wAICount]
and a
- ret z ; if no AI uses left, we're done here
+ jr z, .done ; if no AI uses left, we're done here
inc hl
inc a
jr nz, .getpointer
@@ -318,6 +324,9 @@ TrainerAI:
ld l, a
call Random
jp hl
+.done
+ and a
+ ret
INCLUDE "data/trainers/ai_pointers.asm"
@@ -380,22 +389,22 @@ ErikaAI:
jp AIUseSuperPotion
KogaAI:
- cp 25 percent + 1
+ cp 13 percent - 1
ret nc
jp AIUseXAttack
BlaineAI:
cp 25 percent + 1
ret nc
+ ld a, 10
+ call AICheckIfHPBelowFraction
+ ret nc
jp AIUseSuperPotion
SabrinaAI:
cp 25 percent + 1
ret nc
- ld a, 10
- call AICheckIfHPBelowFraction
- ret nc
- jp AIUseHyperPotion
+ jp AIUseXDefend
Rival2AI:
cp 13 percent - 1
diff --git a/engine/battle/wild_encounters.asm b/engine/battle/wild_encounters.asm
index b5cf9f51..9fe0c96c 100644
--- a/engine/battle/wild_encounters.asm
+++ b/engine/battle/wild_encounters.asm
@@ -24,8 +24,9 @@ TryDoWildEncounter:
ld [wRepelRemainingSteps], a
.next
; determine if wild pokemon can appear in the half-block we're standing in
-; is the bottom right tile (9,9) of the half-block we're standing in a grass/water tile?
- hlcoord 9, 9
+; is the bottom left tile (8,9) of the half-block we're standing in a grass/water tile?
+; note that by using the bottom left tile, this prevents the "left-shore" tiles from generating grass encounters
+ hlcoord 8, 9
ld c, [hl]
ld a, [wGrassTile]
cp c
@@ -68,8 +69,6 @@ TryDoWildEncounter:
cp $14 ; is the bottom left tile (8,9) of the half-block we're standing in a water tile?
jr nz, .gotWildEncounterType ; else, it's treated as a grass tile by default
ld hl, wWaterMons
-; since the bottom right tile of a "left shore" half-block is $14 but the bottom left tile is not,
-; "left shore" half-blocks (such as the one in the east coast of Cinnabar) load grass encounters.
.gotWildEncounterType
ld b, 0
add hl, bc
diff --git a/engine/debug/debug_menu.asm b/engine/debug/debug_menu.asm
index 2946338f..a3933842 100644
--- a/engine/debug/debug_menu.asm
+++ b/engine/debug/debug_menu.asm
@@ -20,8 +20,7 @@ IF DEF(_DEBUG)
call RunDefaultPaletteCommand
hlcoord 5, 6
- ld b, 3
- ld c, 9
+ lb bc, 3, 9
call TextBoxBorder
hlcoord 7, 7
@@ -48,7 +47,8 @@ IF DEF(_DEBUG)
call HandleMenuInput
bit B_PAD_B, a
- jp nz, DisplayTitleScreen
+ ld hl, DisplayTitleScreen
+ ret nz
ld a, [wCurrentMenuItem]
and a ; FIGHT?
@@ -57,7 +57,8 @@ IF DEF(_DEBUG)
; DEBUG
ld hl, wStatusFlags6
set BIT_DEBUG_MODE, [hl]
- jp StartNewGameDebug
+ ld hl, StartNewGameDebug
+ ret
DebugBattlePlayerName:
db "Tom@"
@@ -68,13 +69,10 @@ DebugBattleRivalName:
DebugMenuOptions:
db "FIGHT"
next "DEBUG@"
-ELSE
- ret
-ENDC
TestBattle: ; unreferenced except in _DEBUG
-.loop
- call GBPalNormal
+ ld a, 1
+ ldh [hJoy7], a
; Don't mess around with obedience.
ld a, 1 << BIT_EARTHBADGE
@@ -83,38 +81,1569 @@ TestBattle: ; unreferenced except in _DEBUG
ld hl, wStatusFlags7
set BIT_TEST_BATTLE, [hl]
- ; wNumBagItems and wBagItems are not initialized here,
- ; and their garbage values happen to act as if EXP_ALL
- ; is in the bag at the end of the test battle.
- ; pokeyellow fixes this by initializing them with a
- ; list of items.
-
- ; Reset the party.
+ ld hl, wNumBagItems
+ ld de, Data_feded
+.loop
+ ld a, [de]
+ cp -1
+ jr z, .done
+ inc de
+ ld [wCurItem], a
+ ld a, [de]
+ inc de
+ ld [wItemQuantity], a
+ push de
+ call AddItemToInventory
+ pop de
+ jr .loop
+.done
+ call LoadHpBarAndStatusTilePatterns
+ call ClearScreen
+ call ClearSprites
+ hlcoord 0, 0
+ lb bc, 1, 18
+ call TextBoxBorder
+ hlcoord 6, 1
+ ld de, Text_fed18
+ call PlaceString
+ hlcoord 4, 4
+ ld de, Text_fed21
+ call PlaceString
+ hlcoord 1, 6
+ ld de, Text_fed30
+ call PlaceString
+ xor a
+ ld [wWhichPokemon], a
+ ld [wEnemyMon], a
+ ld [wEnemyMonLevel], a
+ ld [wTrainerClass], a
+ ld [wGrassMons + 1], a
+ ld b, a
+ ld c, a
+ ld hl, wEnemyPartySpecies
+ call Func_fe809
ld hl, wPartyCount
+ call Func_fe809
+ ld de, wPartySpecies
+ hlcoord 4, 6
+ ; fallthrough
+Func_fe7ca:
+ push hl
+ push bc
+ dec hl
+ ld a, '▶'
+ ld [hl], a
+ ld bc, 11
+ add hl, bc
+ ld a, ' '
+ ld [hl], a
+ push de
+ pop de
+ pop bc
+ pop hl
+ ; fallthrough
+Func_fe7db:
+ push bc
+ push de
+ call JoypadLowSensitivity
+ pop de
+ pop bc
+ ldh a, [hJoy5]
+ bit B_PAD_A, a
+ jp nz, Func_fe812
+ bit B_PAD_B, a
+ jp nz, Func_fe850
+ bit B_PAD_SELECT, a
+ jp nz, DebugMenu
+ bit B_PAD_START, a
+ jp nz, Func_fe97f
+ bit B_PAD_RIGHT, a
+ jp nz, Func_fe8a1
+ bit B_PAD_UP, a
+ jp nz, Func_fe85d
+ bit B_PAD_DOWN, a
+ jp nz, Func_fe880
+ jr Func_fe7db
+
+Func_fe809:
xor a
ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ret
+
+Func_fe812:
+ inc b
+ ld a, b
+ cp NUM_POKEMON_INDEXES + 1
+ jr c, Func_fe81a
+ xor a
+ ld b, a
+ ; fallthrough
+Func_fe81a:
+ ld [de], a
+ ld [wTempByteValue], a
+ push bc
+ push hl
+ push de
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ inc hl
+ push hl
+ ld de, Text_fed9c
+ call PlaceString
+ ld bc, hSavedMapTextPtr
+ add hl, bc
+ ld de, Text_fed9c
+ call PlaceString
+ pop hl
+ ld a, [wNamedObjectIndex]
+ and a
+ jr nz, .asm_fe845
+ ld de, Text_feda2
+ jr .asm_fe848
+.asm_fe845
+ call GetMonName
+.asm_fe848
+ call PlaceString
+ pop de
+ pop hl
+ pop bc
+ jr Func_fe7db
+
+Func_fe850:
+ dec b
+ ld a, b
+ cp OPP_ID_OFFSET + 1
+ jp c, Func_fe81a
+ ld a, NUM_POKEMON_INDEXES
+ ld b, a
+ jp Func_fe81a
+
+Func_fe85d:
+ ld a, [wWhichPokemon]
dec a
+ cp -1
+ jp z, Func_fe7db
+ ld [wWhichPokemon], a
+ dec de
+ dec hl
+ ld a, ' '
+ ld [hl], a
+ push bc
+ ld bc, hMovingBGTilesCounter1
+ add hl, bc
+ pop bc
+ ld a, '▶'
+ ld [hl], a
+ inc hl
+ push hl
+ call Func_fe964
+ pop hl
+ jp Func_fe7db
+
+Func_fe880:
+ ld a, [wWhichPokemon]
+ inc a
+ cp 6
+ jp nc, Func_fe7db
+ ld [wWhichPokemon], a
+ inc de
+ dec hl
+ ld a, ' '
+ ld [hl], a
+ ld bc, SCREEN_WIDTH * 2
+ add hl, bc
+ ld a, '▶'
ld [hl], a
+ inc hl
+ push hl
+ call Func_fe964
+ pop hl
+ jp Func_fe7db
- ; Give the player a level 20 Rhydon.
- ld a, RHYDON
+Func_fe8a1:
+ push hl
+ push bc
+ dec hl
+ ld a, ' '
+ ld [hl], a
+ ld bc, 11
+ add hl, bc
+ ld a, '▶'
+ ld [hl], a
+ pop bc
+ pop hl
+ ; fallthrough
+Func_fe8b0:
+ push bc
+ push de
+ call JoypadLowSensitivity
+ pop de
+ pop bc
+ ldh a, [hJoy5]
+ bit B_PAD_A, a
+ jp nz, Func_fe8d9
+ bit B_PAD_B, a
+ jp nz, Func_fe902
+ bit B_PAD_START, a
+ jp nz, Func_fe97f
+ bit B_PAD_LEFT, a
+ jp nz, Func_fe7ca
+ bit B_PAD_UP, a
+ jp nz, Func_fe912
+ bit B_PAD_DOWN, a
+ jp nz, Func_fe93b
+ jr Func_fe8b0
+
+Func_fe8d9:
+ inc c
+ ld a, c
+ cp MAX_LEVEL + 1
+ jr c, Func_fe8e2
+ ld a, 1
+ ld c, a
+ ; fallthrough
+Func_fe8e2:
+ ld a, [wWhichPokemon]
+ push de
+ ld de, wEnemyPartySpecies
+ add e
+ ld e, a
+ jr nc, .asm_fe8ee
+ inc d
+.asm_fe8ee
+ ld a, c
+ ld [de], a
+ push bc
+ push hl
+ ld bc, 11
+ add hl, bc
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ pop hl
+ pop bc
+ pop de
+ jp Func_fe8b0
+
+Func_fe902:
+ dec c
+ ld a, c
+ cp MAX_LEVEL + 1
+ jr nc, .asm_fe90c
+ and a
+ jp nz, Func_fe8e2
+.asm_fe90c
+ ld a, MAX_LEVEL
+ ld c, a
+ jp Func_fe8e2
+
+Func_fe912:
+ ld a, [wWhichPokemon]
+ dec a
+ cp -1
+ jp z, Func_fe8b0
+ ld [wWhichPokemon], a
+ dec de
+ push hl
+ ld bc, 10
+ add hl, bc
+ ld a, ' '
+ ld [hl], a
+ pop hl
+ ld bc, hMovingBGTilesCounter1
+ add hl, bc
+ push hl
+ ld bc, 10
+ add hl, bc
+ ld a, '▶'
+ ld [hl], a
+ call Func_fe964
+ pop hl
+ jp Func_fe8b0
+
+Func_fe93b:
+ ld a, [wWhichPokemon]
+ inc a
+ cp 6
+ jp nc, Func_fe8b0
+ ld [wWhichPokemon], a
+ inc de
+ push hl
+ ld bc, 10
+ add hl, bc
+ ld a, ' '
+ ld [hl], a
+ pop hl
+ ld bc, SCREEN_WIDTH * 2
+ add hl, bc
+ push hl
+ ld bc, 10
+ add hl, bc
+ ld a, '▶'
+ ld [hl], a
+ call Func_fe964
+ pop hl
+ jp Func_fe8b0
+
+Func_fe964:
+ ld hl, wPartySpecies
+ ld a, [wWhichPokemon]
+ add l
+ ld l, a
+ jr nc, .asm_fe96f
+ inc h
+.asm_fe96f
+ ld a, [hl]
+ ld b, a
+ ld hl, wEnemyPartySpecies
+ ld a, [wWhichPokemon]
+ add l
+ ld l, a
+ jr nc, .asm_fe97c
+ inc h
+.asm_fe97c
+ ld a, [hl]
+ ld c, a
+ ret
+
+Func_fe97f:
+ ld hl, wPartyCount
+ ld de, wEnemyPartyCount
+ xor a
+ ld [hl], a
+ inc hl
+ ld a, [hli]
+ ld b, a
+ ld c, 6
+ xor a
+ ld [wIsInBattle], a
+.asm_fe990
+ ld a, b
ld [wCurPartySpecies], a
- ld a, 20
+ ld a, [hl]
+ ld b, a
+ inc de
+ ld a, [de]
+ and a
+ jr z, .asm_fe9ab
ld [wCurEnemyLevel], a
xor a
ld [wMonDataLocation], a
- ld [wCurMap], a
+ ld a, [wCurPartySpecies]
+ and a
+ jr z, .asm_fe9ab
call AddPartyMon
+.asm_fe9ab
+ inc hl
+ dec c
+ jr nz, .asm_fe990
+ ld b, 7
+ ld hl, wPartySpecies
+ ld de, wEnemyPartyCount
+.asm_fe9b7
+ inc de
+ dec b
+ jp z, TestBattle
+ ld a, [hli]
+ and a
+ jr z, .asm_fe9b7
+ ld a, [de]
+ and a
+ jr z, .asm_fe9b7
+ hlcoord 0, 3
+ lb bc, 15, 20
+ call ClearScreenArea
+ hlcoord 0, 3
+ lb bc, 15, 20
+ call ClearScreenArea
+ hlcoord 0, 3
+ lb bc, 15, 20
+ call ClearScreenArea
+ ld c, 20
+ call DelayFrames
+ ld a, 1
+ ld [wIsInBattle], a
+ ld de, Text_feda8
+ ld a, [wGrassMons + 1]
+ cp MAX_LEVEL + 1
+ jr c, .asm_fe9fb
+ ld a, 2
+ ld [wIsInBattle], a
+ ld de, Text_fedb2
+.asm_fe9fb
+ hlcoord 1, 4
+ call PlaceString
+ hlcoord 1, 6
+ ld de, Text_fedbc
+ call PlaceString
+ ld a, [wEnemyMon]
+ ld b, a
+ ld a, [wIsInBattle]
+ dec a
+ jr z, .asm_fea40
+ ld a, [wTrainerClass]
+ ld [wTempByteValue], a
+ ld b, a
+ ld de, wTempByteValue
+ hlcoord 1, 8
+ push bc
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ hlcoord 5, 8
+ ld de, Text_fede2
+ call PlaceString
+ call GetTrainerName
+ hlcoord 5, 8
+ ld de, wTrainerName
+ call PlaceString
+ pop bc
+ jr .asm_fea65
+.asm_fea40
+ ld a, b
+ and a
+ jr z, .asm_fea65
+ ld de, wTempByteValue
+ ld [de], a
+ hlcoord 1, 8
+ push bc
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ hlcoord 5, 8
+ ld de, Text_fede2
+ call PlaceString
+ call GetMonName
+ hlcoord 5, 8
+ call PlaceString
+ pop bc
+.asm_fea65
+ ld a, [wEnemyMonLevel]
+ ld c, a
+ ld de, wTempByteValue
+ ld [de], a
+ hlcoord 16, 8
+ push bc
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ pop bc
+ ; fallthrough
+Func_fea78:
+ ld a, ' '
+ ldcoord_a 0, 8
+ ldcoord_a 15, 8
+ ld a, '▶'
+ ldcoord_a 0, 4
+ ; fallthrough
+Func_fea85:
+ push bc
+ call JoypadLowSensitivity
+ pop bc
+ ldh a, [hJoy5]
+ bit B_PAD_A, a
+ jp nz, Func_fea9d
+ bit B_PAD_START, a
+ jp nz, Func_fec10
+ bit B_PAD_DOWN, a
+ jp nz, Func_feae4
+ jr Func_fea85
- ; Fight against a level 20 Rhydon.
- ld a, RHYDON
- ld [wCurOpponent], a
+Func_fea9d:
+ hlcoord 1, 8
+ ld de, Text_fedcf
+ call PlaceString
+ hlcoord 5, 7
+ ld de, Text_fede2
+ call PlaceString
+ xor a
+ ld b, a
+ ld c, a
+ ld a, [wIsInBattle]
+ dec a
+ jr nz, .asm_feace
+ ld a, 2
+ ld [wIsInBattle], a
+ ld a, ' '
+ ldcoord_a 4, 3
+ hlcoord 1, 4
+ ld de, Text_fedb2
+ call PlaceString
+ jp Func_fea85
+.asm_feace
+ ld a, 1
+ ld [wIsInBattle], a
+ ld a, ' '
+ ldcoord_a 1, 3
+ hlcoord 1, 4
+ ld de, Text_feda8
+ call PlaceString
+ jp Func_fea85
+
+Func_feae4:
+ ld a, '▶'
+ ldcoord_a 0, 8
+ ld a, ' '
+ ldcoord_a 15, 8
+ ldcoord_a 0, 4
+ ; fallthrough
+Func_feaf1:
+ push bc
+ call JoypadLowSensitivity
+ pop bc
+ ldh a, [hJoy5]
+ bit B_PAD_A, a
+ jp nz, Func_feb13
+ bit B_PAD_B, a
+ jp nz, Func_feb82
+ bit B_PAD_START, a
+ jp nz, Func_fec10
+ bit B_PAD_RIGHT, a
+ jp nz, Func_febba
+ bit B_PAD_UP, a
+ jp nz, Func_fea78
+ jr Func_feaf1
+
+Func_feb13:
+ push bc
+ hlcoord 5, 7
+ ld de, Text_fede2
+ call PlaceString
+ hlcoord 5, 8
+ ld de, Text_fede2
+ call PlaceString
+ pop bc
+ ld a, [wIsInBattle]
+ dec a
+ jr z, Func_feb35.asm_feb5c
+ inc b
+ ld a, b
+ cp 48
+ jr c, Func_feb35
+ ld b, 1
+ ; fallthrough
+Func_feb35:
+ ld a, b
+ ld [wTempByteValue], a
+ ld de, wTempByteValue
+ hlcoord 1, 8
+ push bc
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ ld a, [wTempByteValue]
+ ld [wTrainerClass], a
+ call GetTrainerName
+ hlcoord 5, 8
+ ld de, wTrainerName
+ call PlaceString
+ pop bc
+ jp Func_feaf1
+.asm_feb5c
+ inc b
+ ld a, b
+ cp NUM_POKEMON_INDEXES + 1
+ jr c, Func_feb64
+ ld b, 1
+ ; fallthrough
+Func_feb64:
+ ld a, b
+ ld [wTempByteValue], a
+ ld de, wTempByteValue
+ hlcoord 1, 8
+ push bc
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ call GetMonName
+ hlcoord 5, 8
+ call PlaceString
+ pop bc
+ jp Func_feaf1
+
+Func_feb82:
+ push bc
+ hlcoord 5, 7
+ ld de, Text_fede2
+ call PlaceString
+ hlcoord 5, 8
+ ld de, Text_fede2
+ call PlaceString
+ pop bc
+ ld a, [wIsInBattle]
+ dec a
+ jr z, .asm_febab
+ dec b
+ ld a, b
+ cp 48
+ jr nc, .asm_feba6
+ and a
+ jp nz, Func_feb35
+.asm_feba6
+ ld b, 47
+ jp Func_feb35
+.asm_febab
+ dec b
+ ld a, b
+ cp NUM_POKEMON_INDEXES + 1
+ jr nc, .asm_febb5
+ and a
+ jp nz, Func_feb64
+.asm_febb5
+ ld b, NUM_POKEMON_INDEXES
+ jp Func_feb64
+
+Func_febba:
+ ld a, ' '
+ ldcoord_a 0, 8
+ ld a, '▶'
+ ldcoord_a 15, 8
+ ; fallthrough
+Func_febc4:
+ push bc
+ call JoypadLowSensitivity
+ pop bc
+ ldh a, [hJoy5]
+ bit B_PAD_A, a
+ jp nz, Func_febe6
+ bit B_PAD_B, a
+ jp nz, Func_fec01
+ bit B_PAD_START, a
+ jp nz, Func_fec10
+ bit B_PAD_LEFT, a
+ jp nz, Func_feae4
+ bit B_PAD_UP, a
+ jp nz, Func_fea78
+ jr Func_febc4
+
+Func_febe6:
+ inc c
+ ld a, c
+ cp MAX_LEVEL + 1
+ jr c, Func_febee
+ ld c, 1
+Func_febee:
+ hlcoord 16, 8
+ ld a, c
+ ld de, wCurEnemyLevel
+ ld [de], a
+ push bc
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ pop bc
+ jp Func_febc4
+Func_fec01:
+ dec c
+ ld a, c
+ cp MAX_LEVEL + 1
+ jr nc, .asm_fec0b
+ and a
+ jp nz, Func_febee
+.asm_fec0b
+ ld c, MAX_LEVEL
+ jp Func_febee
+
+Func_fec10:
+ ld a, b
+ and a
+ jp z, Func_fea78
+ ld a, c
+ and a
+ jp z, Func_fea78
+ ld a, [wIsInBattle]
+ dec a
+ jr z, .asm_fec28
+ ld a, b
+ add OPP_ID_OFFSET
+ ld b, a
+ ld a, c
+ ld [wTrainerNo], a
+.asm_fec28
+ ld a, c
+ ld [wCurEnemyLevel], a
+ ld a, b
+ ld [wCurOpponent], a
+ xor a
+ ld [wStatusFlags3], a
predef InitOpponent
+ xor a
+ ld [wNumRunAttempts], a
+ ld hl, wPlayerStatsToDouble
+ ld bc, wEnemyStatsToDouble - wPlayerStatsToDouble
+ call FillMemory
+ ld hl, wEnemyStatsToDouble
+ ld bc, wPlayerNumAttacksLeft - wEnemyStatsToDouble
+ call FillMemory
+ call LoadFontTilePatterns
+ call ClearScreen
+ call ClearSprites
+ ld a, %11100100
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ldh [rOBP1], a
+ call UpdateCGBPal_BGP
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
+ hlcoord 0, 0
+ lb bc, 1, 18
+ call TextBoxBorder
+ hlcoord 6, 1
+ ld de, Text_fed18
+ call PlaceString
+ hlcoord 4, 4
+ ld de, Text_fed21
+ call PlaceString
+ hlcoord 1, 6
+ ld de, Text_fed30
+ call PlaceString
+ ld de, wPartyCount
+ xor a
+ ld [de], a
+ ld [wWhichPokemon], a
+ inc de
+ hlcoord 4, 6
+ push de
+ push hl
+ ; fallthrough
+Func_fec9b:
+ ld a, [wWhichPokemon]
+ ld de, wPartySpecies
+ add e
+ ld e, a
+ jr nc, .asm_feca6
+ inc d
+.asm_feca6
+ ld a, [de]
+ cp -1
+ jp z, Func_fed01
+ ld [wTempByteValue], a
+ push hl
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ inc hl
+ ld de, Text_fed9c
+ call PlaceString
+ call GetMonName
+ call PlaceString
+ pop hl
+ push hl
+ ld bc, 11
+ add hl, bc
+ push hl
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMon1Level
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+ ld d, h
+ ld e, l
+ ld a, [de]
+ ld [wCurEnemyLevel], a
+ pop hl
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ ld a, [wWhichPokemon]
+ ld de, wEnemyPartySpecies
+ add e
+ ld e, a
+ jr nc, .asm_fecee
+ inc d
+.asm_fecee
+ ld a, [wCurEnemyLevel]
+ ld [de], a
+ pop hl
+ ld a, [wWhichPokemon]
+ inc a
+ ld [wWhichPokemon], a
+ ld bc, SCREEN_WIDTH * 2
+ add hl, bc
+ jp Func_fec9b
+
+Func_fed01:
+ pop hl
+ pop de
+ ld a, [wPartyMon1]
+ ld b, a
+ ld a, [wPartyMon1Level]
+ ld c, a
+ xor a
+ ld [wWhichPokemon], a
+ jp Func_fe7ca
+
+Text_fed12:
+ db "けんしろう@" ; "KENSHIROU@"
+
+Text_fed18:
+ db "テスト ファイト@" ; "FIGHT TEST@"
+
+Text_fed21:
+ db "№. なまえ レべル@" ; "№. NAME LEVEL@"
+
+Text_fed30:
+ db "1.▶000 ーーーーー 000"
+ next "2. 000 ーーーーー 000"
+ next "3. 000 ーーーーー 000"
+ next "4. 000 ーーーーー 000"
+ next "5. 000 ーーーーー 000"
+ next "6. 000 ーーーーー 000@"
+
+Text_fed9c:
+ db " @"
+
+Text_feda2:
+ db "ーーーーー@"
+
+Text_feda8:
+ db "ワイルドモンスター@" ; "WILD #MON@"
+
+Text_fedb2:
+ db "ディーラー @" ; "TRAINER @"
+
+Text_fedbc:
+ db "№. なまえ レべル" ; "№. NAME LABEL"
+ next ""
+Text_fedcf:
+ db "000 ーーーーーーーーーー 000@"
+
+Text_fede2:
+ db " @"
+
+Data_feded:
+ db GREAT_BALL, 99
+ db POKE_BALL, 99
+ db ANTIDOTE, 99
+ db FULL_RESTORE, 99
+ db MAX_POTION, 99
+ db HYPER_POTION, 99
+ db SUPER_POTION, 99
+ db POTION, 99
+ db -1 ; end
+
+Func_fedfe:
+ ld a, [wBoxCount]
+ cp 30
+ jp nc, Func_ff1ad
+ call ClearScreen
+ call UpdateSprites
+ ld a, [wLetterPrintingDelayFlags]
+ push af
+ xor a
+ ld [wLetterPrintingDelayFlags], a
+ ld hl, wEnemyMonOT
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ inc a
+ ldh [hJoy7], a
+ ld [wCurPartySpecies], a
+ ld [wCurEnemyLevel], a
+ ; fallthrough
+Func_fee23:
+ hlcoord 0, 3
+ ld [hl], ' '
+ hlcoord 0, 1
+ ld [hl], '▶'
+ call Func_fee60
+.asm_fee30
+ call DelayFrame
+ call JoypadLowSensitivity
+ ldh a, [hJoy5]
+ bit B_PAD_A, a
+ jp nz, Func_fee49
+ bit B_PAD_B, a
+ jp nz, Func_fee56
+ bit B_PAD_DOWN, a
+ jp nz, Func_fee96
+ jr .asm_fee30
+
+Func_fee49:
+ ld hl, wCurPartySpecies
+ inc [hl]
+ ld a, [hl]
+ cp NUM_POKEMON + 1
+ jr c, Func_fee23
+ ld [hl], DEX_BULBASAUR
+ jr Func_fee23
+
+Func_fee56:
+ ld hl, wCurPartySpecies
+ dec [hl]
+ jr nz, Func_fee23
+ ld [hl], DEX_MEW
+ jr Func_fee23
+
+Func_fee60:
+ hlcoord 1, 0
+ lb bc, 2, 9
+ call ClearScreenArea
+ hlcoord 1, 1
+ ld de, wCurPartySpecies
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ inc hl
+ push hl
+ ld a, [wCurPartySpecies]
+ ld [wPokedexNum], a
+ callfar PokedexToIndex
+ call GetMonName
+ pop hl
+ call PlaceString
+ ld a, [wPokedexNum]
+ ld [wCurSpecies], a
+ call GetMonHeader
+ ret
+
+Func_fee96:
+ hlcoord 0, 1
+ ld [hl], ' '
+ hlcoord 0, 3
+ ld [hl], '▶'
+ hlcoord 0, 5
+ ld [hl], ' '
+ call Func_feee2
+ call Func_feeef
+.asm_feeab
+ call DelayFrame
+ call JoypadLowSensitivity
+ ld hl, wCurEnemyLevel
+ ldh a, [hJoy5]
+ bit B_PAD_A, a
+ jp nz, Func_feed1
+ bit B_PAD_B, a
+ jp nz, Func_feedb
+ bit B_PAD_START, a
+ jp nz, Func_ff12c
+ bit B_PAD_UP, a
+ jp nz, Func_fee23
+ bit B_PAD_DOWN, a
+ jp nz, Func_fef60
+ jr .asm_feeab
+
+Func_feed1:
+ inc [hl]
+ ld a, [hl]
+ cp MAX_LEVEL + 1
+ jr c, Func_fee96
+ ld [hl], 1
+ jr Func_fee96
- ; When the battle ends, do it all again.
- ; There are some graphical quirks in SGB mode.
+Func_feedb:
+ dec [hl]
+ jr nz, Func_fee96
+ ld [hl], MAX_LEVEL
+ jr Func_fee96
+
+Func_feee2:
+ hlcoord 1, 3
+ ld de, wCurEnemyLevel
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ ret
+
+Func_feeef:
+ hlcoord 1, 4
+ lb bc, 8, 11
+ call ClearScreenArea
+ ld a, [wCurPartySpecies]
+ push af
+ ld [wPokedexNum], a
+ ld hl, BaseStats + 15
+ dec a
+ ld bc, BASE_DATA_SIZE
+ call AddNTimes
+ ld de, wMoves
+ ld bc, NUM_MOVES
+ ld a, BANK(BaseStats)
+ call FarCopyData
+ callfar PokedexToIndex
+ ld a, [wPokedexNum]
+ ld [wCurPartySpecies], a
+ xor a
+ ld [wChangeMonPicEnemyTurnSpecies], a
+ ld de, wMoves
+ predef WriteMonMoves
+ hlcoord 1, 5
+ ld de, wMoves
+ ld b, NUM_MOVES
+.asm_fef36
+ ld a, [de]
+ inc de
+ and a
+ jr z, .asm_fef5b
+ push de
+ push bc
+ push hl
+ ld [wTempByteValue], a
+ ld de, wTempByteValue
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ inc hl
+ call GetMoveName
+ call PlaceString
+ pop hl
+ ld bc, SCREEN_WIDTH * 2
+ add hl, bc
+ pop bc
+ pop de
+ dec b
+ jr nz, .asm_fef36
+.asm_fef5b
+ pop af
+ ld [wCurPartySpecies], a
+ ret
+
+Func_fef60:
+ ld de, wMoves
+ hlcoord 0, 5
+ ld b, 1
+ ; fallthrough
+Func_fef68:
+ call Func_fefc5
+.asm_fef6b
+ call DelayFrame
+ push de
+ push bc
+ call JoypadLowSensitivity
+ pop bc
+ pop de
+ ldh a, [hJoy5]
+ bit B_PAD_A, a
+ jp nz, Func_fef92
+ bit B_PAD_B, a
+ jp nz, Func_fef9e
+ bit B_PAD_START, a
+ jp nz, Func_ff12c
+ bit B_PAD_UP, a
+ jp nz, Func_fefa8
+ bit B_PAD_DOWN, a
+ jp nz, Func_fefb5
+ jr .asm_fef6b
+
+Func_fef92:
+ ld a, [de]
+ inc a
+ ld [de], a
+ cp NUM_ATTACKS
+ jr c, Func_fef68
ld a, 1
- ld [wUpdateSpritesEnabled], a
- ldh [hAutoBGTransferEnabled], a
- jr .loop
+ ld [de], a
+ jr Func_fef68
+
+Func_fef9e:
+ ld a, [de]
+ dec a
+ ld [de], a
+ jr nz, Func_fef68
+ ld a, NUM_ATTACKS - 1
+ ld [de], a
+ jr Func_fef68
+
+Func_fefa8:
+ dec de
+ dec b
+ jp z, Func_fee96
+ push bc
+ ld bc, hMovingBGTilesCounter1
+ add hl, bc
+ pop bc
+ jr Func_fef68
+
+Func_fefb5:
+ inc de
+ inc b
+ ld a, b
+ cp 5
+ jp z, Func_ff03b
+ push bc
+ ld bc, SCREEN_WIDTH * 2
+ add hl, bc
+ pop bc
+ jr Func_fef68
+
+Func_fefc5:
+ push hl
+ push de
+ push bc
+ push hl
+ push de
+ ld bc, hSpriteMapYCoord
+ add hl, bc
+ lb bc, 2, 11
+ call ClearScreenArea
+ pop de
+ pop hl
+ push hl
+ ld [hl], '▶'
+ ld bc, hMovingBGTilesCounter1
+ add hl, bc
+ ld [hl], ' '
+ ld bc, SCREEN_WIDTH * 4
+ add hl, bc
+ ld [hl], ' '
+ pop hl
+ inc hl
+ ld a, [de]
+ ld de, wTempByteValue
+ ld [de], a
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ ld a, [wTempByteValue]
+ and a
+ jr z, .asm_ff002
+ call Func_ff006
+ inc hl
+ call GetMoveName
+ call PlaceString
+.asm_ff002
+ pop bc
+ pop de
+ pop hl
+ ret
+
+Func_ff006:
+ ld a, [wCurPartySpecies]
+ push af
+ ld a, [wPokedexNum]
+ push af
+ push hl
+ ld a, [wCurPartySpecies]
+ ld [wPokedexNum], a
+ callfar PokedexToIndex
+ ld a, [wPokedexNum]
+ ld [wCurPartySpecies], a
+ pop hl
+ pop af
+ ld [wPokedexNum], a
+ push hl
+ callfar Func_3b079
+ pop hl
+ jr c, .asm_ff036
+ ld [hl], '×'
+.asm_ff036
+ pop af
+ ld [wCurPartySpecies], a
+ ret
+
+Func_ff03b:
+ ld de, wEnemyMonOT
+ hlcoord 0, 13
+ ld b, 1
+ ; fallthrough
+Func_ff043:
+ call Func_ff09e
+.asm_ff046
+ call DelayFrame
+ push de
+ push bc
+ call JoypadLowSensitivity
+ pop bc
+ pop de
+ ldh a, [hJoy5]
+ bit B_PAD_A, a
+ jp nz, Func_ff06d
+ bit B_PAD_B, a
+ jp nz, Func_ff072
+ bit B_PAD_START, a
+ jp nz, Func_ff12c
+ bit B_PAD_UP, a
+ jp nz, Func_ff077
+ bit B_PAD_DOWN, a
+ jp nz, Func_ff08f
+ jr .asm_ff046
+
+Func_ff06d:
+ ld a, [de]
+ inc a
+ ld [de], a
+ jr Func_ff043
+
+Func_ff072:
+ ld a, [de]
+ dec a
+ ld [de], a
+ jr Func_ff043
+
+Func_ff077:
+ dec de
+ dec b
+ jp z, Func_ff084
+ push bc
+ ld bc, hMovingBGTilesCounter1
+ add hl, bc
+ pop bc
+ jr Func_ff043
+
+Func_ff084:
+ ld de, wMoves + 3
+ hlcoord 0, 11
+ ld b, NUM_MOVES
+ jp Func_fef68
+
+Func_ff08f:
+ ld a, b
+ cp 3
+ jr z, Func_ff043
+ inc b
+ inc de
+ push bc
+ ld bc, SCREEN_WIDTH * 2
+ add hl, bc
+ pop bc
+ jr Func_ff043
+
+Func_ff09e:
+ push hl
+ push de
+ push bc
+ push hl
+ ld [hl], '▶'
+ ld bc, hMovingBGTilesCounter1
+ add hl, bc
+ ld [hl], ' '
+ ld bc, SCREEN_WIDTH * 4
+ add hl, bc
+ ld [hl], ' '
+ pop hl
+ inc hl
+ ld a, [de]
+ ld de, wTempByteValue
+ ld [de], a
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ call Func_ff0c4
+ pop bc
+ pop de
+ pop hl
+ ret
+
+Func_ff0c4:
+ hlcoord 12, 0
+ lb bc, 18, 8
+ call ClearScreenArea
+ hlcoord 13, 1
+ ld de, Text_ff113
+ call PlaceString
+ ld b, 10
+ ld hl, wLoadedMonHPExp
+ ld a, [wEnemyMonOT + 2]
+.asm_ff0de
+ ld [hli], a
+ dec b
+ jr nz, .asm_ff0de
+ ld a, [wEnemyMonOT]
+ ld [hli], a
+ ld a, [wEnemyMonOT + 1]
+ ld [hl], a
+ ld hl, wLoadedMonExp + 2
+ ld de, wLoadedMonStats
+ ld b, 1
+ call CalcStats
+ hlcoord 17, 1
+ ld de, wLoadedMonStats
+ ld b, 5
+.asm_ff0fd
+ push bc
+ push de
+ push hl
+ lb bc, LEADING_ZEROES | 2, 3
+ call PrintNumber
+ pop hl
+ ld bc, SCREEN_WIDTH * 2
+ add hl, bc
+ pop de
+ inc de
+ inc de
+ pop bc
+ dec b
+ jr nz, .asm_ff0fd
+ ret
+
+Text_ff113:
+ db "たいりき" ; hp
+ next "こうげき" ; attack
+ next "ぼうぎょ" ; defense
+ next "すばやさ" ; speed
+ next "とくしゅ@" ; special
+
+Func_ff12c:
+ ld a, [wCurEnemyLevel]
+ ld [wEnemyMonLevel], a
+ ld a, [wCurPartySpecies]
+ ld [wPokedexNum], a
+ callfar PokedexToIndex
+ ld a, [wPokedexNum]
+ ld [wCurPartySpecies], a
+ ld [wCurSpecies], a
+ call GetMonHeader
+ ld hl, wEnemyMon
+ ld a, [wCurPartySpecies]
+ ld [hli], a
+ ld a, [wLoadedMonStats]
+ ld [hli], a
+ ld a, [wLoadedMonStats + 1]
+ ld [hli], a
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld a, [wMonHTypes]
+ ld [hli], a
+ ld a, [wMonHType2]
+ ld [hli], a
+ ld a, [wMonHCatchRate]
+ ld [hli], a
+ ld a, [wMoves]
+ ld [hli], a
+ ld a, [wMoves + 1]
+ ld [hli], a
+ ld a, [wMoves + 2]
+ ld [hli], a
+ ld a, [wMoves + 3]
+ ld [hl], a
+ ld hl, wEnemyMonPP
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ld a, [wEnemyMonOT]
+ ld [wEnemyMonDVs], a
+ ld a, [wEnemyMonOT + 1]
+ ld [wEnemyMonDVs + 1], a
+ callfar SendNewMonToBox
+ ld b, 10
+ ld hl, wBoxMon1HPExp
+ ld a, [wEnemyMonOT + 2]
+.asm_ff19e
+ ld [hli], a
+ dec b
+ jr nz, .asm_ff19e
+ ld a, 1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ pop af
+ ld [wLetterPrintingDelayFlags], a
+ jr Func_ff1b3
+Func_ff1ad:
+ ld hl, Text_ff1b4
+ call PrintText
+Func_ff1b3:
+ ret
+
+Text_ff1b4:
+ text_far _BoxFullDebugText
+ text_end
+
+Func_ff1b9:
+ ld a, 1
+ ldh [hJoy7], a
+ ld a, 2
+ ld [wCurEnemyLevel], a
+ ld hl, Text_ff290
+ call PrintText
+ call YesNoChoice
+ ld a, [wCurrentMenuItem]
+ and a
+ jp nz, Func_ff286
+ ld hl, Text_ff28f
+ call PrintText
+ callfar EmptyAllSRAMBoxes
+ ld hl, wBoxCount
+ xor a
+ ld [hli], a
+ dec a
+ ld [hl], a
+ ; fallthrough
+Func_ff1e7:
+ hlcoord 2, 13
+ ld [hl], '゙'
+ hlcoord 1, 14
+ ld [hl], 'レ'
+ inc hl
+ ld [hl], 'へ'
+ inc hl
+ ld [hl], 'ル'
+ inc hl
+ inc hl
+ ld de, wCurEnemyLevel
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ call DelayFrame
+ call JoypadLowSensitivity
+ ldh a, [hJoy5]
+ bit B_PAD_A, a
+ jp nz, Func_ff21b
+ bit B_PAD_B, a
+ jp nz, Func_ff227
+ bit B_PAD_START, a
+ jp nz, Func_ff236
+ jr Func_ff1e7
+
+Func_ff21b:
+ ld a, [wCurEnemyLevel]
+ inc a
+ cp MAX_LEVEL + 1
+ jr c, Func_ff231
+ ld a, 2
+ jr Func_ff231
+Func_ff227:
+ ld a, [wCurEnemyLevel]
+ dec a
+ cp 2
+ jr nc, Func_ff231
+ ld a, MAX_LEVEL
+Func_ff231:
+ ld [wCurEnemyLevel], a
+ jr Func_ff1e7
+
+Func_ff236:
+ ld c, 0
+ ld d, 0
+.asm_ff23a
+ push bc
+ push de
+ call Func_ff295
+ ld hl, wChangeMonPicEnemyTurnSpecies
+ inc [hl]
+ pop de
+ pop bc
+ ld b, 30
+.asm_ff247
+ inc c
+ push bc
+ push de
+ ld a, c
+ ld [wPokedexNum], a
+ callfar PokedexToIndex
+ ld a, [wPokedexNum]
+ ld [wEnemyMonSpecies2], a
+ ld [wCurPartySpecies], a
+ xor a
+ ld [wEnemyBattleStatus3], a
+ callfar LoadEnemyMonData
+ ld a, [wEnemyMonSpecies2]
+ ld [wCurPartySpecies], a
+ callfar SendNewMonToBox
+ pop de
+ pop bc
+ ld a, c
+ cp NUM_POKEMON
+ jr z, Func_ff286
+ dec b
+ jr nz, .asm_ff247
+ inc d
+ jr .asm_ff23a
+ ; fallthrough
+Func_ff286:
+ ld a, 1
+ ld [wDoNotWaitForButtonPressAfterDisplayingText], a
+ xor a
+ ldh [hJoy7], a
+ ret
+
+Text_ff28f:
+ text_end
+
+Text_ff290:
+ text_far _BoxWillBeClearedText
+ text_end
+
+Func_ff295:
+ push de
+ ld a, SFX_SAVE
+ call PlaySoundWaitForCurrent
+ call WaitForSoundToFinish
+ call Func_ff2d1
+ ld e, l
+ ld d, h
+ ld hl, wBoxCount
+ call Func_ff2f3
+ pop de
+ ld a, d
+ set BIT_HAS_CHANGED_BOXES, a
+ ld [wCurrentBoxNum], a
+ push de
+ call Func_ff2d1
+ ld de, wBoxCount
+ call Func_ff2f3
+ ld a, [wLetterPrintingDelayFlags]
+ push af
+ ld a, 1 << BIT_FAST_TEXT_DELAY
+ ld [wLetterPrintingDelayFlags], a
+ callfar SaveGameData
+ pop af
+ ld [wLetterPrintingDelayFlags], a
+ pop de
+ ret
+
+Func_ff2d1:
+ ld hl, Data_ff2eb
+ ld a, [wCurrentBoxNum]
+ and %01111111
+ cp 4
+ ld b, 2
+ jr c, .asm_ff2e2
+ inc b
+ and 3
+.asm_ff2e2
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ret
+
+Data_ff2eb:
+ dw sBox1
+ dw sBox2
+ dw sBox3
+ dw sBox4
+
+Func_ff2f3:
+ push hl
+ call DebugEnableSRAM
+ ld a, b
+ ld [rRAMB], a
+ ld bc, sBox2 - sBox1
+ call CopyData
+ pop hl
+ xor a
+ ld [hli], a
+ dec a
+ ld [hl], a
+ ld hl, sBox1
+ ld bc, sBox5 - sBox1 + 1
+ call Func_ff32a
+ ld [sBox5], a
+ call DebugDisableSRAM
+ ret
+
+DebugEnableSRAM: ; duplicate of EnableSRAM
+ ld a, BMODE_ADVANCED
+ ld [rBMODE], a
+ ld a, RAMG_SRAM_ENABLE
+ ld [rRAMG], a
+ ret
+
+DebugDisableSRAM: ; duplicate of DisableSRAM
+ ld a, 0
+ ld [rBMODE], a
+ ld [rRAMG], a
+ ret
+
+Func_ff32a:
+ ld d, 0
+.asm_ff32c
+ ld a, [hli]
+ add d
+ ld d, a
+ dec bc
+ ld a, b
+ or c
+ jr nz, .asm_ff32c
+ ld a, d
+ cpl
+ ret
+ELSE
+ ret
+ENDC
diff --git a/engine/debug/debug_party.asm b/engine/debug/debug_party.asm
index 19cbea0a..de61b091 100644
--- a/engine/debug/debug_party.asm
+++ b/engine/debug/debug_party.asm
@@ -13,22 +13,10 @@ SetDebugNewGameParty: ; unreferenced except in _DEBUG
jr .loop
DebugNewGameParty: ; unreferenced except in _DEBUG
- ; Exeggutor is the only debug party member shared with Red, Green, and Japanese Blue.
- ; "Tsunekazu Ishihara: Exeggutor is my favorite. That's because I was
- ; always using this character while I was debugging the program."
- ; From https://web.archive.org/web/20000607152840/http://pocket.ign.com/news/14973.html
- db EXEGGUTOR, 90
-IF DEF(_DEBUG)
- db MEW, 5
-ELSE
- db MEW, 20
-ENDC
- db JOLTEON, 56
- db DUGTRIO, 56
- db ARTICUNO, 57
-IF DEF(_DEBUG)
- db PIKACHU, 5
-ENDC
+ db SNORLAX, 80
+ db PERSIAN, 80
+ db JIGGLYPUFF, 15
+ db STARTER_PIKACHU, 5
db -1 ; end
PrepareNewGameDebug: ; dummy except in _DEBUG
@@ -47,7 +35,12 @@ IF DEF(_DEBUG)
call SetDebugNewGameParty
- ; Exeggutor gets four HM moves.
+ ; Pikachu gets Surf.
+ ld a, SURF
+ ld hl, wPartyMon4Moves + 2
+ ld [hl], a
+
+ ; Snorlax gets four HM moves.
ld hl, wPartyMon1Moves
ld a, FLY
ld [hli], a
@@ -57,38 +50,6 @@ IF DEF(_DEBUG)
ld [hli], a
ld a, STRENGTH
ld [hl], a
- ld hl, wPartyMon1PP
- ld a, 15
- ld [hli], a
- ld a, 30
- ld [hli], a
- ld a, 15
- ld [hli], a
- ld [hl], a
-
- ; Jolteon gets Thunderbolt.
- ld hl, wPartyMon3Moves + 3
- ld a, THUNDERBOLT
- ld [hl], a
- ld hl, wPartyMon3PP + 3
- ld a, 15
- ld [hl], a
-
- ; Articuno gets Fly.
- ld hl, wPartyMon5Moves
- ld a, FLY
- ld [hl], a
- ld hl, wPartyMon5PP
- ld a, 15
- ld [hl], a
-
- ; Pikachu gets Surf.
- ld hl, wPartyMon6Moves + 2
- ld a, SURF
- ld [hl], a
- ld hl, wPartyMon6PP + 2
- ld a, 15
- ld [hl], a
; Get some debug items.
ld hl, wNumBagItems
@@ -113,14 +74,21 @@ IF DEF(_DEBUG)
call DebugSetPokedexEntries
SetEvent EVENT_GOT_POKEDEX
- ; Rival chose Squirtle,
- ; Player chose Charmander.
+ ; Rival chose Jolteon.
ld hl, wRivalStarter
ASSERT wRivalStarter + 2 == wPlayerStarter
- ld a, STARTER2
+ ld a, RIVAL_STARTER_JOLTEON
+ ld [hli], a
+ ld a, NUM_POKEMON
+ ld [hli], a ; hl = wUnknownDebugByte
+ ld a, STARTER_PIKACHU
+ ld [hl], a
+
+ ; Give max money.
+ ld hl, wPlayerMoney
+ ld a, $99
+ ld [hli], a
ld [hli], a
- inc hl
- ld a, STARTER1
ld [hl], a
ret
@@ -140,20 +108,55 @@ ENDC
ret
DebugNewGameItemsList:
+ db MASTER_BALL, 99
+ db TOWN_MAP, 1
db BICYCLE, 1
db FULL_RESTORE, 99
- db FULL_HEAL, 99
db ESCAPE_ROPE, 99
db RARE_CANDY, 99
- db MASTER_BALL, 99
- db TOWN_MAP, 1
db SECRET_KEY, 1
db CARD_KEY, 1
+ db FULL_HEAL, 99
+ db REVIVE, 99
+ db FRESH_WATER, 99
db S_S_TICKET, 1
db LIFT_KEY, 1
+ db PP_UP, 99
db -1 ; end
DebugUnusedList: ; unreferenced
+ db OLD_AMBER, 1
+ db DOME_FOSSIL, 1
+ db HELIX_FOSSIL, 1
+ db X_ACCURACY, 99
+ db DIRE_HIT, 99
+ db FRESH_WATER, 1
+ db S_S_TICKET, 1
+ db GOLD_TEETH, 1
+ db COIN_CASE, 1
+ db SILPH_SCOPE, 1
+ db POKE_FLUTE, 1
+ db LIFT_KEY, 1
+ db ETHER, 99
+ db MAX_ETHER, 99
+ db ELIXER, 99
+ db MAX_ELIXER, 99
+ db TM_RAZOR_WIND, 10
+ db TM_HORN_DRILL, 10
+ db TM_TAKE_DOWN, 10
+ db TM_BLIZZARD, 10
+ db TM_HYPER_BEAM, 10
+ db TM_SOLARBEAM, 10
+ db TM_DRAGON_RAGE, 10
+ db TM_MIMIC, 10
+ db TM_BIDE, 10
+ db TM_METRONOME, 10
+ db TM_SELFDESTRUCT, 10
+ db TM_SWIFT, 10
+ db TM_SOFTBOILED, 10
+ db TM_DREAM_EATER, 10
+ db TM_REST, 10
+ db TM_SUBSTITUTE, 10
db -1 ; end
ELSE
ret
diff --git a/engine/events/black_out.asm b/engine/events/black_out.asm
index f4b0e4bc..2b017f71 100644
--- a/engine/events/black_out.asm
+++ b/engine/events/black_out.asm
@@ -1,6 +1,8 @@
ResetStatusAndHalveMoneyOnBlackout::
; Reset player status on blackout.
xor a
+ ld [wPikachuCollisionCounter], a
+ xor a ; gamefreak copypasting functions (double xor a)
ld [wBattleResult], a
ld [wWalkBikeSurfState], a
ld [wIsInBattle], a
diff --git a/engine/events/card_key.asm b/engine/events/card_key.asm
index f3fa17fe..d8f4e773 100644
--- a/engine/events/card_key.asm
+++ b/engine/events/card_key.asm
@@ -8,7 +8,7 @@ PrintCardKeyText:
ret z
cp b
jr nz, .silphCoMapListLoop
- predef GetTileAndCoordsInFrontOfPlayer
+; does not check for tile in front of player. This might be buggy.
ld a, [wTileInFrontOfPlayer]
cp $18
jr z, .cardKeyDoorInFrontOfPlayer
@@ -25,12 +25,12 @@ PrintCardKeyText:
ld b, CARD_KEY
call IsItemInBag
jr z, .noCardKey
- call GetCoordsInFrontOfPlayer
- push de
+ xor a
+ ld [wPlayerMovingDirection], a
tx_pre_id CardKeySuccessText
ldh [hTextID], a
call PrintPredefTextID
- pop de
+ call GetCoordsInFrontOfPlayer
srl d
ld a, d
ld b, a
diff --git a/engine/events/diploma.asm b/engine/events/diploma.asm
index e2a34a3b..539cba42 100644
--- a/engine/events/diploma.asm
+++ b/engine/events/diploma.asm
@@ -1,5 +1,3 @@
-DEF CIRCLE_TILE_ID EQU $70
-
DisplayDiploma::
call SaveScreenTilesToBuffer2
call GBPalWhiteOutWithDelay3
@@ -8,110 +6,12 @@ DisplayDiploma::
ld [wUpdateSpritesEnabled], a
ld hl, wStatusFlags5
set BIT_NO_TEXT_DELAY, [hl]
- call DisableLCD
- ld hl, CircleTile
- ld de, vChars2 tile CIRCLE_TILE_ID
- ld bc, TILE_SIZE
- ld a, BANK(CircleTile)
- call FarCopyData2
- hlcoord 0, 0
- lb bc, 16, 18
- predef Diploma_TextBoxBorder
-
- ld hl, DiplomaTextPointersAndCoords
- ld c, $5
-.placeTextLoop
- push bc
- ld a, [hli]
- ld e, a
- ld a, [hli]
- ld d, a
- ld a, [hli]
- push hl
- ld h, [hl]
- ld l, a
- call PlaceString
- pop hl
- inc hl
- pop bc
- dec c
- jr nz, .placeTextLoop
- hlcoord 10, 4
- ld de, wPlayerName
- call PlaceString
- farcall DrawPlayerCharacter
-
-; Move the player 33 pixels right and set the priority bit so he appears
-; behind the background layer.
- ld hl, wShadowOAMSprite00XCoord
- lb bc, $80, $28
-.adjustPlayerGfxLoop
- ld a, [hl] ; X
- add 33
- ld [hli], a
- inc hl
- ld a, b
- ld [hli], a ; attributes
- inc hl
- dec c
- jr nz, .adjustPlayerGfxLoop
-
- call EnableLCD
- farcall LoadTrainerInfoTextBoxTiles
- ld b, SET_PAL_GENERIC
- call RunPaletteCommand
- call Delay3
- call GBPalNormal
- ld a, $90
- ldh [rOBP0], a
+ callfar DisplayDiplomaTop
call WaitForTextScrollButtonPress
ld hl, wStatusFlags5
res BIT_NO_TEXT_DELAY, [hl]
call GBPalWhiteOutWithDelay3
+ call ReloadTilesetTilePatterns
call RestoreScreenTilesAndReloadTilePatterns
call Delay3
jp GBPalNormal
-
-UnusedPlayerNameLengthFunc:
-; Unused function that performs bc = -(player name's length)
-; leftover from the JPN versions
- ld hl, wPlayerName
- lb bc, $ff, $00
-.loop
- ld a, [hli]
- cp '@'
- ret z
- dec c
- jr .loop
-
-MACRO diploma_text
- dw \3
- dwcoord \1, \2
-ENDM
-
-DiplomaTextPointersAndCoords:
- ; x, y, text
- diploma_text 5, 2, DiplomaText
- diploma_text 3, 4, DiplomaPlayer
- diploma_text 15, 4, DiplomaEmptyText
- diploma_text 2, 6, DiplomaCongrats
- diploma_text 9, 16, DiplomaGameFreak
-
-DiplomaText:
- db CIRCLE_TILE_ID, "Diploma", CIRCLE_TILE_ID, "@"
-
-DiplomaPlayer:
- db "Player@"
-
-DiplomaEmptyText:
- db "@"
-
-DiplomaCongrats:
- db "Congrats! This"
- next "diploma certifies"
- next "that you have"
- next "completed your"
- next "#DEX.@"
-
-DiplomaGameFreak:
- db "GAME FREAK@"
diff --git a/engine/events/diploma2.asm b/engine/events/diploma2.asm
new file mode 100644
index 00000000..0653526d
--- /dev/null
+++ b/engine/events/diploma2.asm
@@ -0,0 +1,149 @@
+DEF CIRCLE_TILE_ID EQU $10
+
+DisplayDiplomaTop:
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ ld de, DiplomaGraphics
+ ld hl, vChars2
+ lb bc, BANK(DiplomaGraphics), (DiplomaGraphicsEnd - DiplomaGraphics) / $10
+ call CopyVideoData
+
+ hlcoord 0, 0
+ call DiplomaDrawHorizontalBorder
+ hlcoord 0, 0
+ call DiplomaDrawVerticalBorder
+ hlcoord 19, 0
+ call DiplomaDrawVerticalBorder
+ ld a, $00
+ hlcoord 0, 0
+ ld [hl], a
+ hlcoord 19, 0
+ ld [hl], a
+
+ ld de, DiplomaText
+ hlcoord 5, 2
+ call PlaceString
+
+ ld de, DiplomaPlayer
+ hlcoord 3, 4
+ call PlaceString
+
+ ld de, wPlayerName
+ hlcoord 10, 4
+ call PlaceString
+
+ ld de, DiplomaCongrats
+ hlcoord 2, 6
+ call PlaceString
+
+ ld de, DiplomaGameFreak
+ hlcoord 9, 16
+ call PlaceString
+
+ ld b, SET_PAL_GENERIC
+ call RunPaletteCommand
+ ld a, $01
+ ldh [hAutoBGTransferEnabled], a
+ call Delay3
+ call GBPalNormal
+ ret
+
+DiplomaText:
+ db CIRCLE_TILE_ID, "Diploma", CIRCLE_TILE_ID, "@"
+
+DiplomaPlayer:
+ db "Player@"
+
+DiplomaCongrats:
+ db "Congrats! This"
+ next "diploma certifies"
+ next "that you have"
+ next "completed your"
+ next "#DEX.@"
+
+DiplomaGameFreak:
+ db "GAME FREAK@"
+
+DisplayDiplomaBottom:
+ call ClearScreen
+ hlcoord 0, 17
+ call DiplomaDrawHorizontalBorder
+ hlcoord 0, 0
+ call DiplomaDrawVerticalBorder
+ hlcoord 19, 0
+ call DiplomaDrawVerticalBorder
+ ld a, $00
+ hlcoord 0, 17
+ ld [hl], a
+ hlcoord 19, 17
+ ld [hl], a
+
+ ld de, DiplomaPikachuTiles
+ hlcoord 6, 2
+ lb bc, 10, 12
+ call Diploma_Surfing_CopyBox
+
+ ld de, CongratulationsTiles
+ hlcoord 5, 13
+ lb bc, 1, 11
+ call Diploma_Surfing_CopyBox
+
+ ld de, DiplomaPlayTime
+ hlcoord 2, 15
+ call PlaceString
+ hlcoord 12, 15
+ ld de, wPlayTimeHours
+ lb bc, LEFT_ALIGN | 1, 3
+ call PrintNumber
+ ld [hl], $16 ; colon
+ inc hl
+ ld de, wPlayTimeMinutes
+ lb bc, LEADING_ZEROES | 1, 2
+ call PrintNumber
+
+ ld a, [wNumSetBits]
+ cp NUM_POKEMON
+ ret nz
+ ld de, DiplomaMewTiles
+ hlcoord 2, 0
+ lb bc, 4, 5
+ call Diploma_Surfing_CopyBox
+ ret
+
+DiplomaPikachuTiles:
+INCBIN "gfx/diploma/diploma_pikachu.tilemap"
+
+CongratulationsTiles:
+ db $05, $06, $07, $08, $09, $0a, $0b, $0c, $0d, $0e, $0f ; CONGRATULATIONS!
+
+DiplomaMewTiles:
+INCBIN "gfx/diploma/diploma_mew.tilemap"
+
+DiplomaPlayTime:
+ db "PLAY TIME@"
+
+DiplomaDrawHorizontalBorder:
+ ld c, SCREEN_WIDTH / 2
+.loop
+ ld [hl], $02
+ inc hl
+ ld [hl], $01
+ inc hl
+ dec c
+ jr nz, .loop
+ ret
+
+DiplomaDrawVerticalBorder:
+ ld c, SCREEN_HEIGHT / 2
+ ld de, SCREEN_WIDTH
+.loop
+ ld [hl], $04
+ add hl, de
+ ld [hl], $03
+ add hl, de
+ dec c
+ jr nz, .loop
+ ret
+
+DiplomaGraphics: INCBIN "gfx/diploma/diploma.2bpp"
+DiplomaGraphicsEnd:
diff --git a/engine/events/elevator.asm b/engine/events/elevator.asm
index 9d9b712a..1c7221bc 100644
--- a/engine/events/elevator.asm
+++ b/engine/events/elevator.asm
@@ -1,6 +1,12 @@
DisplayElevatorFloorMenu:
+ ld hl, wStatusFlags5
+ ld a, [hl]
+ push af
+ set BIT_NO_TEXT_DELAY, [hl]
ld hl, WhichFloorText
call PrintText
+ pop af
+ ld [wStatusFlags5], a
ld hl, wItemList
ld a, l
ld [wListPointer], a
diff --git a/engine/events/evolve_trade.asm b/engine/events/evolve_trade.asm
deleted file mode 100644
index 7dfc2433..00000000
--- a/engine/events/evolve_trade.asm
+++ /dev/null
@@ -1,28 +0,0 @@
-InGameTrade_CheckForTradeEvo:
-; In Japanese Blue, TradeMons include a Graveler and a Haunter,
-; both of which have Japanese names that start with "ゴ",
-; which is what this routine originally checked in that game.
-; For English Red and Blue, this routine was adjusted for
-; Graveler's English name and Haunter's early English name "Spectre".
-; The final release replaced Graveler and Haunter in TradeMons.
- ld a, [wInGameTradeReceiveMonName]
- cp 'G' ; GRAVELER
- jr z, .nameMatched
- ; "SPECTRE" (HAUNTER)
- cp 'S'
- ret nz
- ld a, [wInGameTradeReceiveMonName + 1]
- cp 'P'
- ret nz
-.nameMatched
- ld a, [wPartyCount]
- dec a
- ld [wWhichPokemon], a
- ld a, TRUE
- ld [wForceEvolution], a
- ld a, LINK_STATE_TRADING
- ld [wLinkState], a
- callfar TryEvolvingMon
- xor a ; LINK_STATE_NONE
- ld [wLinkState], a
- jp PlayDefaultMusic
diff --git a/engine/events/give_pokemon.asm b/engine/events/give_pokemon.asm
index b25ef048..43c7e4ee 100644
--- a/engine/events/give_pokemon.asm
+++ b/engine/events/give_pokemon.asm
@@ -44,6 +44,8 @@ _GivePokemon::
ret
.addToParty
call SetPokedexOwnedFlag
+ ld hl, UnknownTerminator_f6794
+ call PrintText
call AddPartyMon
ld a, 1
ld [wDoNotWaitForButtonPressAfterDisplayingText], a
@@ -68,6 +70,9 @@ SetPokedexOwnedFlag:
ld hl, GotMonText
jp PrintText
+UnknownTerminator_f6794:
+ text_end
+
GotMonText:
text_far _GotMonText
sound_get_item_1
diff --git a/engine/events/hidden_events/bench_guys.asm b/engine/events/hidden_events/bench_guys.asm
index e5a2a724..81519f2f 100644
--- a/engine/events/hidden_events/bench_guys.asm
+++ b/engine/events/hidden_events/bench_guys.asm
@@ -18,14 +18,10 @@ PrintBenchGuyText:
ld a, [wSpritePlayerStateData1FacingDirection]
cp b
- ; bug: an 'inc hl' instruction is needed before looping back. When trying to
- ; talk to a bench guy from above, this Sprite Facing test will fail, and the
- ; next loop iteration will be misaligned within BenchGuyTextPointers table.
- ; As a result, the routine will miss the terminator byte, and continue to
- ; process data beyond the table boundary.
- ; It seems that it will only return after starting to read data from VRAM
- ; (According to Pan Docs, during PPU mode 3, reads return garbage value,
- ; usually $FF).
+ ; bug: an 'inc hl' instruction is needed before looping back.
+ ; Due to Yellow's new Pokecenter layout, it's now impossible to talk to a
+ ; bench guy from above. The bug is still present but will not be triggered
+ ; in a regular play.
jr nz, .loop ; player isn't facing the bench guy
ld a, [hl]
jp PrintPredefTextID
diff --git a/engine/events/hidden_events/bills_house_pc.asm b/engine/events/hidden_events/bills_house_pc.asm
index 3972e20c..fefb66dd 100644
--- a/engine/events/hidden_events/bills_house_pc.asm
+++ b/engine/events/hidden_events/bills_house_pc.asm
@@ -52,9 +52,7 @@ BillsHouseInitiatedText::
text_far _BillsHouseInitiatedText
text_promptbutton
text_asm
- ld a, SFX_STOP_ALL_MUSIC
- ld [wNewSoundID], a
- call PlaySound
+ call StopAllMusic
ld c, 16
call DelayFrames
ld a, SFX_SWITCH
@@ -85,8 +83,7 @@ BillsHousePokemonList::
ld hl, wStatusFlags5
set BIT_NO_TEXT_DELAY, [hl]
hlcoord 0, 0
- ld b, 10
- ld c, 9
+ lb bc, 10, 9
call TextBoxBorder
hlcoord 2, 2
ld de, BillsMonListText
diff --git a/engine/events/hidden_events/cinnabar_gym_quiz.asm b/engine/events/hidden_events/cinnabar_gym_quiz.asm
index 9762c214..c76a97c8 100644
--- a/engine/events/hidden_events/cinnabar_gym_quiz.asm
+++ b/engine/events/hidden_events/cinnabar_gym_quiz.asm
@@ -9,6 +9,8 @@ CinnabarGymQuiz::
text_asm
xor a
ld [wOpponentAfterWrongAnswer], a
+ ld hl, wd474
+ res 7, [hl]
ld a, [wHiddenEventFunctionArgument]
push af
and $f
@@ -17,7 +19,12 @@ CinnabarGymQuiz::
and $f0
swap a
ldh [hGymGateAnswer], a
+ ldh a, [hGymGateIndex]
ld hl, CinnabarGymQuizIntroText
+ cp 1
+ jr z, .onFirstQuestion
+ ld hl, CinnabarGymQuizShortIntroText
+.onFirstQuestion
call PrintText
ldh a, [hGymGateIndex]
dec a
@@ -35,10 +42,18 @@ CinnabarGymQuiz::
call CinnabarGymQuiz_AskQuestion
jp TextScriptEnd
+CinnabarGymQuizDummyIntroText:
+ text_far _CinnabarGymQuizDummyIntroText
+ text_end
+
CinnabarGymQuizIntroText:
text_far _CinnabarGymQuizIntroText
text_end
+CinnabarGymQuizShortIntroText:
+ text_far _CinnabarGymQuizShortIntroText
+ text_end
+
CinnabarQuizQuestions:
dw CinnabarQuizQuestionsText1
dw CinnabarQuizQuestionsText2
@@ -71,10 +86,6 @@ CinnabarQuizQuestionsText6:
text_far _CinnabarQuizQuestionsText6
text_end
-CinnabarGymGateFlagAction:
- EventFlagAddress hl, EVENT_CINNABAR_GYM_GATE0_UNLOCKED
- predef_jump FlagActionPredef
-
CinnabarGymQuiz_AskQuestion:
call YesNoChoice
ldh a, [hGymGateAnswer]
@@ -114,6 +125,8 @@ CinnabarGymQuiz_AskQuestion:
ldh a, [hGymGateIndex]
add $2
ld [wOpponentAfterWrongAnswer], a
+ ld hl, wd474
+ set 7, [hl]
ret
CinnabarGymQuizCorrectText:
@@ -140,6 +153,10 @@ CinnabarGymQuizIncorrectText:
text_far _CinnabarGymQuizIncorrectText
text_end
+CinnabarGymGateFlagAction:
+ EventFlagAddress hl, EVENT_CINNABAR_GYM_GATE0_UNLOCKED
+ predef_jump FlagActionPredef
+
UpdateCinnabarGymGateTileBlocks_::
; Update the overworld map with open floor blocks or locked gate blocks
; depending on event flags.
@@ -177,10 +194,11 @@ UpdateCinnabarGymGateTileBlocks_::
.next
pop bc
ld [wNewTileBlockID], a
- predef ReplaceTileBlock
+ call CinnabarGym_ReplaceTileBlock
ld hl, hGymGateIndex
dec [hl]
jr nz, .loop
+ callfar RedrawMapView
ret
MACRO gym_gate_coord
@@ -198,3 +216,31 @@ CinnabarGymGateCoords:
gym_gate_coord 3, 8, VERTICAL_GATE_BLOCK
gym_gate_coord 2, 6, HORIZONTAL_GATE_BLOCK
gym_gate_coord 2, 3, HORIZONTAL_GATE_BLOCK
+
+
+CinnabarGym_ReplaceTileBlock:
+; basically a copy of the first half of ReplaceTileBlock
+; before checking if it is necessary to redraw the map view
+ ld hl, wOverworldMap
+ ld a, [wCurMapWidth]
+ add $6
+ ld e, a
+ ld d, $0
+ add hl, de
+ add hl, de
+ add hl, de
+ ld e, $3
+ add hl, de
+ ld e, a
+ ld a, b
+ and a
+ jr z, .addX
+.addWidthYTimesLoop
+ add hl, de
+ dec b
+ jr nz, .addWidthYTimesLoop
+.addX
+ add hl, bc
+ ld a, [wNewTileBlockID]
+ ld [hl], a
+ ret
diff --git a/engine/events/hidden_events/fanclub_pictures.asm b/engine/events/hidden_events/fanclub_pictures.asm
new file mode 100644
index 00000000..2a3db4bc
--- /dev/null
+++ b/engine/events/hidden_events/fanclub_pictures.asm
@@ -0,0 +1,23 @@
+FanClubPicture1:
+ ld a, RAPIDASH
+ ld [wCurPartySpecies], a
+ call DisplayMonFrontSpriteInBox
+ call EnableAutoTextBoxDrawing
+ tx_pre FanClubPicture1Text
+ ret
+
+FanClubPicture1Text::
+ text_far _FanClubPicture1Text
+ text_end
+
+FanClubPicture2:
+ ld a, FEAROW
+ ld [wCurPartySpecies], a
+ call DisplayMonFrontSpriteInBox
+ call EnableAutoTextBoxDrawing
+ tx_pre FanClubPicture2Text
+ ret
+
+FanClubPicture2Text::
+ text_far _FanClubPicture2Text
+ text_end
diff --git a/engine/events/hidden_events/museum_fossils.asm b/engine/events/hidden_events/museum_fossils.asm
index df74293f..9e02aeba 100644
--- a/engine/events/hidden_events/museum_fossils.asm
+++ b/engine/events/hidden_events/museum_fossils.asm
@@ -21,31 +21,3 @@ KabutopsFossil:
KabutopsFossilText::
text_far _KabutopsFossilText
text_end
-
-DisplayMonFrontSpriteInBox:
-; Displays a pokemon's front sprite in a pop-up window.
- ld a, 1
- ldh [hAutoBGTransferEnabled], a
- call Delay3
- xor a
- ldh [hWY], a
- call SaveScreenTilesToBuffer1
- ld a, MON_SPRITE_POPUP
- ld [wTextBoxID], a
- call DisplayTextBoxID
- call UpdateSprites
- ld a, [wCurPartySpecies]
- ld [wCurSpecies], a
- call GetMonHeader
- ld de, vChars1 tile $31
- call LoadMonFrontSprite
- ld a, $80
- ldh [hStartTileID], a
- hlcoord 10, 11
- predef AnimateSendingOutMon
- call WaitForTextScrollButtonPress
- call LoadScreenTilesFromBuffer1
- call Delay3
- ld a, $90
- ldh [hWY], a
- ret
diff --git a/engine/events/hidden_events/museum_fossils2.asm b/engine/events/hidden_events/museum_fossils2.asm
new file mode 100644
index 00000000..240b7ece
--- /dev/null
+++ b/engine/events/hidden_events/museum_fossils2.asm
@@ -0,0 +1,27 @@
+DisplayMonFrontSpriteInBox:
+; Displays a pokemon's front sprite in a pop-up window.
+ ld a, 1
+ ldh [hAutoBGTransferEnabled], a
+ call Delay3
+ xor a
+ ldh [hWY], a
+ call SaveScreenTilesToBuffer1
+ ld a, MON_SPRITE_POPUP
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ call UpdateSprites
+ ld a, [wCurPartySpecies]
+ ld [wCurSpecies], a
+ call GetMonHeader
+ ld de, vChars1 tile $31
+ call LoadMonFrontSprite
+ ld a, $80
+ ldh [hStartTileID], a
+ hlcoord 10, 11
+ predef AnimateSendingOutMon
+ call WaitForTextScrollButtonPress
+ call LoadScreenTilesFromBuffer1
+ call Delay3
+ ld a, $90
+ ldh [hWY], a
+ ret
diff --git a/engine/events/hidden_events/oaks_lab_email.asm b/engine/events/hidden_events/oaks_lab_email.asm
index b66babe0..bd4c66d7 100644
--- a/engine/events/hidden_events/oaks_lab_email.asm
+++ b/engine/events/hidden_events/oaks_lab_email.asm
@@ -3,7 +3,8 @@ DisplayOakLabEmailText:
cp SPRITE_FACING_UP
ret nz
call EnableAutoTextBoxDrawing
- tx_pre_jump OakLabEmailText
+ tx_pre OakLabEmailText
+ ret
OakLabEmailText::
text_far _OakLabEmailText
diff --git a/engine/events/hidden_events/route_15_binoculars.asm b/engine/events/hidden_events/route_15_binoculars.asm
index 733ab73e..a9b8ca37 100644
--- a/engine/events/hidden_events/route_15_binoculars.asm
+++ b/engine/events/hidden_events/route_15_binoculars.asm
@@ -7,7 +7,10 @@ Route15GateLeftBinoculars:
ld a, ARTICUNO
ld [wCurPartySpecies], a
call PlayCry
- jp DisplayMonFrontSpriteInBox
+ call DisplayMonFrontSpriteInBox
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ret
Route15UpstairsBinocularsText::
text_far _Route15UpstairsBinocularsText
diff --git a/engine/events/hidden_events/safari_game.asm b/engine/events/hidden_events/safari_game.asm
index fc014ce0..7fd59ea9 100644
--- a/engine/events/hidden_events/safari_game.asm
+++ b/engine/events/hidden_events/safari_game.asm
@@ -31,8 +31,7 @@ SafariZoneGameOver:
call EnableAutoTextBoxDrawing
xor a
ld [wAudioFadeOutControl], a
- dec a ; SFX_STOP_ALL_MUSIC
- call PlaySound
+ call StopAllMusic
ld c, BANK(SFX_Safari_Zone_PA)
ld a, SFX_SAFARI_ZONE_PA
call PlayMusic
diff --git a/engine/events/hidden_events/school_blackboard.asm b/engine/events/hidden_events/school_blackboard.asm
index 71e24ed0..23022398 100644
--- a/engine/events/hidden_events/school_blackboard.asm
+++ b/engine/events/hidden_events/school_blackboard.asm
@@ -27,8 +27,7 @@ LinkCableHelp::
ld hl, wStatusFlags5
set BIT_NO_TEXT_DELAY, [hl]
hlcoord 0, 0
- ld b, 8
- ld c, 13
+ lb bc, 8, 13
call TextBoxBorder
hlcoord 2, 2
ld de, HowToLinkText
diff --git a/engine/events/hidden_events/vermilion_gym_trash.asm b/engine/events/hidden_events/vermilion_gym_trash.asm
index 40e200d6..e83bef51 100644
--- a/engine/events/hidden_events/vermilion_gym_trash.asm
+++ b/engine/events/hidden_events/vermilion_gym_trash.asm
@@ -33,53 +33,17 @@ GymTrashScript:
.openFirstLock
; Next can is trying for the second switch.
SetEvent EVENT_1ST_LOCK_OPENED
-
- ld hl, GymTrashCans
- ld a, [wGymTrashCanIndex]
- ; * 5
- ld b, a
- add a
- add a
- add b
-
- ld d, 0
- ld e, a
- add hl, de
- ld a, [hli]
-
-; Bug: This code should calculate a value in the range [0, 3],
-; but if the mask and random number don't have any 1 bits in common, then
-; the result of the AND will be 0. When 1 is subtracted from that, the value
-; will become $ff. This will result in 255 being added to hl, which will cause
-; hl to point to one of the zero bytes that pad the end of the ROM bank.
-; Trash can 0 was intended to be able to have the second lock only when the
-; first lock was in trash can 1 or 3. However, due to this bug, trash can 0 can
-; have the second lock regardless of which trash can had the first lock.
-
- ldh [hGymTrashCanRandNumMask], a
- push hl
- call Random
- swap a
- ld b, a
- ldh a, [hGymTrashCanRandNumMask]
- and b
- dec a
- pop hl
-
- ld d, 0
- ld e, a
- add hl, de
- ld a, [hl]
- and $f
- ld [wSecondLockTrashCanIndex], a
-
+ callfar Yellow_SampleSecondTrashCan
tx_pre_id VermilionGymTrashSuccessText1
jr .done
.trySecondLock
- ld a, [wSecondLockTrashCanIndex]
- ld b, a
ld a, [wGymTrashCanIndex]
+ ld b, a
+ ld a, [wSecondLockTrashCanIndex]
+ cp b
+ jr z, .openSecondLock
+ ld a, [wSecondLockTrashCanIndex + 1]
cp b
jr z, .openSecondLock
@@ -107,25 +71,26 @@ GymTrashScript:
GymTrashCans:
; byte 0: mask for random number
; bytes 1-4: indices of the trash cans that can have the second lock
-; (but see the comment above explaining a bug regarding this)
; Note that the mask is simply the number of valid trash can indices that
-; follow. The remaining bytes are filled with 0 to pad the length of each entry
+; follow. The remaining bytes are filled with -1 to pad the length of each entry
; to 5 bytes.
- db 2, 1, 3, 0, 0 ; 0
- db 3, 0, 2, 4, 0 ; 1
- db 2, 1, 5, 0, 0 ; 2
- db 3, 0, 4, 6, 0 ; 3
+; This is functionally replaced with GymTrashCans3a but was never removed from source.
+
+ db 2, 1, 3, -1, -1 ; 0
+ db 3, 0, 2, 4, -1 ; 1
+ db 2, 1, 5, -1, -1 ; 2
+ db 3, 0, 4, 6, -1 ; 3
db 4, 1, 3, 5, 7 ; 4
- db 3, 2, 4, 8, 0 ; 5
- db 3, 3, 7, 9, 0 ; 6
+ db 3, 2, 4, 8, -1 ; 5
+ db 3, 3, 7, 9, -1 ; 6
db 4, 4, 6, 8, 10 ; 7
- db 3, 5, 7, 11, 0 ; 8
- db 3, 6, 10, 12, 0 ; 9
+ db 3, 5, 7, 11, -1 ; 8
+ db 3, 6, 10, 12, -1 ; 9
db 4, 7, 9, 11, 13 ; 10
- db 3, 8, 10, 14, 0 ; 11
- db 2, 9, 13, 0, 0 ; 12
- db 3, 10, 12, 14, 0 ; 13
- db 2, 11, 13, 0, 0 ; 14
+ db 3, 8, 10, 14, -1 ; 11
+ db 2, 9, 13, -1, -1 ; 12
+ db 3, 10, 12, 14, -1 ; 13
+ db 2, 11, 13, -1, -1 ; 14
VermilionGymTrashSuccessText1::
text_far _VermilionGymTrashSuccessText1
diff --git a/engine/events/hidden_events/vermilion_gym_trash2.asm b/engine/events/hidden_events/vermilion_gym_trash2.asm
new file mode 100644
index 00000000..1bc0590b
--- /dev/null
+++ b/engine/events/hidden_events/vermilion_gym_trash2.asm
@@ -0,0 +1,108 @@
+TrashCanRandom:
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call JumpToAddress
+ ld e, a
+ ld d, 0
+ ret
+
+.Jumptable:
+ dw .zero
+ dw .one
+ dw .two
+ dw .three
+ dw .four
+
+.zero
+.one
+ ld a, 0
+ ret
+
+.two
+ call Random
+ and $1
+ ret
+
+.three ; should return to a, instead returns to b
+ call Random
+ swap a
+ cp 1 * $ff / 3
+ ld b, 0
+ ret c
+ cp 2 * $ff / 3
+ ld b, 1
+ ret c
+ ld b, 2
+ ret
+
+.four
+ call Random
+ and $3
+ ret
+
+Yellow_SampleSecondTrashCan:
+ ld hl, GymTrashCans3c
+ ld a, [wGymTrashCanIndex]
+ ld c, a
+ ld b, 0
+ ld a, 9
+ call AddNTimes
+ call AddNTimes ; ????
+ ld a, [hli]
+ ldh [hGymTrashCanRandNumMask], a
+ ld e, a
+ push hl
+ call TrashCanRandom
+ pop hl
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld [wSecondLockTrashCanIndex], a
+ ld a, [hl]
+ ld [wSecondLockTrashCanIndex + 1], a
+ ret
+
+GymTrashCans3c:
+; First byte: number of trashcan entries
+; Following four byte pairs: indices for the second trash can.
+; BUG: Rows that have 3 trashcan entries are sampled incorrectly.
+; The sampling occurs by taking a random number and seeing which
+; third of the range 0-255 the number falls in. However, it returns
+; that value to the wrong register, so the result is never used.
+; Instead of using an offset in [0,1,2], the offset is instead
+; in the full range 0-255. This results in truly random behavior.
+ db 4
+ db 1,3, 3,1, 1,-1, 3,-1
+ db 3
+ db 0,2, 2,4, 4,0, -1,-1
+ db 4
+ db 1,5, 5,1, 1,-1, 5,-1
+ db 3
+ db 0,4, 4,6, 6,0, -1,-1
+ db 4
+ db 1,3, 3,1, 5,5, 7,7
+ db 3
+ db 2,4, 4,8, 8,2, -1,-1
+ db 3
+ db 3,7, 7,9, 9,3, -1,-1
+ db 4
+ db 4,8, 6,10, 8,4, 10,6
+ db 3
+ db 5,7, 7,11, 11,5, -1,-1
+ db 3
+ db 6,10, 10,12, 12,6, -1,-1
+ db 4
+ db 7,9, 9,7, 11,13, 13,11
+ db 3
+ db 8,10, 10,14, 14,8, -1,-1
+ db 4
+ db 9,13, 13,9, 9,-1, 13,-1
+ db 3
+ db 10,12, 12,14, 14,10, -1,-1
+ db 4
+ db 11,13, 13,11, 11,-1, 13,-1
diff --git a/engine/events/hidden_items.asm b/engine/events/hidden_items.asm
index 065c2d5e..3ce8b716 100644
--- a/engine/events/hidden_items.asm
+++ b/engine/events/hidden_items.asm
@@ -9,7 +9,7 @@ HiddenItems:
predef FlagActionPredef
ld a, c
and a
- ret nz
+ jr nz, .itemAlreadyFound
call EnableAutoTextBoxDrawing
ld a, 1
ld [wDoNotWaitForButtonPressAfterDisplayingText], a
@@ -18,6 +18,11 @@ HiddenItems:
call GetItemName
tx_pre_jump FoundHiddenItemText
+.itemAlreadyFound
+ ld a, $ff
+ ldh [hItemAlreadyFound], a
+ ret
+
INCLUDE "data/events/hidden_item_coords.asm"
FoundHiddenItemText::
@@ -54,7 +59,7 @@ HiddenCoins:
predef GetQuantityOfItemInBag
ld a, b
and a
- ret z
+ jr z, .doNotPickUpCoins
ld hl, HiddenCoinCoords
call FindHiddenItemOrCoinsIndex
ld [wHiddenItemOrCoinsIndex], a
@@ -65,7 +70,7 @@ HiddenCoins:
predef FlagActionPredef
ld a, c
and a
- ret nz
+ jr nz, .doNotPickUpCoins
xor a
ldh [hUnusedCoinsByte], a
ldh [hCoins], a
@@ -79,6 +84,12 @@ HiddenCoins:
cp 40
jr z, .bcd20 ; should be bcd40
jr .bcd100
+
+.doNotPickUpCoins
+ ld a, $ff
+ ldh [hItemAlreadyFound], a
+ ret
+
.bcd10
ld a, $10
ldh [hCoins + 1], a
diff --git a/engine/events/in_game_trades.asm b/engine/events/in_game_trades.asm
index 3107550f..fab80ada 100644
--- a/engine/events/in_game_trades.asm
+++ b/engine/events/in_game_trades.asm
@@ -12,13 +12,8 @@ DoInGameTradeDialogue:
call SaveScreenTilesToBuffer2
ld hl, TradeMons
ld a, [wWhichTrade]
- ld b, a
- swap a
- sub b
- sub b
- ld c, a
- ld b, 0
- add hl, bc
+ ld bc, $e
+ call AddNTimes
ld a, [hli]
ld [wInGameTradeGiveMonSpecies], a
ld a, [hli]
@@ -44,19 +39,15 @@ DoInGameTradeDialogue:
ld a, [wInGameTradeReceiveMonSpecies]
ld de, wInGameTradeReceiveMonName
call InGameTrade_GetMonName
- ld hl, wCompletedInGameTradeFlags
- ld a, [wWhichTrade]
- ld c, a
+ ld a, TRADETEXT_AFTER_TRADE
+ ld [wInGameTradeTextPointerTableIndex], a
ld b, FLAG_TEST
- predef FlagActionPredef
+ call InGameTrade_FlagActionPredef
ld a, c
and a
- ld a, TRADETEXT_AFTER_TRADE
- ld [wInGameTradeTextPointerTableIndex], a
jr nz, .printText
; if the trade hasn't been done yet
- ASSERT TRADETEXT_WANNA_TRADE == 0
- xor a
+ ld a, TRADETEXT_WANNA_TRADE
ld [wInGameTradeTextPointerTableIndex], a
call .printText
ld a, TRADETEXT_NO_TRADE
@@ -119,11 +110,8 @@ InGameTrade_DoTrade:
call AddNTimes
ld a, [hl]
ld [wCurEnemyLevel], a
- ld hl, wCompletedInGameTradeFlags
- ld a, [wWhichTrade]
- ld c, a
ld b, FLAG_SET
- predef FlagActionPredef
+ call InGameTrade_FlagActionPredef
ld hl, ConnectCableText
call PrintText
ld a, [wWhichPokemon]
@@ -147,7 +135,7 @@ InGameTrade_DoTrade:
ld [wMonDataLocation], a
call AddPartyMon
call InGameTrade_CopyDataToReceivedMon
- callfar InGameTrade_CheckForTradeEvo
+ call InGameTrade_CheckForTradeEvo
call ClearScreen
call InGameTrade_RestoreScreen
farcall RedrawMapView
@@ -239,6 +227,37 @@ InGameTrade_GetReceivedMonPointer:
ld d, h
ret
+InGameTrade_FlagActionPredef:
+ ld hl, wCompletedInGameTradeFlags
+ ld a, [wWhichTrade]
+ ld c, a
+ predef_jump FlagActionPredef
+
+InGameTrade_CheckForTradeEvo:
+ ld a, [wInGameTradeReceiveMonSpecies]
+ cp KADABRA
+ jr z, .tradeEvo
+ cp GRAVELER
+ jr z, .tradeEvo
+ cp MACHOKE
+ jr z, .tradeEvo
+ cp HAUNTER
+ jr z, .tradeEvo
+ ret
+
+.tradeEvo
+ ld a, [wPartyCount]
+ dec a
+ ld [wWhichPokemon], a
+ ld a, $1
+ ld [wForceEvolution], a
+ ld a, LINK_STATE_TRADING
+ ld [wLinkState], a
+ callfar TryEvolvingMon
+ xor a ; LINK_STATE_NONE
+ ld [wLinkState], a
+ jp PlayDefaultMusic
+
InGameTrade_TrainerString:
dname "<TRAINER>", NAME_LENGTH
diff --git a/engine/events/pikachu_happiness.asm b/engine/events/pikachu_happiness.asm
new file mode 100644
index 00000000..32a69c2b
--- /dev/null
+++ b/engine/events/pikachu_happiness.asm
@@ -0,0 +1,118 @@
+ModifyPikachuHappiness::
+ ld a, d
+ cp PIKAHAPPY_GYMLEADER
+ jr z, .checkanywhereinparty
+ cp PIKAHAPPY_WALKING
+ jr z, .checkanywhereinparty
+ push de
+ callfar IsThisPartyMonStarterPikachu
+ pop de
+ ret nc
+ jr .proceed
+
+.checkanywhereinparty
+ push de
+ callfar IsStarterPikachuAliveInOurParty
+ pop de
+ ret nc
+
+.proceed
+ push de
+ ; Divide [wPikachuHappiness] by 100. Hold the integer part in e.
+ ld e, $0
+ ld a, [wPikachuHappiness]
+ cp 100
+ jr c, .wPikachuHappiness_div_100
+ inc e
+ cp 200
+ jr c, .wPikachuHappiness_div_100
+ inc e
+.wPikachuHappiness_div_100
+ ; Get the (d, e) entry from HappinessChangeTable.
+ ld c, d
+ dec c
+ ld b, $0
+ ld hl, HappinessChangeTable
+ add hl, bc
+ add hl, bc
+ add hl, bc
+ ld d, $0
+ add hl, de
+ ld a, [hl]
+ ; If [hl] is positive, take min(0xff, [hl] + [wPikachuHappiness]).
+ ; If [hl] is negative, take max(0x00, [hl] + [wPikachuHappiness]).
+ ; Inexplicably, we're using 100 as the threshold for comparison.
+ cp 100
+ ld a, [wPikachuHappiness]
+ jr nc, .negative
+ add [hl]
+ jr nc, .okay
+ ld a, -1
+ jr .okay
+
+.negative
+ add [hl]
+ jr c, .okay
+ xor a
+.okay
+ ld [wPikachuHappiness], a
+
+ ; Restore d and get the d'th entry in PikachuMoods.
+ pop de
+ dec d
+ ld hl, PikachuMoods
+ ld e, d
+ ld d, $0
+ add hl, de
+ ld a, [hl]
+ ld b, a
+ ; Modify Pikachu's mood
+ cp $80
+ jr z, .done
+ ld a, [wPikachuMood]
+ jr c, .decreased
+ cp b
+ jr nc, .done
+ ld a, [wd49b]
+ and a
+ jr nz, .done
+ jr .update_mood
+
+.decreased
+ cp b
+ jr c, .done
+.update_mood
+ ld a, b
+ ld [wPikachuMood], a
+.done
+ ret
+
+HappinessChangeTable:
+ ; Increase
+ db 5, 3, 2 ; Gained a level
+ db 5, 3, 2 ; HP restore
+ db 1, 1, 0 ; Used X item
+ db 3, 2, 1 ; Challenged Gym Leader
+ db 1, 1, 0 ; Teach TM/HM
+ db 2, 1, 1 ; Walking around
+ ; Decrease
+ db -3, -3, -5 ; Deposited
+ db -1, -1, -1 ; Fainted in battle
+ db -5, -5, -10 ; Fainted due to Poison outside of battle
+ db -5, -5, -10 ; Fainted to opponent at least 30 levels higher
+ db -10, -10, -20 ; Traded away
+
+PikachuMoods:
+ ; Increase
+ db $8a ; Gained a level
+ db $83 ; HP restore
+ db $80 ; Teach TM/HM
+ db $80 ; Challenged Gym Leader
+ db $94 ; Unknown (d = 5)
+ db $80 ; Unknown (d = 6)
+ ; Decrease
+ db $62 ; Deposited
+ db $6c ; Fainted
+ db $62 ; Unknown (d = 9)
+ db $6c ; Unknown (d = 10)
+ db $00 ; Unknown (d = 11)
diff --git a/engine/events/poison.asm b/engine/events/poison.asm
index 8c3dc8b3..3a26df8f 100644
--- a/engine/events/poison.asm
+++ b/engine/events/poison.asm
@@ -3,13 +3,20 @@ ApplyOutOfBattlePoisonDamage:
ASSERT BIT_SCRIPTED_MOVEMENT_STATE == 7
add a ; overflows scripted movement state bit into carry flag
jp c, .noBlackOut ; no black out if joypad states are being simulated
+ ld a, [wd492]
+ bit 7, a
+ jp nz, .noBlackOut
+ ld a, [wStatusFlags4]
+ bit BIT_LINK_CONNECTED, a
+ jp nz, .noBlackOut
ld a, [wPartyCount]
and a
jp z, .noBlackOut
call IncrementDayCareMonExp
+ call Func_c4c7
ld a, [wStepCounter]
and $3 ; is the counter a multiple of 4?
- jp nz, .noBlackOut ; only apply poison damage every fourth step
+ jp nz, .skipPoisonEffectAndSound ; only apply poison damage every fourth step
ld [wWhichPokemon], a
ld hl, wPartyMon1Status
ld de, wPartySpecies
@@ -55,6 +62,12 @@ ApplyOutOfBattlePoisonDamage:
ld a, TEXT_MON_FAINTED
ldh [hTextID], a
call DisplayTextID
+ callfar IsThisPartyMonStarterPikachu
+ jr nc, .curMonNotPlayerPikachu
+ ldpikacry e, PikachuCry4
+ callfar PlayPikachuSoundClip
+ callfar_ModifyPikachuHappiness PIKAHAPPY_PSNFNT
+.curMonNotPlayerPikachu
pop de
pop hl
.nextMon
@@ -111,3 +124,29 @@ ApplyOutOfBattlePoisonDamage:
.done
ld [wOutOfBattleBlackout], a
ret
+
+Func_c4c7:
+ ld a, [wStepCounter]
+ and a
+ jr nz, .asm_c4de
+ call Random
+ and $1
+ jr z, .asm_c4de
+ callfar_ModifyPikachuHappiness PIKAHAPPY_WALKING
+.asm_c4de
+ ld hl, wPikachuMood
+ ld a, [hl]
+ cp $80
+ jr z, .asm_c4ef
+ jr c, .asm_c4ea
+ dec a
+ dec a
+.asm_c4ea
+ inc a
+ ld [hl], a
+ cp $80
+ ret nz
+.asm_c4ef
+ xor a
+ ld [wd49b], a
+ ret
diff --git a/engine/events/pokecenter.asm b/engine/events/pokecenter.asm
index e52c8f5e..6b8c584c 100644
--- a/engine/events/pokecenter.asm
+++ b/engine/events/pokecenter.asm
@@ -1,4 +1,13 @@
DisplayPokemonCenterDialogue_::
+ ld a, [wCurMap]
+ cp PEWTER_POKECENTER
+ jr nz, .regularCenter
+ call CheckPikachuFollowingPlayer
+ jr z, .regularCenter
+ ld hl, LooksContentText ; if pikachu is sleeping, don't heal
+ call PrintText
+ ret
+.regularCenter
call SaveScreenTilesToBuffer1 ; save screen
ld hl, PokemonCenterWelcomeText
call PrintText
@@ -11,18 +20,36 @@ DisplayPokemonCenterDialogue_::
call PrintText
.skipShallWeHealYourPokemon
call YesNoChoicePokeCenter ; yes/no menu
+ call UpdateSprites
ld a, [wCurrentMenuItem]
and a
- jr nz, .declinedHealing ; if the player chose No
+ jp nz, .declinedHealing ; if the player chose No
call SetLastBlackoutMap
- call LoadScreenTilesFromBuffer1 ; restore screen
+ callfar IsStarterPikachuAliveInOurParty
+ jr nc, .notHealingPlayerPikachu
+ call CheckPikachuFollowingPlayer
+ jr nz, .notHealingPlayerPikachu
+ call LoadCurrentMapView
+ call Delay3
+ call UpdateSprites
+ callfar PikachuWalksToNurseJoy
+.notHealingPlayerPikachu
ld hl, NeedYourPokemonText
call PrintText
- ld a, $18
- ld [wSprite01StateData1ImageIndex], a ; make the nurse turn to face the machine
- call Delay3
- predef HealParty
+ ld c, 64
+ call DelayFrames
+ call CheckPikachuFollowingPlayer
+ jr nz, .playerPikachuNotOnScreen
+ call DisablePikachuOverworldSpriteDrawing
+ callfar IsStarterPikachuAliveInOurParty
+ call c, Func_6eaa
+.playerPikachuNotOnScreen
+ lb bc, 1, 8
+ call Func_6ebb
+ ld c, 30
+ call DelayFrames
farcall AnimateHealingMachine ; do the healing machine animation
+ predef HealParty
xor a
ld [wAudioFadeOutControl], a
ld a, [wAudioSavedROMBank]
@@ -31,19 +58,69 @@ DisplayPokemonCenterDialogue_::
ld [wLastMusicSoundID], a
ld [wNewSoundID], a
call PlaySound
+ call CheckPikachuFollowingPlayer
+ jr nz, .doNotReturnPikachu
+ callfar IsStarterPikachuAliveInOurParty
+ call c, Func_6eaa
+ ld a, $5
+ ld [wPikachuSpawnState], a
+ call EnablePikachuOverworldSpriteDrawing
+.doNotReturnPikachu
+ lb bc, 1, 0
+ call Func_6ebb
ld hl, PokemonFightingFitText
call PrintText
- ld a, $14
- ld [wSprite01StateData1ImageIndex], a ; make the nurse bow
- ld c, a
+ callfar IsStarterPikachuAliveInOurParty
+ jr nc, .notInParty
+ lb bc, 15, 0
+ call Func_6ebb
+.notInParty
+ call LoadCurrentMapView
+ call Delay3
+ call UpdateSprites
+ callfar ReloadWalkingTilePatterns
+ ld a, $1
+ ldh [hSpriteIndex], a
+ ld a, $1
+ ldh [hSpriteImageIndex], a
+ call SpriteFunc_34a1
+ ld c, 40
call DelayFrames
+ call UpdateSprites
+ call LoadFontTilePatterns
jr .done
.declinedHealing
call LoadScreenTilesFromBuffer1 ; restore screen
.done
ld hl, PokemonCenterFarewellText
call PrintText
- jp UpdateSprites
+ call UpdateSprites
+ ret
+
+Func_6eaa:
+ ld a, $1
+ ldh [hSpriteIndex], a
+ ld a, $4
+ ldh [hSpriteImageIndex], a
+ call SpriteFunc_34a1
+ ld c, 64
+ call DelayFrames
+ ret
+
+Func_6ebb:
+ ld a, b
+ ldh [hSpriteIndex], a
+ ld a, c
+ ldh [hSpriteImageIndex], a
+ push bc
+ call SetSpriteFacingDirectionAndDelay
+ pop bc
+ ld a, b
+ ldh [hSpriteIndex], a
+ ld a, c
+ ldh [hSpriteImageIndex], a
+ call SpriteFunc_34a1
+ ret
PokemonCenterWelcomeText:
text_far _PokemonCenterWelcomeText
@@ -66,3 +143,7 @@ PokemonCenterFarewellText:
text_pause
text_far _PokemonCenterFarewellText
text_end
+
+LooksContentText:
+ text_far _LooksContentText
+ text_end
diff --git a/engine/events/pokecenter_chansey.asm b/engine/events/pokecenter_chansey.asm
new file mode 100644
index 00000000..d7c3a95b
--- /dev/null
+++ b/engine/events/pokecenter_chansey.asm
@@ -0,0 +1,11 @@
+PokecenterChanseyText::
+ ld hl, NurseChanseyText
+ call PrintText
+ ld a, CHANSEY
+ call PlayCry
+ call WaitForSoundToFinish
+ ret
+
+NurseChanseyText:
+ text_far _NurseChanseyText
+ text_end
diff --git a/engine/events/prize_menu.asm b/engine/events/prize_menu.asm
index 1f71af42..8f25f272 100644
--- a/engine/events/prize_menu.asm
+++ b/engine/events/prize_menu.asm
@@ -23,8 +23,7 @@ CeladonPrizeMenu::
ld [wTopMenuItemX], a
call PrintPrizePrice
hlcoord 0, 2
- ld b, 8
- ld c, 16
+ lb bc, 8, 16
call TextBoxBorder
call GetPrizeMenuId
call UpdateSprites
@@ -137,12 +136,14 @@ GetPrizeMenuId:
ld c, 2 | LEADING_ZEROES
jp PrintBCDNumber
+NoThanksText:
+ db "NO THANKS@"
+
INCLUDE "data/events/prizes.asm"
PrintPrizePrice:
hlcoord 11, 0
- ld b, 1
- ld c, 7
+ lb bc, 1, 7
call TextBoxBorder
call UpdateSprites
hlcoord 12, 0
diff --git a/engine/events/try_pikachu_movement.asm b/engine/events/try_pikachu_movement.asm
new file mode 100644
index 00000000..9dd25008
--- /dev/null
+++ b/engine/events/try_pikachu_movement.asm
@@ -0,0 +1,27 @@
+TryApplyPikachuMovementData::
+ ld a, [wd471]
+ bit 7, a
+ ret z
+ ld a, [wWalkBikeSurfState]
+ and a
+ ret nz
+ push hl
+ push bc
+ callfar GetPikachuFacingDirectionAndReturnToE
+ pop bc
+ pop hl
+ ld a, b
+ cp e
+ ret nz
+ push hl
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ callfar LoadPikachuShadowIntoVRAM
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ pop hl
+ call ApplyPikachuMovementData
+ callfar RefreshPikachuFollow
+ ret
diff --git a/engine/events/vending_machine.asm b/engine/events/vending_machine.asm
index bdbcd9bb..979d9d82 100644
--- a/engine/events/vending_machine.asm
+++ b/engine/events/vending_machine.asm
@@ -18,8 +18,7 @@ VendingMachineMenu::
ld hl, wStatusFlags5
set BIT_NO_TEXT_DELAY, [hl]
hlcoord 0, 3
- ld b, 8
- ld c, 12
+ lb bc, 8, 12
call TextBoxBorder
call UpdateSprites
hlcoord 2, 5
diff --git a/engine/gfx/animated_objects.asm b/engine/gfx/animated_objects.asm
new file mode 100644
index 00000000..83d36aa9
--- /dev/null
+++ b/engine/gfx/animated_objects.asm
@@ -0,0 +1,394 @@
+ClearObjectAnimationBuffers:
+ ld hl, wAnimatedObjectsData
+ ld bc, wAnimatedObjectsDataEnd - wAnimatedObjectsData
+ xor a
+ call FillMemory
+ ret
+
+RunObjectAnimations:
+ ld hl, wAnimatedObjectDataStructs
+ ld e, 10
+.loop
+ ld a, [hl]
+ and a
+ jr z, .next
+ ld c, l
+ ld b, h
+ push hl
+ push de
+ call ExecuteCurrentAnimatedObjectCallback
+ call UpdateCurrentAnimatedObjectFrame
+ pop de
+ pop hl
+ jr c, .quit
+.next
+ ld bc, $10
+ add hl, bc
+ dec e
+ jr nz, .loop
+ ld a, [wCurrentAnimatedObjectOAMBufferOffset]
+ ld l, a
+ ld h, HIGH(wShadowOAM)
+.deinit_unused_oam_loop
+ ld a, l
+ cp LOW(wShadowOAMEnd)
+ jr nc, .quit
+ xor a
+ ld [hli], a
+ jr .deinit_unused_oam_loop
+
+.quit
+ ret
+
+SpawnAnimatedObject:
+ push de
+ push af
+ ld hl, wAnimatedObjectDataStructs
+ ld e, 10
+.loop
+ ld a, [hl]
+ and a
+ jr z, .init
+ ld bc, $10
+ add hl, bc
+ dec e
+ jr nz, .loop
+ pop af
+ pop de
+ scf
+ ret
+
+.init
+ pop af
+ ld c, l
+ ld b, h
+ ld hl, wNumLoadedAnimatedObjects
+ inc [hl]
+ ld e, a
+ ld d, $0
+ ld a, [wAnimatedObjectSpawnStateDataPointer]
+ ld l, a
+ ld a, [wAnimatedObjectSpawnStateDataPointer + 1]
+ ld h, a
+ add hl, de
+ add hl, de
+ add hl, de
+ ld e, l
+ ld d, h
+ ld hl, $0
+ add hl, bc
+ ld a, [wNumLoadedAnimatedObjects]
+ ld [hli], a
+ ld a, [de]
+ ld [hli], a
+ inc de
+ ld a, [de]
+ ld [hli], a
+ inc de
+ xor a
+ ld [hli], a
+ pop de
+ ld hl, $4
+ add hl, bc
+ ld a, e
+ ld [hli], a
+ ld a, d
+ ld [hli], a
+ xor a
+ ld [hli], a
+ ld [hli], a
+ xor a
+ ld [hli], a
+ ld [hli], a
+ dec a
+ ld [hli], a
+ xor a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ret
+
+MaskCurrentAnimatedObjectStruct:
+ ld hl, $0
+ add hl, bc
+ ld [hl], $0
+ ret
+
+MaskAllAnimatedObjectStructs:
+ ld hl, wAnimatedObjectDataStructs
+ ld e, 10
+.loop
+ ld [hl], $0
+ ld bc, $10
+ add hl, bc
+ dec e
+ jr nz, .loop
+ ret
+
+UpdateCurrentAnimatedObjectFrame:
+ xor a
+ ld [wCurAnimatedObjectOAMAttributes], a
+ ld hl, $3
+ add hl, bc
+ ld a, [hli]
+ ld [wCurrentAnimatedObjectVTileOffset], a
+ ld a, [hli]
+ ld [wCurrentAnimatedObjectXCoord], a
+ ld a, [hli]
+ ld [wCurrentAnimatedObjectYCoord], a
+ ld a, [hli]
+ ld [wCurrentAnimatedObjectXOffset], a
+ ld a, [hl]
+ ld [wCurrentAnimatedObjectYOffset], a
+ call UpdateDurationTimerAndFrameStateForCurrentAnimatedObject
+ cp $fd
+ jr z, .finish
+ cp $fc
+ jr z, .delete_animation
+ call GetCurrentAnimatedObjectOAMDataPointer
+ ld a, [wCurrentAnimatedObjectVTileOffset]
+ add [hl]
+ ld [wCurrentAnimatedObjectVTileOffset], a
+ inc hl
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ push bc
+ ld a, [wCurrentAnimatedObjectOAMBufferOffset]
+ ld e, a
+ ld d, HIGH(wShadowOAM)
+ ld a, [hli]
+ ld c, a
+.loop
+ ld a, [wCurrentAnimatedObjectYCoord]
+ ld b, a
+ ld a, [wCurrentAnimatedObjectYOffset]
+ add b
+ ld b, a
+ ld a, [wAnimatedObjectGlobalYOffset]
+ add b
+ ld b, a
+ call GetCurrentAnimatedObjectTileYCoordinate
+ add b
+ ld [de], a
+ inc hl
+ inc de
+ ld a, [wCurrentAnimatedObjectXCoord]
+ ld b, a
+ ld a, [wCurrentAnimatedObjectXOffset]
+ add b
+ ld b, a
+ ld a, [wAnimatedObjectGlobalXOffset]
+ add b
+ ld b, a
+ call GetCurrentAnimatedObjectTileXCoordinate
+ add b
+ ld [de], a
+ inc hl
+ inc de
+ ld a, [wCurrentAnimatedObjectVTileOffset]
+ add [hl]
+ ld [de], a
+ inc hl
+ inc de
+ call SetCurrentAnimatedObjectOAMAttributes
+ ld b, a
+ ld a, [wc634]
+ cp $7
+ ld a, b
+ jr z, .skip_load
+ ld [de], a
+.skip_load
+ inc hl
+ inc de
+ ld a, e
+ ld [wCurrentAnimatedObjectOAMBufferOffset], a
+ cp LOW(wShadowOAMEnd)
+ jr nc, .oam_is_full
+ dec c
+ jr nz, .loop
+ pop bc
+ jr .finish
+
+.delete_animation
+ call MaskCurrentAnimatedObjectStruct
+.finish
+ and a
+ ret
+
+.oam_is_full
+ pop bc
+ scf
+ ret
+
+GetCurrentAnimatedObjectTileYCoordinate:
+ push hl
+ ld a, [hl]
+ ld hl, wCurAnimatedObjectOAMAttributes
+ bit B_OAM_YFLIP, [hl]
+ jr z, .no_flip
+ add $8
+ xor $ff
+ inc a
+.no_flip
+ pop hl
+ ret
+
+GetCurrentAnimatedObjectTileXCoordinate:
+ push hl
+ ld a, [hl]
+ ld hl, wCurAnimatedObjectOAMAttributes
+ bit B_OAM_XFLIP, [hl]
+ jr z, .no_flip
+ add $8
+ xor $ff
+ inc a
+.no_flip
+ pop hl
+ ret
+
+SetCurrentAnimatedObjectOAMAttributes:
+ ld a, [wCurAnimatedObjectOAMAttributes]
+ ld b, a
+ ld a, [hl]
+ xor b
+ and OAM_XFLIP | OAM_YFLIP | OAM_PRIO
+ ld b, a
+ ld a, [hl]
+ and OAM_PAL1
+ or b
+ bit B_OAM_PAL1, a
+ ret z
+ or OAM_HIGH_PALS
+ ret
+
+GetCurrentAnimatedObjectOAMDataPointer:
+ ld e, a
+ ld d, $0
+ ld a, [wAnimatedObjectOAMDataPointer]
+ ld l, a
+ ld a, [wAnimatedObjectOAMDataPointer + 1]
+ ld h, a
+ add hl, de
+ add hl, de
+ add hl, de
+ ret
+
+SetCurrentAnimatedObjectCallbackAndResetFrameStateRegisters:
+ ld hl, $1
+ add hl, bc
+ ld [hl], a
+ ld hl, $8
+ add hl, bc
+ ld [hl], $0
+ ld hl, $9
+ add hl, bc
+ ld [hl], $0
+ ld hl, $a
+ add hl, bc
+ ld [hl], $ff
+ ret
+
+UpdateDurationTimerAndFrameStateForCurrentAnimatedObject:
+.loop
+ ld hl, $8
+ add hl, bc
+ ld a, [hl]
+ and a
+ jr z, .next_frame
+ dec [hl]
+ call GetPointerToCurrentAnimatedObjectFrameScript
+ ld a, [hli]
+ push af
+ jr .finish
+
+.next_frame
+ ld hl, $a
+ add hl, bc
+ inc [hl]
+ call GetPointerToCurrentAnimatedObjectFrameScript
+ ld a, [hli]
+ cp $fe
+ jr z, .restart_anim
+ cp $ff
+ jr z, .hold_last_frame_state
+ push af
+ ld a, [hl]
+ push hl
+ and $3f
+ ld hl, $9
+ add hl, bc
+ add [hl]
+ ld hl, $8
+ add hl, bc
+ ld [hl], a
+ pop hl
+.finish
+ ld a, [hl]
+ and $c0
+ srl a
+ ld [wCurAnimatedObjectOAMAttributes], a
+ pop af
+ ret
+
+.hold_last_frame_state
+ xor a
+ ld hl, $8
+ add hl, bc
+ ld [hl], a
+ ld hl, $a
+ add hl, bc
+ dec [hl]
+ dec [hl]
+ jr .loop
+
+.restart_anim
+ xor a
+ ld hl, $8
+ add hl, bc
+ ld [hl], a
+ dec a
+ ld hl, $a
+ add hl, bc
+ ld [hl], a
+ jr .loop
+
+GetPointerToCurrentAnimatedObjectFrameScript:
+ ld hl, $1
+ add hl, bc
+ ld e, [hl]
+ ld d, $0
+ ld a, [wAnimatedObjectFramesDataPointer]
+ ld l, a
+ ld a, [wAnimatedObjectFramesDataPointer + 1]
+ ld h, a
+ add hl, de
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld hl, $a
+ add hl, bc
+ ld l, [hl]
+ ld h, $0
+ add hl, hl
+ add hl, de
+ ret
+
+ExecuteCurrentAnimatedObjectCallback:
+ ld hl, $2
+ add hl, bc
+ ld e, [hl]
+ ld d, $0
+ ld a, [wAnimatedObjectJumptablePointer]
+ ld l, a
+ ld a, [wAnimatedObjectJumptablePointer + 1]
+ ld h, a
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
diff --git a/engine/gfx/bg_map_attributes.asm b/engine/gfx/bg_map_attributes.asm
new file mode 100644
index 00000000..cc550ff8
--- /dev/null
+++ b/engine/gfx/bg_map_attributes.asm
@@ -0,0 +1,217 @@
+LoadBGMapAttributes::
+ ld hl, BGMapAttributesPointers
+ ld a, c ; c = which packet
+ push af ; save for later (to determine if we're handling the trainer card or party menu)
+ dec a ; read this code as:
+ add a ; dec a
+ ld e, a ; add a
+ xor a ; ld e, a
+ ld d, a ; ld d, 0
+ add hl, de ; add hl, de
+ ld a, [hli] ; ld a, [hli]
+ ld e, a ; ld h, [hl]
+ ld a, [hl] ; ld l, a
+ ld h, a
+ ld a, e
+ ld l, a
+
+ di
+ ld a, $1
+ ldh [rVBK], a
+ push hl
+ ld a, [hl]
+ ld c, a ; save attribute count for later
+ ld de, $10
+ add hl, de
+ ld a, h
+ ldh [rVDMA_SRC_HIGH], a
+ ld a, l
+ ldh [rVDMA_SRC_LOW], a
+ ld de, vBGMap0
+ ld a, d
+ ldh [rVDMA_DEST_HIGH], a
+ ld a, e
+ ldh [rVDMA_DEST_LOW], a
+
+ ldh a, [rLCDC]
+ and LCDC_ON ; is LCD off?
+ jr z, .lcdOff ; if off, transfer immediately
+; wait for VBlank if LCD is on
+.waitForVBlankLoop1
+ ldh a, [rLY]
+ cp $90
+ jr nz, .waitForVBlankLoop1
+.waitForAccessibleVRAMLoop1
+ ldh a, [rSTAT]
+ and %10 ; are we in HBlank or VBlank?
+ jr nz, .waitForAccessibleVRAMLoop1 ; loop until we're in a safe period to transfer to VRAM
+.lcdOff
+ ld a, c ; number of BG attributes to transfer, plus 1 times 16
+ ldh [rVDMA_LEN], a ; initiate transfer
+ call Func_3082 ; update audio so it doesn't "lag"
+ pop hl
+ ld a, [hli]
+ ld c, a ; number of BG attributes to transfer, plus 1 times 16
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a ; offset of the attributes
+ add hl, de ; hl = new pointer
+ ld a, h
+ ldh [rVDMA_SRC_HIGH], a
+ ld a, l
+ ldh [rVDMA_SRC_LOW], a
+ ld de, vBGMap1 ; copy to vBGMap1
+ ld a, d
+ ldh [rVDMA_DEST_HIGH], a
+ ld a, e
+ ldh [rVDMA_DEST_LOW], a
+; LCD check again
+ ldh a, [rLCDC]
+ and LCDC_ON ; is LCD off?
+ jr z, .lcdOff2 ; if off, transfer immediately
+; wait for VBlank if LCD is on
+.waitForVBlankLoop2
+ ldh a, [rLY]
+ cp $90
+ jr nz, .waitForVBlankLoop2
+.waitForAccessibleVRAMLoop2
+ ldh a, [rSTAT]
+ and %10 ; are we in HBlank or VBlank?
+ jr nz, .waitForAccessibleVRAMLoop2 ; loop until we're in a safe period to transfer to VRAM
+.lcdOff2
+ ld a, c
+ ldh [rVDMA_LEN], a
+ pop af
+ dec a
+ dec a
+ dec a
+ dec a
+ jr nz, .checkIfHandlingPartyMenu
+ call HandleBadgeFaceAttributes
+ jr .done
+.checkIfHandlingPartyMenu
+ dec a
+ call z, HandlePartyHPBarAttributes
+.done
+ call Func_3082
+ ldh a, [rIF]
+ res B_IF_VBLANK, a
+ ldh [rIF], a
+ xor a
+ ldh [rVBK], a
+ ei
+ ret
+
+BGMapAttributesPointers:
+ dw BGMapAttributes_Unknown1
+ dw BGMapAttributes_Unknown2
+ dw BGMapAttributes_GameFreakIntro
+ dw BGMapAttributes_TrainerCard
+ dw BGMapAttributes_PartyMenu
+ dw BGMapAttributes_NidorinoIntro
+ dw BGMapAttributes_TitleScreen
+ dw BGMapAttributes_Slots
+ dw BGMapAttributes_Pokedex
+ dw BGMapAttributes_StatusScreen
+ dw BGMapAttributes_Battle
+ dw BGMapAttributes_WholeScreen
+ dw BGMapAttributes_Unknown13
+
+HandleBadgeFaceAttributes:
+; zero out the attributes if the player doesn't have the respective badge
+; BOULDERBADGE
+ ld hl, vBGMap1 + $183
+ ld de, wTrainerCardBadgeAttributes + 6 * 0
+ ld a, [de]
+ and a
+ call z, ZeroOutCurrentBadgeAttributes
+; CASCADEBADGE
+ ld hl, vBGMap1 + $187
+ ld de, wTrainerCardBadgeAttributes + 6 * 1
+ ld a, [de]
+ and a
+ call z, ZeroOutCurrentBadgeAttributes
+; THUNDERBADGE
+ ld hl, vBGMap1 + $18b
+ ld de, wTrainerCardBadgeAttributes + 6 * 2
+ ld a, [de]
+ and a
+ call z, ZeroOutCurrentBadgeAttributes
+; RAINBOWBADGE
+ ld hl, vBGMap1 + $18f
+ ld de, wTrainerCardBadgeAttributes + 6 * 3
+ ld a, [de]
+ and a
+ call z, ZeroOutCurrentBadgeAttributes
+; SOULBADGE
+ ld hl, vBGMap1 + $1e3
+ ld de, wTrainerCardBadgeAttributes + 6 * 6
+ ld a, [de]
+ and a
+ call z, ZeroOutCurrentBadgeAttributes
+; MARSHBADGE
+ ld hl, vBGMap1 + $1e7
+ ld de, wTrainerCardBadgeAttributes + 6 * 7
+ ld a, [de]
+ and a
+ call z, ZeroOutCurrentBadgeAttributes
+; VOLCANOBADGE
+ ld hl, vBGMap1 + $1eb
+ ld de, wTrainerCardBadgeAttributes + 6 * 8
+ ld a, [de]
+ and a
+ call z, ZeroOutCurrentBadgeAttributes
+; EARTHBADGE
+ ld hl, vBGMap1 + $1ef
+ ld de, wTrainerCardBadgeAttributes + 6 * 9
+ ld a, [de]
+ and a
+ call z, ZeroOutCurrentBadgeAttributes
+ ret
+
+ZeroOutCurrentBadgeAttributes:
+ push hl
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ld bc, $1f
+ add hl, bc
+ ld [hli], a
+ ld [hl], a
+ pop hl
+ ret
+
+HandlePartyHPBarAttributes:
+; hp bars require 3 (green, orange, red) colours, when there are only 2 "free" colours per palette
+; therefore, we must transfer individual bg attributes where the locations of the hp bars are in vram
+ ld hl, vBGMap1 + $25 ; location of start of the HP bar in vram
+ ld de, wPartyHPBarAttributes
+ ld c, PARTY_LENGTH
+.loop
+ push bc
+ push hl
+ ld a, [de]
+ and $3 ; 4 possible palettes
+REPT 7 ; hp bar length in tiles
+ ld [hli], a
+ENDR
+ pop hl
+ ld bc, $40 ; get 2nd party location
+ add hl, bc
+ push hl
+
+ push de ; (inefficiently) copy de to hl
+ pop hl
+
+ ld bc, $6
+ add hl, bc ; get the next palette
+
+ push hl
+ pop de ; copy back to de
+
+ pop hl
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
diff --git a/engine/gfx/hp_bar.asm b/engine/gfx/hp_bar.asm
index d8dcaa24..04a3251a 100644
--- a/engine/gfx/hp_bar.asm
+++ b/engine/gfx/hp_bar.asm
@@ -213,14 +213,12 @@ UpdateHPBar_PrintHPNumber:
ld a, [wHPBarOldHP + 1]
ld [wHPBarTempHP], a
push hl
+ ld de, $15
ldh a, [hUILayoutFlags]
bit BIT_PARTY_MENU_HP_BAR, a
jr z, .hpBelowBar
ld de, $9
- jr .next
.hpBelowBar
- ld de, $15
-.next
add hl, de
push hl
ld a, ' '
diff --git a/engine/gfx/mon_icons.asm b/engine/gfx/mon_icons.asm
index 63da2345..4775084f 100644
--- a/engine/gfx/mon_icons.asm
+++ b/engine/gfx/mon_icons.asm
@@ -91,7 +91,7 @@ PartyMonSpeeds:
LoadMonPartySpriteGfx:
; Load mon party sprite tile patterns into VRAM during V-blank.
ld hl, MonPartySpritePointers
- ld a, $1c
+ ld a, $1e
LoadAnimSpriteGfx:
; Load animated sprite tile patterns into VRAM during V-blank. hl is the address
@@ -130,7 +130,7 @@ LoadMonPartySpriteGfxWithLCDDisabled:
; LCD.
call DisableLCD
ld hl, MonPartySpritePointers
- ld a, $1c
+ ld a, $1e
ld bc, $0
.loop
push af
@@ -151,7 +151,7 @@ LoadMonPartySpriteGfxWithLCDDisabled:
inc hl
ld d, [hl]
pop hl
- call FarCopyData2
+ call FarCopyData
pop hl
pop bc
ld a, $6
@@ -170,6 +170,8 @@ WriteMonPartySpriteOAMByPartyIndex:
push de
push bc
ldh a, [hPartyMonIndex]
+ cp $ff
+ jr z, .asm_7191f
ld hl, wPartySpecies
ld e, a
ld d, 0
@@ -183,6 +185,16 @@ WriteMonPartySpriteOAMByPartyIndex:
pop hl
ret
+.asm_7191f
+ ld hl, wShadowOAM
+ ld de, wMonPartySpritesSavedOAM
+ ld bc, $60
+ call CopyData
+ pop bc
+ pop de
+ pop hl
+ ret
+
WriteMonPartySpriteOAMBySpecies:
; Write OAM blocks for the party sprite of the species in
; [wMonPartySpriteSpecies].
@@ -204,7 +216,7 @@ UnusedPartyMonSpriteFunction:
ld hl, vSprites tile $00
call .LoadTilePatterns
pop af
- add $54
+ add $5A
ld hl, vSprites tile $04
call .LoadTilePatterns
xor a
diff --git a/engine/gfx/palettes.asm b/engine/gfx/palettes.asm
index f4ae5c39..359f235c 100644
--- a/engine/gfx/palettes.asm
+++ b/engine/gfx/palettes.asm
@@ -30,11 +30,17 @@ SetPal_Battle:
ld de, wPalPacket
ld bc, $10
call CopyData
- ld a, [wPlayerBattleStatus3]
ld hl, wBattleMonSpecies
+ ld a, [hl]
+ and a
+ jr z, .asm_71ef9
+ ld hl, wPartyMon1
+ ld a, [wPlayerMonNumber]
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+.asm_71ef9
call DeterminePaletteID
ld b, a
- ld a, [wEnemyBattleStatus3]
ld hl, wEnemyMonSpecies2
call DeterminePaletteID
ld c, a
@@ -155,6 +161,10 @@ SetPal_Overworld:
jr z, .Lorelei
cp BRUNOS_ROOM
jr z, .caveOrBruno
+ cp TRADE_CENTER
+ jr z, .trade_center_colosseum
+ cp COLOSSEUM
+ jr z, .trade_center_colosseum
.normalDungeonOrBuilding
ld a, [wLastMap] ; town or route that current dungeon or building is located
.townOrRoute
@@ -178,6 +188,9 @@ SetPal_Overworld:
.Lorelei
xor a
jr .town
+.trade_center_colosseum
+ ld a, PAL_GRAYMON - 1
+ jr .town
; used when a Pokemon is the only thing on the screen
; such as evolution, trading and the Hall of Fame
@@ -240,6 +253,16 @@ SetPal_TrainerCard:
ld de, wTrainerCardBlkPacket
ret
+SetPal_PikachusBeach::
+ ld hl, PalPacket_PikachusBeach
+ ld de, BlkPacket_WholeScreen
+ ret
+
+SetPal_PikachusBeachTitle::
+ ld hl, PalPacket_PikachusBeachTitle
+ ld de, UnknownPacket_72751
+ ret
+
SetPalFunctions:
; entries correspond to SET_PAL_* constants
dw SetPal_BattleBlack
@@ -256,6 +279,8 @@ SetPalFunctions:
dw SetPal_PokemonWholeScreen
dw SetPal_GameFreakIntro
dw SetPal_TrainerCard
+ dw SetPal_PikachusBeach
+ dw SetPal_PikachusBeachTitle
; The length of the blk data of each badge on the Trainer Card.
; The Rainbow Badge has 3 entries because of its many colors.
@@ -270,9 +295,6 @@ BadgeBlkDataLengths:
db 6 ; Earth Badge
DeterminePaletteID:
- bit TRANSFORMED, a ; a is battle status 3
- ld a, PAL_GRAYMON ; if the mon has used Transform, use Ditto's palette
- ret nz
ld a, [hl]
DeterminePaletteIDOutOfBattle:
ld [wPokedexNum], a
@@ -290,6 +312,132 @@ DeterminePaletteIDOutOfBattle:
ld a, [hl]
ret
+YellowIntroPaletteAction::
+ ld a, e
+ and a
+ jr nz, .asm_720bd
+ ld hl, PalPacket_Generic
+ ldh a, [hOnCGB]
+ and a
+ jp z, SendSGBPacket
+ jp InitCGBPalettes
+
+.asm_720bd
+ ld hl, PalPacket_PikachusBeach
+ ldh a, [hOnCGB]
+ and a
+ jp z, SendSGBPacket
+ call InitCGBPalettes
+ ld hl, PalPacket_Generic
+ inc hl
+ ld a, [hli]
+ call GetCGBBasePalAddress
+ ld a, e
+ ld [wCGBBasePalPointers + 2], a
+ ld a, d
+ ld [wCGBBasePalPointers + 2 + 1], a
+ xor a ; CONVERT_BGP
+ call DMGPalToCGBPal
+ ld a, 1
+ call TransferCurBGPData
+ ret
+
+LoadOverworldPikachuFrontpicPalettes::
+ ld hl, PalPacket_Empty
+ ld de, wPalPacket
+ ld bc, $10
+ call CopyData
+ call GetPal_Pikachu
+ ld hl, wPartyMenuBlkPacket
+ ld [hl], a
+ ld hl, wPartyMenuBlkPacket + 2
+ ld a, PAL_PIKACHU_PORTRAIT
+ ld [hl], a
+ ld hl, wPalPacket
+ ldh a, [hOnCGB]
+ and a
+ jr nz, .cgb_1
+ call SendSGBPacket
+ jr .okay_1
+
+.cgb_1
+ call InitCGBPalettes
+.okay_1
+ ld hl, BlkPacket_WholeScreen
+ ld de, wPalPacket
+ ld bc, $10
+ call CopyData
+ ld hl, wPartyMenuBlkPacket + 2
+ ld a, $5
+ ld [hli], a
+ ld a, $7
+ ld [hli], a
+ ld a, $6
+ ld [hli], a
+ ld a, $b
+ ld [hli], a
+ ld a, $a
+ ld [hl], a
+ ld hl, wPalPacket
+ ldh a, [hOnCGB]
+ and a
+ jr nz, .cgb_2
+ call SendSGBPacket
+ jr .okay_2
+
+.cgb_2
+ call InitCGBPalettes
+.okay_2
+ ret
+
+GetPal_Pikachu::
+; similar to SetPal_Overworld
+ ld a, [wCurMapTileset]
+ cp CEMETERY
+ jr z, .PokemonTowerOrAgatha
+ cp CAVERN
+ jr z, .caveOrBruno
+ ld a, [wCurMap]
+ cp REDS_HOUSE_1F
+ jr c, .townOrRoute
+ cp CERULEAN_CAVE_2F
+ jr c, .normalDungeonOrBuilding
+ cp NAME_RATERS_HOUSE
+ jr c, .caveOrBruno
+ cp LORELEIS_ROOM
+ jr z, .Lorelei
+ cp BRUNOS_ROOM
+ jr z, .caveOrBruno
+ cp TRADE_CENTER
+ jr z, .battleOrTradeCenter
+ cp COLOSSEUM
+ jr z, .battleOrTradeCenter
+.normalDungeonOrBuilding
+ ld a, [wLastMap] ; town or route that current dungeon or building is located
+.townOrRoute
+ cp SAFFRON_CITY + 1
+ jr c, .town
+ ld a, PAL_ROUTE - 1
+.town
+ inc a ; a town's pallete ID is its map ID + 1
+ ret
+
+.PokemonTowerOrAgatha
+ ld a, PAL_GRAYMON - 1
+ jr .town
+
+.caveOrBruno
+ ld a, PAL_CAVE - 1
+ jr .town
+
+.Lorelei
+ xor a ; PAL_PALLET - 1
+ jr .town
+
+.battleOrTradeCenter
+ ld a, PAL_GRAYMON - 1
+ jr .town
+
InitPartyMenuBlkPacket:
ld hl, BlkPacket_PartyMenu
ld de, wPartyMenuBlkPacket
@@ -325,6 +473,14 @@ UpdatePartyMenuBlkPacket:
ret
SendSGBPacket:
+ ld a, 1
+ ldh [hDisableJoypadPolling], a ; don't poll joypad while sending packet
+ call _SendSGBPacket
+ xor a
+ ldh [hDisableJoypadPolling], a
+ ret
+
+_SendSGBPacket:
;check number of packets
ld a, [hl]
and $07
@@ -334,9 +490,6 @@ SendSGBPacket:
.loop2
; save B for later use
push bc
-; disable ReadJoypad to prevent it from interfering with sending the packet
- ld a, 1
- ldh [hDisableJoypadPolling], a
; send RESET signal (P14=LOW, P15=LOW)
xor a ; JOYP_SGB_START
ldh [rJOYP], a
@@ -377,8 +530,6 @@ SendSGBPacket:
; set P14=HIGH,P15=HIGH
ld a, JOYP_SGB_FINISH
ldh [rJOYP], a
- xor a
- ldh [hDisableJoypadPolling], a
; wait for about 70000 cycles
call Wait7000
; restore (previously pushed) number of packets
@@ -393,14 +544,17 @@ LoadSGB:
xor a
ld [wOnSGB], a
call CheckSGB
- ret nc
- ld a, 1
- ld [wOnSGB], a
- ld a, [wOnCGB]
+ jr c, .onSGB
+ ldh a, [hOnCGB]
and a
- jr z, .notCGB
+ jr z, .onDMG
+ ld a, $1
+ ld [wOnSGB], a
+.onDMG
ret
-.notCGB
+.onSGB
+ ld a, $1
+ ld [wOnSGB], a
di
call PrepareSuperNintendoVRAMTransfer
ei
@@ -455,11 +609,7 @@ PrepareSuperNintendoVRAMTransfer:
CheckSGB:
; Returns whether the game is running on an SGB in carry.
ld hl, MltReq2Packet
- di
call SendSGBPacket
- ld a, 1
- ldh [hDisableJoypadPolling], a
- ei
call Wait7000
ldh a, [rJOYP]
and JOYP_SGB_MLT_REQ
@@ -484,7 +634,6 @@ CheckSGB:
ldh a, [rJOYP]
ldh a, [rJOYP]
call Wait7000
- vc_hook Unknown_network_reset
call Wait7000
ld a, JOYP_SGB_FINISH
ldh [rJOYP], a
@@ -508,6 +657,7 @@ CheckSGB:
SendMltReq1Packet:
ld hl, MltReq1Packet
call SendSGBPacket
+ vc_hook Unknown_network_reset
jp Wait7000
CopyGfxToSuperNintendoVRAM:
@@ -516,6 +666,7 @@ CopyGfxToSuperNintendoVRAM:
call DisableLCD
ld a, $e4
ldh [rBGP], a
+ call _UpdateCGBPal_BGP_CheckDMG
ld de, vChars1
ld a, [wCopyingSGBTileData]
and a
@@ -546,6 +697,7 @@ CopyGfxToSuperNintendoVRAM:
call SendSGBPacket
xor a
ldh [rBGP], a
+ call _UpdateCGBPal_BGP_CheckDMG
ei
ret
@@ -563,13 +715,17 @@ Wait7000:
ret
SendSGBPackets:
- ld a, [wOnCGB]
+ ldh a, [hOnCGB]
and a
jr z, .notCGB
push de
call InitCGBPalettes
pop hl
- call EmptyFunc3
+ call InitCGBPalettes
+ ldh a, [rLCDC]
+ and LCDC_ON
+ ret z
+ call Delay3
ret
.notCGB
push de
@@ -578,30 +734,334 @@ SendSGBPackets:
jp SendSGBPacket
InitCGBPalettes:
- ld a, $80 ; index 0 with auto-increment
- ldh [rBGPI], a
- inc hl
- ld c, $20
-.loop
- ld a, [hli]
+ ld a, [hl]
+ and $f8
+ cp $20
+ jp z, TranslatePalPacketToBGMapAttributes
+
inc hl
+
+ FOR index, NUM_ACTIVE_PALS
+ IF index > 0
+ pop hl
+ ENDC
+
+ ld a, [hli]
+ inc hl
+
+ IF index < NUM_ACTIVE_PALS - 1
+ push hl
+ ENDC
+
+ call GetCGBBasePalAddress
+ ld a, e
+ ld [wCGBBasePalPointers + index * 2], a
+ ld a, d
+ ld [wCGBBasePalPointers + index * 2 + 1], a
+
+ xor a ; CONVERT_BGP
+ call DMGPalToCGBPal
+ ld a, index
+ call TransferCurBGPData
+
+ ld a, CONVERT_OBP0
+ call DMGPalToCGBPal
+ ld a, index
+ call TransferCurOBPData
+
+ ld a, CONVERT_OBP1
+ call DMGPalToCGBPal
+ ld a, index + 4
+ call TransferCurOBPData
+ ENDR
+
+ ret
+
+GetCGBBasePalAddress::
+; Input: a = palette ID
+; Output: de = palette address
+ push hl
+ ld l, a
+ xor a
+ ld h, a
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld de, CGBBasePalettes
+ add hl, de
+ ld a, l
+ ld e, a
+ ld a, h
+ ld d, a
+ pop hl
+ ret
+
+DMGPalToCGBPal::
+; Populate wCGBPal with colors from a base palette, selected using one of the
+; DMG palette registers.
+; Input:
+; a = which DMG palette register
+; de = address of CGB base palette
+ and a
+ jr nz, .notBGP
+ ldh a, [rBGP]
+ ld [wLastBGP], a
+ jr .convert
+.notBGP
+ dec a
+ jr nz, .notOBP0
+ ldh a, [rOBP0]
+ ld [wLastOBP0], a
+ jr .convert
+.notOBP0
+ ldh a, [rOBP1]
+ ld [wLastOBP1], a
+.convert
+ FOR color_index, PAL_COLORS
+ ld b, a
+ and %11
+ call .GetColorAddress
+ ld a, [hli]
+ ld [wCGBPal + color_index * 2], a
+ ld a, [hl]
+ ld [wCGBPal + color_index * 2 + 1], a
+
+ IF color_index < PAL_COLORS - 1
+ ld a, b
+ rrca
+ rrca
+ ENDC
+ ENDR
+ ret
+
+.GetColorAddress:
+ add a
+ ld l, a
+ xor a
+ ld h, a
+ add hl, de
+ ret
+
+TransferCurBGPData::
+ push de
add a
add a
add a
- ld de, SuperPalettes
- add e
- jr nc, .noCarry
- inc d
-.noCarry
+ or $80 ; auto-increment
+ ldh [rBGPI], a
+ ld de, rBGPD
+ ld hl, wCGBPal
+ ld b, %10 ; mask for non-V-blank/non-H-blank STAT mode
+ ldh a, [rLCDC]
+ and LCDC_ON
+ jr nz, .lcdEnabled
+ REPT PAL_COLORS
+ call TransferPalColorLCDDisabled
+ ENDR
+ jr .done
+.lcdEnabled
+ REPT PAL_COLORS
+ call TransferPalColorLCDEnabled
+ ENDR
+.done
+ pop de
+ ret
+
+BufferBGPPal::
+; Copy wCGBPal to palette a in wBGPPalsBuffer.
+ push de
+ add a
+ add a
+ add a
+ ld l, a
+ xor a
+ ld h, a
+ ld de, wBGPPalsBuffer
+ add hl, de
+ ld de, wCGBPal
+ ld c, PAL_SIZE
+.loop
ld a, [de]
- ldh [rBGPD], a
+ ld [hli], a
+ inc de
+ dec c
+ jr nz, .loop
+ pop de
+ ret
+
+TransferBGPPals::
+; Transfer the buffered BG palettes.
+ ldh a, [rLCDC]
+ and LCDC_ON
+ jr z, .lcdDisabled
+ di
+.waitLoop
+ ldh a, [rLY]
+ cp 144
+ jr c, .waitLoop
+.lcdDisabled
+ call .DoTransfer
+ ei
+ ret
+
+.DoTransfer:
+ xor a
+ or $80 ; auto-increment
+ ldh [rBGPI], a
+ ld de, rBGPD
+ ld hl, wBGPPalsBuffer
+ ld c, 4 * PAL_SIZE
+.loop
+ ld a, [hli]
+ ld [de], a
dec c
jr nz, .loop
ret
-EmptyFunc3:
+TransferCurOBPData:
+ push de
+ add a
+ add a
+ add a
+ or $80 ; auto-increment
+ ldh [rOBPI], a
+ ld de, rOBPD
+ ld hl, wCGBPal
+ ld b, %10 ; mask for non-V-blank/non-H-blank STAT mode
+ ldh a, [rLCDC]
+ and LCDC_ON
+ jr nz, .lcdEnabled
+ REPT PAL_COLORS
+ call TransferPalColorLCDDisabled
+ ENDR
+ jr .done
+.lcdEnabled
+ REPT PAL_COLORS
+ call TransferPalColorLCDEnabled
+ ENDR
+.done
+ pop de
+ ret
+
+TransferPalColorLCDEnabled:
+; Transfer a palette color while the LCD is enabled.
+
+; In case we're already in H-blank or V-blank, wait for it to end. This is a
+; precaution so that the transfer doesn't extend past the blanking period.
+ ldh a, [rSTAT]
+ and b
+ jr z, TransferPalColorLCDEnabled
+
+; Wait for H-blank or V-blank to begin.
+.notInBlankingPeriod
+ ldh a, [rSTAT]
+ and b
+ jr nz, .notInBlankingPeriod
+; fall through
+
+TransferPalColorLCDDisabled:
+; Transfer a palette color while the LCD is disabled.
+ ld a, [hli]
+ ld [de], a
+ ld a, [hli]
+ ld [de], a
ret
+_UpdateCGBPal_BGP_CheckDMG::
+ ldh a, [hOnCGB]
+ and a
+ ret z
+; fall through
+
+_UpdateCGBPal_BGP::
+ FOR index, NUM_ACTIVE_PALS
+ ld a, [wCGBBasePalPointers + index * 2]
+ ld e, a
+ ld a, [wCGBBasePalPointers + index * 2 + 1]
+ ld d, a
+ xor a ; CONVERT_BGP
+ call DMGPalToCGBPal
+ ld a, index
+ call BufferBGPPal
+ ENDR
+
+ call TransferBGPPals
+ ret
+
+_UpdateCGBPal_OBP::
+ FOR index, NUM_ACTIVE_PALS
+ ld a, [wCGBBasePalPointers + index * 2]
+ ld e, a
+ ld a, [wCGBBasePalPointers + index * 2 + 1]
+ ld d, a
+ ld a, c
+ call DMGPalToCGBPal
+ ld a, c
+ dec a
+ rlca
+ rlca
+
+ IF index > 0
+ IF index == 1
+ inc a
+ ELSE
+ add index
+ ENDC
+ ENDC
+
+ call TransferCurOBPData
+ ENDR
+
+ ret
+
+TranslatePalPacketToBGMapAttributes::
+; translate the SGB pal packets into something usable for the CGB
+ push hl
+ pop de
+ ld hl, PalPacketPointers
+ ld a, [hli]
+ ld c, a
+.loop
+ ld a, e
+.innerLoop
+ cp [hl]
+ jr z, .checkHighByte
+ inc hl
+ inc hl
+ dec c
+ jr nz, .innerLoop
+ ret
+.checkHighByte
+; the low byte of pointer matched, so check the high byte
+ inc hl
+ ld a, d
+ cp [hl]
+ jr z, .foundMatchingPointer
+ inc hl
+ dec c
+ jr nz, .loop
+ ret
+.foundMatchingPointer
+ farcall LoadBGMapAttributes
+ ret
+
+PalPacketPointers::
+ db (palPacketPointersEnd - palPacketPointers) / 2
+palPacketPointers:
+ dw BlkPacket_WholeScreen
+ dw BlkPacket_Battle
+ dw BlkPacket_StatusScreen
+ dw BlkPacket_Pokedex
+ dw BlkPacket_Slots
+ dw BlkPacket_Titlescreen
+ dw BlkPacket_NidorinoIntro
+ dw wPartyMenuBlkPacket
+ dw wTrainerCardBlkPacket
+ dw BlkPacket_GameFreakIntro
+ dw wPalPacket
+ dw UnknownPacket_72751
+palPacketPointersEnd:
+
CopySGBBorderTiles:
; SGB tile data is stored in a 4BPP planar format.
; Each tile is 32 bytes. The first 16 bytes contain bit planes 1 and 2, while
diff --git a/engine/gfx/screen_effects.asm b/engine/gfx/screen_effects.asm
index 7d0ccf7e..ece0a950 100644
--- a/engine/gfx/screen_effects.asm
+++ b/engine/gfx/screen_effects.asm
@@ -1,14 +1,16 @@
-; b = new color for BG color 0 (usually white) for 4 frames
+; inverts the BGP for 4 (6 on CGB due to lag) frames
ChangeBGPalColor0_4Frames:
- call GetPredefRegisters
+ call GetPredefRegisters ; leftover of red/blue, has no use here
ldh a, [rBGP]
- or b
+ xor $ff
ldh [rBGP], a
+ call UpdateCGBPal_BGP
ld c, 4
call DelayFrames
ldh a, [rBGP]
- and %11111100
+ xor $ff
ldh [rBGP], a
+ call UpdateCGBPal_BGP
ret
PredefShakeScreenVertically:
diff --git a/engine/gfx/sprite_oam.asm b/engine/gfx/sprite_oam.asm
index 649ab01e..3b869394 100644
--- a/engine/gfx/sprite_oam.asm
+++ b/engine/gfx/sprite_oam.asm
@@ -1,6 +1,8 @@
PrepareOAMData::
; Determine OAM data for currently visible
; sprites and write it to wShadowOAM.
+; Yellow code has been changed to use registers more efficiently
+; as well as tweaking the code to show cgb palettes
ld a, [wUpdateSpritesEnabled]
dec a
@@ -18,9 +20,9 @@ PrepareOAMData::
.spriteLoop
ldh [hSpriteOffset2], a
- ld d, HIGH(wSpriteStateData1)
- ldh a, [hSpriteOffset2]
ld e, a
+ ld d, HIGH(wSpriteStateData1)
+
ld a, [de] ; [x#SPRITESTATEDATA1_PICTUREID]
and a
jp z, .nextSprite
@@ -40,16 +42,22 @@ PrepareOAMData::
jr c, .usefacing
; unchanging
- and $f
- add $10 ; skip to the second half of the table which doesn't account for facing direction
+ ld a, $0
jr .next
.usefacing
and $f
.next
+; read the entry from the table
+ ld c, a
+ ld b, 0
+ ld hl, SpriteFacingAndAnimationTable
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
ld l, a
-
; get sprite priority
push de
inc d
@@ -61,65 +69,46 @@ PrepareOAMData::
ldh [hSpritePriority], a ; temp store sprite priority
pop de
-; read the entry from the table
- ld h, 0
- ld bc, SpriteFacingAndAnimationTable
- add hl, hl
- add hl, hl
- add hl, bc
- ld a, [hli]
- ld c, a
- ld a, [hli]
- ld b, a
- ld a, [hli]
- ld h, [hl]
- ld l, a
call GetSpriteScreenXY
ldh a, [hOAMBufferOffset]
+ add [hl]
+ cp $a0
+ jr z, .hidden
+ jr nc, .asm_4a41
+.hidden
+ call Func_4a7b
+ ld [wSavedSpriteImageIndex], a
+ ldh a, [hOAMBufferOffset]
+
ld e, a
ld d, HIGH(wShadowOAM)
.tileLoop
+ ld a, [hli]
+ ld c, a
+.loop
ldh a, [hSpriteScreenY] ; temp for sprite Y position
add $10 ; Y=16 is top of screen (Y=0 is invisible)
add [hl] ; add Y offset from table
ld [de], a ; write new sprite OAM Y position
inc hl
+ inc e
ldh a, [hSpriteScreenX] ; temp for sprite X position
add $8 ; X=8 is left of screen (X=0 is invisible)
add [hl] ; add X offset from table
+ ld [de], a
+ inc hl
inc e
- ld [de], a ; write new sprite OAM X position
- inc e
- ld a, [bc] ; read pattern number offset (accommodates orientation (offset 0,4 or 8) and animation (offset 0 or $80))
- inc bc
- push bc
- ld b, a
-
ld a, [wSavedSpriteImageIndex]
- swap a ; high nybble determines sprite used (0 is always player sprite, next are some npcs)
- and $f
-
- ; Sprites $a and $b have one face (and therefore 4 tiles instead of 12).
- ; As a result, sprite $b's tile offset is less than normal.
- cp $b
- jr nz, .notFourTileSprite
- ld a, $a * 12 + 4
- jr .next2
-
-.notFourTileSprite
- ; a *= 12
- sla a
- sla a
- ld c, a
- sla a
- add c
-
-.next2
- add b ; add the tile offset from the table (based on frame and facing direction)
- pop bc
+ add [hl]
+ cp $80
+ jr c, .asm_4a1c
+ ld b, a
+ ldh a, [hPikachuSpriteVRAMOffset]
+ add b
+.asm_4a1c
ld [de], a ; tile id
inc hl
inc e
@@ -129,15 +118,19 @@ PrepareOAMData::
ldh a, [hSpritePriority]
or [hl]
.skipPriority
- inc hl
+ and $f0
+ bit B_OAM_PAL1, a
+ jr z, .spriteusesOBP0
+ or OAM_HIGH_PALS
+.spriteusesOBP0
ld [de], a
+ inc hl
inc e
- bit BIT_END_OF_OAM_DATA, a
- jr z, .tileLoop
+ dec c
+ jr nz, .loop
ld a, e
ldh [hOAMBufferOffset], a
-
.nextSprite
ldh a, [hSpriteOffset2]
add $10
@@ -145,26 +138,31 @@ PrepareOAMData::
jp nz, .spriteLoop
; Clear unused OAM.
- ldh a, [hOAMBufferOffset]
- ld l, a
- ld h, HIGH(wShadowOAM)
- ld de, OBJ_SIZE
- ld b, SCREEN_HEIGHT_PX + OAM_Y_OFS
+.asm_4a41
ld a, [wMovementFlags]
bit BIT_LEDGE_OR_FISHING, a
- ld a, LOW(wShadowOAMEnd)
+ ld c, LOW(wShadowOAMEnd)
jr z, .clear
; Don't clear the last 4 entries because they are used for the shadow in the
; jumping down ledge animation and the rod in the fishing animation.
- ld a, LOW(wShadowOAMSprite36)
+ ld c, LOW(wShadowOAMSprite36)
.clear
- cp l
- ret z
+ ldh a, [hOAMBufferOffset]
+ cp c
+ ret nc
+ ld l, a
+ ld h, HIGH(wShadowOAM)
+ ld a, c
+ ld de, $4 ; entry size
+ ld b, $a0
+.clearLoop
ld [hl], b
add hl, de
- jr .clear
+ cp l
+ jr nz, .clearLoop
+ ret
GetSpriteScreenXY:
inc e
@@ -187,3 +185,48 @@ GetSpriteScreenXY:
and $f0
ld [de], a ; [x#SPRITESTATEDATA1_XADJUSTED]
ret
+
+Func_4a7b:
+ push bc
+ ld a, [wSavedSpriteImageIndex]
+ swap a ; high nybble determines sprite used (0 is always player sprite, next are some npcs)
+ and $f
+
+ ; Sprites $a and $b have one face (and therefore 4 tiles instead of 12).
+ ; As a result, sprite $b's tile offset is less than normal.
+ cp $b
+ jr nz, .notFourTileSprite
+ ld a, $a * 12 + 4 ; $7c
+ jr .done
+
+.notFourTileSprite
+ ; a *= 12
+ add a
+ add a
+ ld c, a
+ add a
+ add c
+.done
+ pop bc
+ ret
+
+INCLUDE "engine/gfx/oam_dma.asm"
+
+_IsTilePassable::
+ ld hl, wTilesetCollisionPtr ; pointer to list of passable tiles
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a ; hl now points to passable tiles
+.loop
+ ld a, [hli]
+ cp $ff
+ jr z, .tileNotPassable
+ cp c
+ jr nz, .loop
+ xor a
+ ret
+.tileNotPassable
+ scf
+ ret
+
+INCLUDE "data/tilesets/collision_tile_ids.asm"
diff --git a/engine/items/inventory.asm b/engine/items/inventory.asm
index 84950a4e..caa9dd22 100644
--- a/engine/items/inventory.asm
+++ b/engine/items/inventory.asm
@@ -34,6 +34,7 @@ AddItemToInventory_::
cp b ; does the current item in the table match the item being added?
jp z, .increaseItemQuantity ; if so, increase the item's quantity
inc hl
+.addAnotherStackOfItem
ld a, [hl]
cp $ff ; is it the end of the table?
jr nz, .notAtEndOfInventory
@@ -73,7 +74,7 @@ AddItemToInventory_::
; if so, store 99 in the current slot and store the rest in a new slot
ld a, 99
ld [hli], a
- jp .notAtEndOfInventory
+ jp .addAnotherStackOfItem
.increaseItemQuantityFailed
pop hl
and a
@@ -101,7 +102,7 @@ RemoveItemFromInventory_::
push hl
inc hl
ld a, [wWhichPokemon] ; index (within the inventory) of the item being removed
- sla a
+ add a
add l
ld l, a
jr nc, .noCarry
diff --git a/engine/items/item_effects.asm b/engine/items/item_effects.asm
index c4ce13de..0cbb0c48 100644
--- a/engine/items/item_effects.asm
+++ b/engine/items/item_effects.asm
@@ -114,7 +114,9 @@ ItemUseBall:
; If this is for the old man battle, skip checking if the party & box are full.
ld a, [wBattleType]
- dec a
+ cp BATTLE_TYPE_OLD_MAN
+ jr z, .canUseBall
+ cp BATTLE_TYPE_PIKACHU
jr z, .canUseBall
ld a, [wPartyCount] ; is party full?
@@ -153,16 +155,26 @@ ItemUseBall:
jp z, .setAnimData
ld a, [wBattleType]
- dec a
- jr nz, .notOldManBattle
+ cp BATTLE_TYPE_OLD_MAN
+ jr z, .oldManBattle
+ cp BATTLE_TYPE_PIKACHU
+ jr z, .oldManBattle ; pikachu battle technically old man battle
+ jr .notOldManBattle
-; Old Man battle
+.oldManBattle
ld hl, wGrassRate
ld de, wPlayerName
ld bc, NAME_LENGTH
call CopyData ; save the player's name in the Wild Monster data (part of the Cinnabar Island Missingno. glitch)
+ ld a, [wBattleType]
+ cp BATTLE_TYPE_OLD_MAN
+ jp nz, .captured
+ ld a, $1
+ ld [wCapturedMonSpecies], a
+ CheckEvent EVENT_INITIAL_CATCH_TRAINING
+ ld b, $63
+ jp nz, .setAnimData
jp .captured
-
.notOldManBattle
; If the player is fighting the ghost Marowak, set the value that indicates the
; Pokémon can't be caught and skip the capture calculations.
@@ -281,6 +293,7 @@ ItemUseBall:
inc a
.skip2
+
; Let W = ((MaxHP * 255) / BallFactor) / max(HP / 4, 1). Calculate W.
ldh [hDivisor], a
ld b, 4
@@ -348,6 +361,7 @@ ItemUseBall:
jr z, .skip4
.skip4
+
; Let Y = (CatchRate * 100) / BallFactor2. Calculate Y.
ld a, b
ldh [hDivisor], a
@@ -512,9 +526,10 @@ ItemUseBall:
ld [wCurPartySpecies], a
ld [wPokedexNum], a
ld a, [wBattleType]
- dec a ; is this the old man battle?
- jr z, .oldManCaughtMon ; if so, don't give the player the caught Pokémon
-
+ cp BATTLE_TYPE_OLD_MAN ; is this the old man battle?
+ jp z, .oldManCaughtMon ; if so, don't give the player the caught Pokémon
+ cp BATTLE_TYPE_PIKACHU
+ jr z, .oldManCaughtMon ; same with Pikachu battle
ld hl, ItemUseBallText05
call PrintText
@@ -546,12 +561,18 @@ ItemUseBall:
predef ShowPokedexData
.skipShowingPokedexData
+ ld a, $1
+ ld [wd49b], a
+ ld a, $85
+ ld [wPikachuMood], a
ld a, [wPartyCount]
cp PARTY_LENGTH ; is party full?
jr z, .sendToBox
xor a ; PLAYER_PARTY_DATA
ld [wMonDataLocation], a
call ClearSprites
+ ld hl, .emptyString
+ call PrintText
call AddPartyMon
jr .done
@@ -584,6 +605,9 @@ ItemUseBall:
ld [wItemQuantity], a
jp RemoveItemFromInventory
+.emptyString
+ db "@"
+
ItemUseBallText00:
;"It dodged the thrown ball!"
;"This pokemon can't be caught"
@@ -649,21 +673,28 @@ ItemUseBicycle:
call ItemUseReloadOverworldData
xor a
ld [wWalkBikeSurfState], a ; change player state to walking
+ ld a, $00
+ ld [wPikachuSpawnState], a
call PlayDefaultMusic ; play walking music
ld hl, GotOffBicycleText
- jr .printText
+ jp PrintText
+
.tryToGetOnBike
call IsBikeRidingAllowed
jp nc, NoCyclingAllowedHere
call ItemUseReloadOverworldData
xor a ; no keys pressed
ldh [hJoyHeld], a ; current joypad state
- inc a
+ ld a, $1
ld [wWalkBikeSurfState], a ; change player state to bicycling
- ld hl, GotOnBicycleText
call PlayDefaultMusic ; play bike riding music
-.printText
- jp PrintText
+ xor a
+ ld [wWalkBikeSurfState], a
+ ld hl, GotOnBicycleText
+ call PrintText
+ ld a, $1
+ ld [wWalkBikeSurfState], a
+ ret
; indirectly used by SURF in StartMenu_Pokemon.surf
ItemUseSurfboard:
@@ -673,7 +704,7 @@ ItemUseSurfboard:
jr z, .tryToStopSurfing
; try to Surf
call IsNextTileShoreOrWater
- jp c, SurfingAttemptFailed
+ jp nc, SurfingAttemptFailed
ld hl, TilePairCollisionsWater
call CheckForTilePairCollisions
jp c, SurfingAttemptFailed
@@ -686,6 +717,7 @@ ItemUseSurfboard:
call PlayDefaultMusic ; play surfing music
ld hl, SurfingGotOnText
jp PrintText
+
.tryToStopSurfing
xor a
ldh [hSpriteIndex], a
@@ -698,23 +730,20 @@ ItemUseSurfboard:
ld hl, TilePairCollisionsWater
call CheckForTilePairCollisions
jr c, .cannotStopSurfing
- ld hl, wTilesetCollisionPtr ; pointer to list of passable tiles
- ld a, [hli]
- ld h, [hl]
- ld l, a ; hl now points to passable tiles
- ld a, [wTileInFrontOfPlayer] ; tile in front of the player
- ld b, a
-.passableTileLoop
- ld a, [hli]
- cp b
- jr z, .stopSurfing
- cp $ff
- jr nz, .passableTileLoop
+ ld a, [wTileInFrontOfPlayer]
+ ld c, a
+ call IsTilePassable
+ jr nc, .stopSurfing
.cannotStopSurfing
ld hl, SurfingNoPlaceToGetOffText
jp PrintText
+
.stopSurfing
call .makePlayerMoveForward
+ ld a, $3
+ ld [wPikachuSpawnState], a
+ ld hl, wPikachuOverworldStateFlags
+ set 5, [hl]
ld hl, wStatusFlags5
set BIT_SCRIPTED_MOVEMENT_STATE, [hl]
xor a
@@ -722,7 +751,9 @@ ItemUseSurfboard:
dec a
ld [wJoyIgnore], a
call PlayDefaultMusic ; play walking music
+ call GBPalWhiteOutWithDelay3
jp LoadWalkingPlayerSpriteGraphics
+
; uses a simulated button press to make the player move forward
.makePlayerMoveForward
ld a, [wPlayerDirection] ; direction the player is going
@@ -770,25 +801,43 @@ ItemUseEvoStone:
ld a, $ff
ld [wUpdateSpritesEnabled], a
call DisplayPartyMenu
+ ld a, [wCurPartySpecies]
+ ld [wLoadedMon], a
pop bc
jr c, .canceledItemUse
ld a, b
ld [wCurPartySpecies], a
- ld a, TRUE
- ld [wForceEvolution], a
+ call Func_d85d
+ jr nc, .noEffect
+ callfar IsThisPartyMonStarterPikachu
+ jr nc, .notPlayerPikachu
+ ldpikacry e, PikachuCry28
+ callfar PlayPikachuSoundClip
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMonNicks
+ call GetPartyMonName
+ ld hl, RefusingText
+ call PrintText
+ ld a, $4
+ ld [wd49b], a
+ ld a, $82
+ ld [wPikachuMood], a
+ jr .canceledItemUse
+
+.notPlayerPikachu
ld a, SFX_HEAL_AILMENT
call PlaySoundWaitForCurrent
call WaitForSoundToFinish
+ ld a, TRUE
+ ld [wForceEvolution], a
callfar TryEvolvingMon ; try to evolve pokemon
- ld a, [wEvolutionOccurred]
- and a
- jr z, .noEffect
pop af
ld [wWhichPokemon], a
ld hl, wNumBagItems
ld a, 1 ; remove 1 stone
ld [wItemQuantity], a
jp RemoveItemFromInventory
+
.noEffect
call ItemUseNoEffect
.canceledItemUse
@@ -797,6 +846,55 @@ ItemUseEvoStone:
pop af
ret
+Func_d85d:
+ ld hl, EvosMovesPointerTable
+ ld a, [wLoadedMon]
+ dec a
+ ld c, a
+ ld b, $0
+ add hl, bc
+ add hl, bc
+ ld de, wEvoDataBuffer
+ ld a, BANK(TryEvolvingMon)
+ ld bc, $2
+ call FarCopyData
+ ld hl, wEvoDataBuffer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wEvoDataBuffer
+ ld a, BANK(TryEvolvingMon)
+ ld bc, 13
+ call FarCopyData
+ ld hl, wEvoDataBuffer
+.loop
+ ld a, [hli]
+ and a
+ jr z, .cannotEvolveWithUsedStone
+ inc hl
+ inc hl
+ cp EVOLVE_ITEM
+ jr nz, .loop
+ dec hl
+ dec hl
+ ld b, [hl]
+ ld a, [wCurItem]
+ inc hl
+ inc hl
+ inc hl
+ cp b
+ jr nz, .loop
+ scf
+ ret
+
+.cannotEvolveWithUsedStone
+ and a
+ ret
+
+RefusingText:
+ text_far _RefusingText
+ text_end
+
ItemUseVitamin:
ld a, [wIsInBattle]
and a
@@ -805,7 +903,7 @@ ItemUseVitamin:
ItemUseMedicine:
ld a, [wPartyCount]
and a
- jp z, .emptyParty
+ jp z, Func_e4bf
ld a, [wWhichPokemon]
push af
ld a, [wCurItem]
@@ -820,15 +918,6 @@ ItemUseMedicine:
; if using softboiled
call GoBackToPartyMenu
jr .getPartyMonDataAddress
-.emptyParty
- ld hl, .emptyPartyText
- xor a
- ld [wActionResultOrTookBattleTurn], a ; item use failed
- jp PrintText
-.emptyPartyText
- text "You don't have"
- line "any #MON!"
- prompt
.notUsingSoftboiled
call DisplayPartyMenu
.getPartyMonDataAddress
@@ -844,6 +933,16 @@ ItemUseMedicine:
ld e, a
ld [wCurSpecies], a
pop af
+ push af
+ cp CALCIUM + 1
+ jr nc, .noHappinessBoost
+ push hl
+ push de
+ farcall_ModifyPikachuHappiness PIKAHAPPY_USEDITEM
+ pop de
+ pop hl
+.noHappinessBoost
+ pop af
ld [wCurItem], a
pop af
ld [wWhichPokemon], a
@@ -911,6 +1010,7 @@ ItemUseMedicine:
call CopyData ; copy party stats to in-battle stat data
predef DoubleOrHalveSelectedStats
jp .doneHealing
+
.healHP
inc hl ; hl = address of current HP
ld a, [hli]
@@ -928,7 +1028,22 @@ ItemUseMedicine:
cp MAX_REVIVE
jr z, .updateInBattleFaintedData
jp .healingItemNoEffect
+
.updateInBattleFaintedData
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wUsedItemOnWhichPokemon]
+ ld [wWhichPokemon], a
+ push hl
+ push de
+ push bc
+ callfar RespawnOverworldPikachu
+ pop bc
+ pop de
+ pop hl
+ pop af
+ ld [wWhichPokemon], a
+
ld a, [wIsInBattle]
and a
jr z, .compareCurrentHPToMaxHP
@@ -953,6 +1068,7 @@ ItemUseMedicine:
pop de
pop hl
jr .compareCurrentHPToMaxHP
+
.notFainted
ld a, [wCurItem]
cp REVIVE
@@ -988,6 +1104,7 @@ ItemUseMedicine:
dec hl
dec hl
jp .cureStatusAilment
+
.notFullHP ; if the pokemon's current HP doesn't equal its max HP
xor a
ld [wLowHealthAlarm], a ;disable low health alarm
@@ -1072,6 +1189,7 @@ ItemUseMedicine:
pop af
ld [hl], a
jr .addHealAmount
+
.notUsingSoftboiled2
ld a, [wCurItem]
cp SODA_POP
@@ -1126,6 +1244,7 @@ ItemUseMedicine:
cp MAX_REVIVE
jr z, .setCurrentHPToMaxHp ; if using a Max Revive
jr .updateInBattleData
+
.setCurrentHPToHalfMaxHP
dec hl
dec de
@@ -1140,6 +1259,7 @@ ItemUseMedicine:
ld [wHPBarNewHP], a
dec de
jr .doneHealingPartyHP
+
.setCurrentHPToMaxHp
ld a, [hli]
ld [de], a
@@ -1183,9 +1303,11 @@ ItemUseMedicine:
dec d
jr nz, .calculateHPBarCoordsLoop
jr .doneHealing
+
.healingItemNoEffect
call ItemUseNoEffect
jp .done
+
.doneHealing
ld a, [wPseudoItemID]
and a ; using Softboiled?
@@ -1220,6 +1342,7 @@ ItemUseMedicine:
ld a, POTION_MSG
ld [wPartyMenuTypeOrMessageID], a
jr .showHealingItemMessage
+
.playStatusAilmentCuringSound
ld a, SFX_HEAL_AILMENT
call PlaySoundWaitForCurrent
@@ -1236,6 +1359,7 @@ ItemUseMedicine:
call DelayFrames
call WaitForTextScrollButtonPress
jr .done
+
.canceledItemUse
xor a
ld [wActionResultOrTookBattleTurn], a ; item use failed
@@ -1251,6 +1375,7 @@ ItemUseMedicine:
and a
ret nz
jp ReloadMapData
+
.useVitamin
push hl
ld a, [hl]
@@ -1306,6 +1431,7 @@ ItemUseMedicine:
cp b
jr nz, .statNameInnerLoop
jr .statNameLoop
+
.gotStatName
ld de, wStringBuffer
ld bc, STAT_NAME_LENGTH
@@ -1315,11 +1441,13 @@ ItemUseMedicine:
ld hl, VitaminStatRoseText
call PrintText
jp RemoveUsedItem
+
.vitaminNoEffect
pop hl
ld hl, VitaminNoEffectText
call PrintText
jp GBPalWhiteOut
+
.recalculateStats
ld bc, MON_STATS
add hl, bc
@@ -1406,8 +1534,18 @@ ItemUseMedicine:
xor a ; PLAYER_PARTY_DATA
ld [wMonDataLocation], a
predef LearnMoveFromLevelUp
+
xor a
ld [wForceEvolution], a
+ farcall_ModifyPikachuHappiness PIKAHAPPY_LEVELUP
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wUsedItemOnWhichPokemon]
+ ld [wWhichPokemon], a
+ callfar RespawnOverworldPikachu
+ pop af
+ ld [wWhichPokemon], a
+
callfar TryEvolvingMon
ld a, $01
ld [wUpdateSpritesEnabled], a
@@ -1496,6 +1634,10 @@ ItemUseEscapeRope:
ld a, [wCurMap]
cp AGATHAS_ROOM
jr z, .notUsable
+ cp BILLS_HOUSE
+ jr z, .notUsable
+ cp POKEMON_FAN_CLUB
+ jr z, .notUsable
ld a, [wCurMapTileset]
ld b, a
ld hl, EscapeRopeTilesets
@@ -1508,6 +1650,7 @@ ItemUseEscapeRope:
ld hl, wStatusFlags6
set BIT_FLY_WARP, [hl]
set BIT_ESCAPE_WARP, [hl]
+ call Func_1510
ld hl, wStatusFlags4
res BIT_NO_BATTLES, [hl]
ResetEvent EVENT_IN_SAFARI_ZONE
@@ -1524,6 +1667,7 @@ ItemUseEscapeRope:
ld c, 30
call DelayFrames
jp RemoveUsedItem
+
.notUsable
jp ItemUseNotTime
@@ -1547,6 +1691,7 @@ ItemUseXAccuracy:
jp z, ItemUseNotTime
ld hl, wPlayerBattleStatus2
set USING_X_ACCURACY, [hl] ; X Accuracy bit
+ farcall_ModifyPikachuHappiness PIKAHAPPY_USEDXITEM
jp PrintItemUseTextAndRemoveItem
; This function is bugged and never works. It always jumps to ItemUseNotTime.
@@ -1560,11 +1705,13 @@ ItemUseCardKey:
jr nz, .next0
ld hl, CardKeyTable1
jr .next1
+
.next0
cp $24
jr nz, .next2
ld hl, CardKeyTable2
jr .next1
+
.next2
cp $5e
jp nz, ItemUseNotTime
@@ -1587,6 +1734,7 @@ ItemUseCardKey:
ld a, [hl]
ld [wUnusedCardKeyGateID], a
jr .done
+
.nextEntry1
inc hl
.nextEntry2
@@ -1594,6 +1742,7 @@ ItemUseCardKey:
.nextEntry3
inc hl
jr .loop
+
.done
ld hl, ItemUseText00
call PrintText
@@ -1615,6 +1764,15 @@ ItemUseGuardSpec:
ld a, [wIsInBattle]
and a
jp z, ItemUseNotTime
+
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wPlayerMonNumber]
+ ld [wWhichPokemon], a
+ farcall_ModifyPikachuHappiness PIKAHAPPY_USEDXITEM
+ pop af
+ ld [wWhichPokemon], a
+
ld hl, wPlayerBattleStatus2
set PROTECTED_BY_MIST, [hl] ; Mist bit
jp PrintItemUseTextAndRemoveItem
@@ -1631,6 +1789,15 @@ ItemUseDireHit:
ld a, [wIsInBattle]
and a
jp z, ItemUseNotTime
+
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wPlayerMonNumber]
+ ld [wWhichPokemon], a
+ farcall_ModifyPikachuHappiness PIKAHAPPY_USEDXITEM
+ pop af
+ ld [wWhichPokemon], a
+
ld hl, wPlayerBattleStatus2
set GETTING_PUMPED, [hl] ; Focus Energy bit
jp PrintItemUseTextAndRemoveItem
@@ -1643,6 +1810,7 @@ ItemUseXStat:
ld a, 2
ld [wActionResultOrTookBattleTurn], a ; item not used
ret
+
.inBattle
ld hl, wPlayerMoveNum
ld a, [hli]
@@ -1661,6 +1829,15 @@ ItemUseXStat:
xor a
ldh [hWhoseTurn], a ; set turn to player's turn
farcall StatModifierUpEffect ; do stat increase move
+
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wPlayerMonNumber]
+ ld [wWhichPokemon], a
+ farcall_ModifyPikachuHappiness PIKAHAPPY_USEDXITEM
+ pop af
+ ld [wWhichPokemon], a
+
pop hl
pop af
ld [hld], a ; restore [wPlayerMoveEffect]
@@ -1678,31 +1855,48 @@ ItemUsePokeFlute:
cp ROUTE_12
jr nz, .notRoute12
CheckEvent EVENT_BEAT_ROUTE12_SNORLAX
- jr nz, .noSnorlaxToWakeUp
+ jr nz, .noSnorlaxOrPikachuToWakeUp
; if the player hasn't beaten Route 12 Snorlax
ld hl, Route12SnorlaxFluteCoords
call ArePlayerCoordsInArray
- jr nc, .noSnorlaxToWakeUp
+ jr nc, .noSnorlaxOrPikachuToWakeUp
ld hl, PlayedFluteHadEffectText
call PrintText
SetEvent EVENT_FIGHT_ROUTE12_SNORLAX
ret
+
.notRoute12
cp ROUTE_16
- jr nz, .noSnorlaxToWakeUp
+ jr nz, .notRoute16
CheckEvent EVENT_BEAT_ROUTE16_SNORLAX
- jr nz, .noSnorlaxToWakeUp
+ jr nz, .noSnorlaxOrPikachuToWakeUp
; if the player hasn't beaten Route 16 Snorlax
ld hl, Route16SnorlaxFluteCoords
call ArePlayerCoordsInArray
- jr nc, .noSnorlaxToWakeUp
+ jr nc, .noSnorlaxOrPikachuToWakeUp
ld hl, PlayedFluteHadEffectText
call PrintText
SetEvent EVENT_FIGHT_ROUTE16_SNORLAX
ret
-.noSnorlaxToWakeUp
+
+.notRoute16
+ cp PEWTER_POKECENTER
+ jr nz, .noSnorlaxOrPikachuToWakeUp
+ call CheckPikachuFollowingPlayer
+ jr z, .noSnorlaxOrPikachuToWakeUp
+ callfar IsPikachuRightNextToPlayer
+ jr nc, .noSnorlaxOrPikachuToWakeUp
+ ld hl, PlayedFluteHadEffectText
+ call PrintText
+ call ItemUseReloadOverworldData
+ ldpikaemotion e, PikachuEmotion26
+ callfar PlaySpecificPikachuEmotion
+ ret
+
+.noSnorlaxOrPikachuToWakeUp
ld hl, PlayedFluteNoEffectText
jp PrintText
+
.inBattle
xor a
ld [wWereAnyMonsAsleep], a
@@ -1722,8 +1916,15 @@ ItemUsePokeFlute:
ld [hl], a
ld hl, wEnemyMonStatus
ld a, [hl]
+ ld c, a
and b ; remove Sleep status
ld [hl], a
+ ld a, c
+ and SLP_MASK
+ jr z, .asm_e063
+ ld a, $1
+ ld [wWereAnyMonsAsleep], a
+.asm_e063
call LoadScreenTilesFromBuffer2 ; restore saved screen
ld a, [wWereAnyMonsAsleep]
and a ; were any pokemon asleep before playing the flute?
@@ -1799,8 +2000,7 @@ PlayedFluteHadEffectText:
and a
jr nz, .done
; play out-of-battle pokeflute music
- ld a, SFX_STOP_ALL_MUSIC
- call PlaySound
+ call StopAllMusic
ld a, SFX_POKEFLUTE
ld c, BANK(SFX_Pokeflute)
call PlayMusic
@@ -1861,13 +2061,28 @@ INCLUDE "data/wild/good_rod.asm"
ItemUseSuperRod:
call FishingInit
jp c, ItemUseNotTime
- call ReadSuperRodData
- ld a, e
+ callfar ReadSuperRodData
+ ld c, e
+ ld b, d
+ ld a, $2
+ ld [wRodResponse], a
+ ld a, c
+ and a ; are there fish in the map?
+ jr z, DoNotGenerateFishingEncounter ; if not, do not generate an encounter
+ ld a, $1
+ ld [wRodResponse], a
+ call Random
+ and $1
+ jr nz, RodResponse
+ xor a
+ ld [wRodResponse], a
+ jr DoNotGenerateFishingEncounter
+
RodResponse:
ld [wRodResponse], a
dec a ; is there a bite?
- jr nz, .next
+ jr nz, DoNotGenerateFishingEncounter
; if yes, store level and species data
ld a, 1
ld [wMoveMissed], a
@@ -1876,7 +2091,7 @@ RodResponse:
ld a, c ; species
ld [wCurOpponent], a
-.next
+DoNotGenerateFishingEncounter:
ld hl, wWalkBikeSurfState
ld a, [hl] ; store the value in a
push af
@@ -1896,22 +2111,28 @@ FishingInit:
jr z, .notInBattle
scf ; can't fish during battle
ret
+
.notInBattle
call IsNextTileShoreOrWater
- ret c
+ jr nc, .cannotFish
ld a, [wWalkBikeSurfState]
cp 2 ; Surfing?
- jr z, .surfing
+ jr z, .cannotFish
call ItemUseReloadOverworldData
ld hl, ItemUseText00
call PrintText
ld a, SFX_HEAL_AILMENT
call PlaySound
+ ld a, $2
+ ld [wd49b], a
+ ld a, $81
+ ld [wPikachuMood], a
ld c, 80
call DelayFrames
and a
ret
-.surfing
+
+.cannotFish
scf ; can't fish when surfing
ret
@@ -1964,7 +2185,23 @@ ItemUsePPRestore:
call DisplayPartyMenu
jr nc, .chooseMove
jp .itemNotUsed
+
.chooseMove
+ ld a, [wIsInBattle]
+ and a
+ jr z, .usePPItem
+ ld a, [wWhichPokemon]
+ ld b, a
+ ld a, [wPlayerMonNumber]
+ cp b
+ jr nz, .usePPItem
+ ld a, [wPlayerBattleStatus3]
+ bit TRANSFORMED, a
+ jr z, .usePPItem
+ call ItemUseNotTime
+ jp .itemNotUsed
+
+.usePPItem
ld a, [wPPRestoreItem]
cp ELIXER
jp nc, .useElixir ; if Elixir or Max Elixir
@@ -2004,6 +2241,7 @@ ItemUsePPRestore:
ld hl, PPMaxedOutText
call PrintText
jr .chooseMove
+
.PPNotMaxedOut
ld a, [hl]
add 1 << 6 ; increase PP Up count by 1
@@ -2011,6 +2249,8 @@ ItemUsePPRestore:
ld a, 1 ; 1 PP Up used
ld [wUsingPPUp], a
call RestoreBonusPP ; add the bonus PP to current PP
+ ld a, SFX_HEAL_AILMENT
+ call PlaySound
ld hl, PPIncreasedText
call PrintText
.done
@@ -2019,6 +2259,7 @@ ItemUsePPRestore:
call GBPalWhiteOut
call RunDefaultPaletteCommand
jp RemoveUsedItem
+
.afterRestoringPP ; after using a (Max) Ether/Elixir
ld a, [wWhichPokemon]
ld b, a
@@ -2037,10 +2278,12 @@ ItemUsePPRestore:
ld hl, PPRestoredText
call PrintText
jr .done
+
.useEther
call .restorePP
jr nz, .afterRestoringPP
jp .noEffect
+
; unsets zero flag if PP was restored, sets zero flag if not
; however, this is bugged for Max Ethers and Max Elixirs (see below)
.restorePP
@@ -2075,6 +2318,7 @@ ItemUsePPRestore:
add b
ld [hl], a
ret
+
.fullyRestorePP
ld a, [hl] ; move PP
; Bug: This code doesn't mask out the upper two bits, which are used to count
@@ -2084,6 +2328,7 @@ ItemUsePPRestore:
cp b ; does current PP equal max PP?
ret z
jr .storeNewAmount
+
.useElixir
; decrement the item ID so that ELIXER becomes ETHER and MAX_ELIXER becomes MAX_ETHER
ld hl, wPPRestoreItem
@@ -2187,6 +2432,7 @@ ItemUseTMHM:
ld a, 2
ld [wActionResultOrTookBattleTurn], a ; item not used
ret
+
.useMachine
ld a, [wWhichPokemon]
push af
@@ -2232,10 +2478,13 @@ ItemUseTMHM:
ld hl, MonCannotLearnMachineMoveText
call PrintText
jr .chooseMon
+
.checkIfAlreadyLearnedMove
callfar CheckIfMoveIsKnown ; check if the pokemon already knows the move
jr c, .chooseMon
predef LearnMove ; teach move
+ ld a, [wWhichPokemon]
+ ld d, a
pop af
ld [wCurItem], a
pop af
@@ -2243,6 +2492,28 @@ ItemUseTMHM:
ld a, b
and a
ret z
+
+ ld a, [wWhichPokemon]
+ push af
+ ld a, d
+ ld [wWhichPokemon], a
+ farcall_ModifyPikachuHappiness PIKAHAPPY_USEDTMHM
+ callfar IsThisPartyMonStarterPikachu
+ jr nc, .notTeachingThunderboltOrThunderToPikachu
+ ld a, [wCurItem]
+ cp TM_THUNDERBOLT ; are we teaching thunderbolt to the player pikachu?
+ jr z, .teachingThunderboltOrThunderToPlayerPikachu
+ cp TM_THUNDER ; are we teaching thunder then?
+ jr nz, .notTeachingThunderboltOrThunderToPikachu
+.teachingThunderboltOrThunderToPlayerPikachu
+ ld a, $5
+ ld [wd49b], a
+ ld a, $85
+ ld [wPikachuMood], a
+.notTeachingThunderboltOrThunderToPikachu
+ pop af
+ ld [wWhichPokemon], a
+
ld a, [wCurItem]
call IsItemHM
ret c
@@ -2289,6 +2560,12 @@ ItemUseNotYoursToUse:
ld hl, ItemUseNotYoursToUseText
jr ItemUseFailed
+Func_e4bf:
+ ld a, $2
+ ld [wActionResultOrTookBattleTurn], a
+ ld hl, DontHavePokemonText
+ jp PrintText
+
ThrowBallAtTrainerMon:
call RunDefaultPaletteCommand
call LoadScreenTilesFromBuffer1 ; restore saved screen
@@ -2350,6 +2627,10 @@ BoxFullCannotThrowBallText:
text_far _BoxFullCannotThrowBallText
text_end
+DontHavePokemonText:
+ text_far _DontHavePokemonText
+ text_end
+
ItemUseText00:
text_far _ItemUseText001
text_low
@@ -2484,6 +2765,7 @@ GetMaxPP:
.sourceWithOneMon
call GetSelectedMoveOffset2
jr .next
+
.sourceWithMultipleMon
call GetSelectedMoveOffset
.next
@@ -2586,6 +2868,7 @@ TossItem_::
pop hl
and a
ret
+
.tooImportantToToss
push hl
ld hl, TooImportantToTossText
@@ -2821,83 +3104,39 @@ SendNewMonToBox:
ld [de], a
dec b
jr nz, .movePPLoop
+ ld a, [wCurPartySpecies]
+ cp KADABRA
+ jr nz, .notKadabra
+ ld a, TWISTEDSPOON_GSC
+ ld [wBoxMon1CatchRate], a
+.notKadabra
ret
; checks if the tile in front of the player is a shore or water tile
; used for surfing and fishing
; unsets carry if it is, sets carry if not
-IsNextTileShoreOrWater:
+IsNextTileShoreOrWater::
ld a, [wCurMapTileset]
ld hl, WaterTilesets
ld de, 1
- call IsInArray
- jr nc, .notShoreOrWater
+ call IsInArray ; does the current map allow surfing?
+ ret nc ; if not, return
+ ld hl, WaterTile
ld a, [wCurMapTileset]
cp SHIP_PORT ; Vermilion Dock tileset
- ld a, [wTileInFrontOfPlayer] ; tile in front of player
jr z, .skipShoreTiles ; if it's the Vermilion Dock tileset
- cp $48 ; eastern shore tile in Safari Zone
- jr z, .shoreOrWater
- cp $32 ; usual eastern shore tile
- jr z, .shoreOrWater
+ cp GYM ; eastern shore tile in Safari Zone
+ jr z, .skipShoreTiles
+ cp DOJO ; usual eastern shore tile
+ jr z, .skipShoreTiles
+ ld hl, ShoreTiles
.skipShoreTiles
- cp $14 ; water tile
- jr z, .shoreOrWater
-.notShoreOrWater
- scf
- ret
-.shoreOrWater
- and a
- ret
-
-INCLUDE "data/tilesets/water_tilesets.asm"
-
-ReadSuperRodData:
-; return e = 2 if no fish on this map
-; return e = 1 if a bite, bc = level,species
-; return e = 0 if no bite
- ld a, [wCurMap]
- ld de, 3 ; each fishing group is three bytes wide
- ld hl, SuperRodData
+ ld a, [wTileInFrontOfPlayer]
+ ld de, $1
call IsInArray
- jr c, .ReadFishingGroup
- ld e, $2 ; $2 if no fishing groups found
ret
-.ReadFishingGroup
-; hl points to the fishing group entry in the index
- inc hl ; skip map id
-
- ; read fishing group address
- ld a, [hli]
- ld h, [hl]
- ld l, a
-
- ld b, [hl] ; how many mons in group
- inc hl ; point to data
- ld e, $0 ; no bite yet
-
-.RandomLoop
- call Random
- srl a
- ret c ; 50% chance of no battle
-
- and %11 ; 2-bit random number
- cp b
- jr nc, .RandomLoop ; if a is greater than the number of mons, regenerate
-
- ; get the mon
- add a
- ld c, a
- ld b, $0
- add hl, bc
- ld b, [hl] ; level
- inc hl
- ld c, [hl] ; species
- ld e, $1 ; $1 if there's a bite
- ret
-
-INCLUDE "data/wild/super_rod.asm"
+INCLUDE "data/tilesets/water_tilesets.asm"
; reloads map view and processes sprite data
; for items that cause the overworld to be displayed
diff --git a/engine/items/super_rod.asm b/engine/items/super_rod.asm
new file mode 100644
index 00000000..db82f5fb
--- /dev/null
+++ b/engine/items/super_rod.asm
@@ -0,0 +1,41 @@
+ReadSuperRodData:
+ ld a, [wCurMap]
+ ld c, a
+ ld hl, SuperRodFishingSlots
+.loop
+ ld a, [hli]
+ cp $ff
+ jr z, .notfound
+ cp c
+ jr z, .found
+ ld de, $8
+ add hl, de
+ jr .loop
+.found
+ call GenerateRandomFishingEncounter
+ ret
+.notfound
+ ld de, $0
+ ret
+
+GenerateRandomFishingEncounter:
+ call Random
+ cp $66
+ jr c, .asm_f5ed6
+ inc hl
+ inc hl
+ cp $b2
+ jr c, .asm_f5ed6
+ inc hl
+ inc hl
+ cp $e5
+ jr c, .asm_f5ed6
+ inc hl
+ inc hl
+.asm_f5ed6
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ret
+
+INCLUDE "data/wild/super_rod.asm"
diff --git a/engine/items/tms.asm b/engine/items/tms.asm
index 2da15fab..06d60ad3 100644
--- a/engine/items/tms.asm
+++ b/engine/items/tms.asm
@@ -11,6 +11,8 @@ CanLearnTM:
ld hl, TechnicalMachines
.findTMloop
ld a, [hli]
+ cp -1 ; reached terminator?
+ jr z, .done
cp b
jr z, .TMfoundLoop
inc c
@@ -19,6 +21,10 @@ CanLearnTM:
pop hl
ld b, FLAG_TEST
predef_jump FlagActionPredef
+.done
+ pop hl
+ ld c, 0
+ ret
; converts TM/HM number in [wTempTMHM] into move number
; HMs start at 51
diff --git a/engine/items/town_map.asm b/engine/items/town_map.asm
index 35acaa29..fe274579 100644
--- a/engine/items/town_map.asm
+++ b/engine/items/town_map.asm
@@ -107,6 +107,13 @@ DisplayTownMap:
ld [wWhichTownMapLocation], a
jp .townMapLoop
+Func_70f87: ; unreferenced
+ ldh a, [hJoy5]
+ and PAD_DOWN | PAD_UP
+ ret z
+ callfar PlayPikachuSoundClip
+ ret
+
INCLUDE "data/maps/town_map_order.asm"
TownMapCursor:
@@ -141,11 +148,14 @@ MonsNestText:
LoadTownMap_Fly::
call ClearSprites
call LoadTownMap
+ ld a, $1
+ ldh [hJoy7], a
call LoadPlayerSpriteGraphics
call LoadFontTilePatterns
ld de, BirdSprite
+ ld b, BANK(BirdSprite)
+ ld c, 12
ld hl, vSprites tile BIRD_BASE_TILE
- lb bc, BANK(BirdSprite), 12
call CopyVideoData
ld de, TownMapUpArrow
ld hl, vChars1 tile $6d
@@ -218,6 +228,7 @@ LoadTownMap_Fly::
.pressedB
xor a
ld [wTownMapSpriteBlinkingEnabled], a
+ ldh [hJoy7], a
call GBPalWhiteOutWithDelay3
pop hl
pop af
@@ -284,15 +295,14 @@ LoadTownMap:
call ClearScreen
call UpdateSprites
hlcoord 0, 0
- ld b, $12
- ld c, $12
+ lb bc, $12, $12
call TextBoxBorder
call DisableLCD
ld hl, WorldMapTileGraphics
ld de, vChars2 tile $60
ld bc, WorldMapTileGraphicsEnd - WorldMapTileGraphics
ld a, BANK(WorldMapTileGraphics)
- call FarCopyData2
+ call FarCopyData
ld hl, MonNestIcon
ld de, vSprites tile $04
ld bc, MonNestIconEnd - MonNestIcon
@@ -401,8 +411,7 @@ DisplayWildLocations:
jr nz, .drawPlayerSprite
; if no OAM entries were written, print area unknown text
hlcoord 1, 7
- ld b, 2
- ld c, 15
+ lb bc, 2, 15
call TextBoxBorder
hlcoord 2, 9
ld de, AreaUnknownText
diff --git a/engine/joypad.asm b/engine/joypad.asm
index b6c50e69..7ebb88ef 100644
--- a/engine/joypad.asm
+++ b/engine/joypad.asm
@@ -1,12 +1,46 @@
+ReadJoypad_::
+; Poll joypad input.
+; Unlike the hardware register, button
+; presses are indicated by a set bit.
+ ldh a, [hDisableJoypadPolling]
+ and a
+ ret nz
+
+ ld a, 1 << 5 ; select direction keys
+
+ ldh [rJOYP], a
+ ldh a, [rJOYP]
+ ldh a, [rJOYP]
+ cpl
+ and %1111
+ swap a
+ ld b, a
+
+ ld a, 1 << 4 ; select button keys
+ ldh [rJOYP], a
+REPT 6
+ ldh a, [rJOYP]
+ENDR
+ cpl
+ and %1111
+ or b
+
+ ldh [hJoyInput], a
+
+ ld a, 1 << 4 + 1 << 5 ; deselect keys
+ ldh [rJOYP], a
+ ret
+
_Joypad::
; hJoyReleased: (hJoyLast ^ hJoyInput) & hJoyLast
; hJoyPressed: (hJoyLast ^ hJoyInput) & hJoyInput
ldh a, [hJoyInput]
+ ld b, a
+ and PAD_BUTTONS | PAD_UP
cp PAD_BUTTONS ; soft reset
jp z, TrySoftReset
- ld b, a
ldh a, [hJoyLast]
ld e, a
xor b
diff --git a/engine/link/cable_club.asm b/engine/link/cable_club.asm
index 6ffb2aea..716b1441 100644
--- a/engine/link/cable_club.asm
+++ b/engine/link/cable_club.asm
@@ -10,8 +10,7 @@ CableClub_DoBattleOrTrade:
call LoadHpBarAndStatusTilePatterns
call LoadTrainerInfoTextBoxTiles
hlcoord 3, 8
- ld b, 2
- ld c, 12
+ lb bc, 2, 12
call CableClub_TextBoxBorder
hlcoord 4, 10
ld de, PleaseWaitString
@@ -119,12 +118,12 @@ CableClub_DoBattleOrTradeAgain:
ldh [rSC], a
.skipSendingTwoZeroBytes
call Delay3
+ call StopAllMusic
ld a, IE_SERIAL
ldh [rIE], a
ld hl, wSerialRandomNumberListBlock
ld de, wSerialOtherGameboyRandomNumberListBlock
ld bc, SERIAL_RN_PREAMBLE_LENGTH + SERIAL_RNS_LENGTH
- vc_hook Wireless_ExchangeBytes_RNG_state_unknown_Type5
call Serial_ExchangeBytes
ld a, SERIAL_NO_DATA_BYTE
ld [de], a
@@ -142,8 +141,6 @@ CableClub_DoBattleOrTradeAgain:
call Serial_ExchangeBytes
ld a, IE_SERIAL | IE_TIMER | IE_VBLANK
ldh [rIE], a
- ld a, SFX_STOP_ALL_MUSIC
- call PlaySound
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr z, .skipCopyingRandomNumberList ; the list generated by the gameboy clocking the connection is used by both gameboys
@@ -264,8 +261,7 @@ CableClub_DoBattleOrTradeAgain:
ld [wUnusedNamePointer + 1], a
xor a
ld [wTradeCenterPointerTableIndex], a
- ld a, SFX_STOP_ALL_MUSIC
- call PlaySound
+ call StopAllMusic
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
ld c, 66
@@ -281,9 +277,17 @@ CableClub_DoBattleOrTradeAgain:
ld [wCurOpponent], a
call ClearScreen
call Delay3
+ ld b, SET_PAL_OVERWORLD
+ call RunPaletteCommand
ld hl, wOptions
res BIT_BATTLE_ANIMATION, [hl]
+ ld a, [wLetterPrintingDelayFlags]
+ push af
+ xor a
+ ld [wLetterPrintingDelayFlags], a
predef InitOpponent
+ pop af
+ ld [wLetterPrintingDelayFlags], a
predef HealParty
jp ReturnToCableClubRoom
.trading
@@ -311,6 +315,9 @@ CallCurrentTradeCenterFunction:
TradeCenter_SelectMon:
call ClearScreen
+ call Delay3
+ ld b, SET_PAL_OVERWORLD
+ call RunPaletteCommand
call LoadTrainerInfoTextBoxTiles
call TradeCenter_DrawPartyLists
call TradeCenter_DrawCancelBox
@@ -468,8 +475,7 @@ TradeCenter_SelectMon:
.displayStatsTradeMenu
push af
hlcoord 0, 14
- ld b, 2
- ld c, 18
+ lb bc, 2, 18
call CableClub_TextBoxBorder
hlcoord 2, 16
ld de, .statsTrade
@@ -604,8 +610,7 @@ TradeCenter_DrawCancelBox:
ld bc, 2 * SCREEN_WIDTH + 9
call FillMemory
hlcoord 0, 15
- ld b, 1
- ld c, 9
+ lb bc, 1, 9
call CableClub_TextBoxBorder
hlcoord 2, 16
ld de, CancelTextString
@@ -627,6 +632,9 @@ TradeCenter_DisplayStats:
ld [wWhichPokemon], a
predef StatusScreen
predef StatusScreen2
+ call Delay3
+ ld b, SET_PAL_OVERWORLD
+ call RunPaletteCommand
call GBPalNormal
call LoadTrainerInfoTextBoxTiles
call TradeCenter_DrawPartyLists
@@ -634,12 +642,10 @@ TradeCenter_DisplayStats:
TradeCenter_DrawPartyLists:
hlcoord 0, 0
- ld b, 6
- ld c, 18
+ lb bc, 6, 18
call CableClub_TextBoxBorder
hlcoord 0, 8
- ld b, 6
- ld c, 18
+ lb bc, 6, 18
call CableClub_TextBoxBorder
hlcoord 5, 0
ld de, wPlayerName
@@ -688,8 +694,7 @@ TradeCenter_Trade:
ld [wMenuWatchMovingOutOfBounds], a
ld [wMenuJoypadPollCount], a
hlcoord 0, 12
- ld b, 4
- ld c, 18
+ lb bc, 4, 18
call CableClub_TextBoxBorder
ld a, [wTradingWhichPlayerMon]
ld hl, wPartySpecies
@@ -730,8 +735,7 @@ TradeCenter_Trade:
ld a, $1
ld [wSerialExchangeNybbleSendData], a
hlcoord 0, 12
- ld b, 4
- ld c, 18
+ lb bc, 4, 18
call CableClub_TextBoxBorder
hlcoord 1, 14
ld de, TradeCanceled
@@ -747,8 +751,7 @@ TradeCenter_Trade:
jr nz, .doTrade
; if the other person cancelled
hlcoord 0, 12
- ld b, 4
- ld c, 18
+ lb bc, 4, 18
call CableClub_TextBoxBorder
hlcoord 1, 14
ld de, TradeCanceled
@@ -795,6 +798,7 @@ TradeCenter_Trade:
add hl, bc
ld a, [hl]
ld [wTradedPlayerMonSpecies], a
+ farcall_ModifyPikachuHappiness PIKAHAPPY_TRADE
xor a
ld [wRemoveMonFromBox], a
call RemovePokemon
@@ -854,9 +858,11 @@ TradeCenter_Trade:
call Serial_PrintWaitingTextAndSyncAndExchangeNybble
ld c, 40
call DelayFrames
+ call Delay3
+ ld b, SET_PAL_OVERWORLD
+ call RunPaletteCommand
hlcoord 0, 12
- ld b, 4
- ld c, 18
+ lb bc, 4, 18
call CableClub_TextBoxBorder
hlcoord 1, 14
ld de, TradeCompleted
diff --git a/engine/link/cable_club_npc.asm b/engine/link/cable_club_npc.asm
index 2c458b59..fda27dd9 100644
--- a/engine/link/cable_club_npc.asm
+++ b/engine/link/cable_club_npc.asm
@@ -1,9 +1,12 @@
CableClubNPC::
ld hl, CableClubNPCWelcomeText
call PrintText
+ call CheckPikachuFollowingPlayer
+ jr nz, .asm_7048
CheckEvent EVENT_GOT_POKEDEX
jp nz, .receivedPokedex
; if the player hasn't received the pokedex
+.asm_7048
ld c, 60
call DelayFrames
ld hl, CableClubNPCMakingPreparationsText
@@ -76,8 +79,8 @@ CableClubNPC::
xor a
ld [hl], a
ldh [hSerialReceivedNewData], a
- vc_hook Wireless_prompt
ld [wSerialExchangeNybbleSendData], a
+ vc_hook Wireless_prompt
call Serial_SyncAndExchangeNybble
vc_hook Wireless_net_recheck
ld hl, wUnknownSerialCounter
@@ -119,7 +122,61 @@ CableClubNPC::
xor a
ld [hld], a
ld [hl], a
- jpfar LinkMenu
+ ld a, [wLetterPrintingDelayFlags]
+ push af
+ callfar LinkMenu
+ pop af
+ ld [wLetterPrintingDelayFlags], a
+ ret
+
+; seems to be similar of Serial_SyncAndExchangeNybble
+Serial_SyncAndExchangeNybbleDouble:
+ ld a, $ff
+ ld [wSerialExchangeNybbleReceiveData], a
+.loop
+ call Serial_ExchangeNybble
+ call DelayFrame
+ push hl
+ ld hl, wUnknownSerialCounter + 1
+ dec [hl]
+ jr nz, .next
+ dec hl
+ dec [hl]
+ jr nz, .next
+ pop hl
+ jr .setUnknownSerialCounterToFFFF
+.next
+ pop hl
+ ld a, [wSerialExchangeNybbleReceiveData]
+ inc a
+ jr z, .loop
+ call DelayFrame
+ ld a, $ff
+ ld [wSerialExchangeNybbleReceiveData], a
+ call Serial_ExchangeNybble
+ ld a, [wSerialExchangeNybbleReceiveData]
+ inc a
+ jr z, .loop
+ ld b, 10
+.syncLoop1
+ call DelayFrame
+ call Serial_ExchangeNybble
+ dec b
+ jr nz, .syncLoop1
+ ld b, 10
+.syncLoop2
+ call DelayFrame
+ call Serial_SendZeroByte
+ dec b
+ jr nz, .syncLoop2
+ ld a, [wSerialExchangeNybbleReceiveData]
+ ld [wSerialSyncAndExchangeNybbleReceiveData], a
+ ret
+.setUnknownSerialCounterToFFFF
+ ld a, $ff
+ ld [wUnknownSerialCounter], a
+ ld [wUnknownSerialCounter + 1], a
+ ret
CableClubNPCAreaReservedFor2FriendsLinkedByCableText:
text_far _CableClubNPCAreaReservedFor2FriendsLinkedByCableText
diff --git a/engine/link/print_waiting_text.asm b/engine/link/print_waiting_text.asm
index 1a16e2f2..a07967fd 100644
--- a/engine/link/print_waiting_text.asm
+++ b/engine/link/print_waiting_text.asm
@@ -1,7 +1,6 @@
PrintWaitingText::
hlcoord 3, 10
- ld b, 1
- ld c, 11
+ lb bc, 1, 11
ld a, [wIsInBattle]
and a
jr z, .trade
diff --git a/engine/menus/display_text_id_init.asm b/engine/menus/display_text_id_init.asm
index 7ffdf7c3..1dda338d 100644
--- a/engine/menus/display_text_id_init.asm
+++ b/engine/menus/display_text_id_init.asm
@@ -14,19 +14,16 @@ DisplayTextIDInit::
CheckEvent EVENT_GOT_POKEDEX
; start menu with pokedex
hlcoord 10, 0
- ld b, $0e
- ld c, $08
+ lb bc, 14, 8
jr nz, .drawTextBoxBorder
; start menu without pokedex
hlcoord 10, 0
- ld b, $0c
- ld c, $08
+ lb bc, 12, 8
jr .drawTextBoxBorder
; if text ID is not 0 (i.e. not the start menu) then do a standard dialogue text box
.notStartMenu
hlcoord 0, 12
- ld b, $04
- ld c, $12
+ lb bc, 4, 18
.drawTextBoxBorder
call TextBoxBorder
.skipDrawingTextBoxBorder
diff --git a/engine/menus/draw_start_menu.asm b/engine/menus/draw_start_menu.asm
index 7a048528..a72236c3 100644
--- a/engine/menus/draw_start_menu.asm
+++ b/engine/menus/draw_start_menu.asm
@@ -3,13 +3,11 @@ DrawStartMenu::
CheckEvent EVENT_GOT_POKEDEX
; menu with pokedex
hlcoord 10, 0
- ld b, $0e
- ld c, $08
+ lb bc, 14, 8
jr nz, .drawTextBoxBorder
; shorter menu if the player doesn't have the pokedex
hlcoord 10, 0
- ld b, $0c
- ld c, $08
+ lb bc, 12, 8
.drawTextBoxBorder
call TextBoxBorder
ld a, PAD_DOWN | PAD_UP | PAD_START | PAD_B | PAD_A
@@ -63,7 +61,7 @@ StartMenuPokedexText:
db "POKéDEX@"
StartMenuPokemonText:
- db "POKéMON@"
+ db "#MON@"
StartMenuItemText:
db "ITEM@"
diff --git a/engine/menus/league_pc.asm b/engine/menus/league_pc.asm
index c8a8972f..ba6ca318 100644
--- a/engine/menus/league_pc.asm
+++ b/engine/menus/league_pc.asm
@@ -100,8 +100,7 @@ LeaguePCShowMon:
call LoadFrontSpriteByMonIndex
call GBPalNormal
hlcoord 0, 13
- ld b, 2
- ld c, $12
+ lb bc, 2, 18
call TextBoxBorder
hlcoord 1, 15
ld de, HallOfFameNoText
@@ -110,7 +109,7 @@ LeaguePCShowMon:
ld de, wHoFTeamNo
lb bc, 1, 3
call PrintNumber
- farjp HoFDisplayMonInfo
+ farjp Func_7033f
HallOfFameNoText:
db "HALL OF FAME No @"
diff --git a/engine/menus/link_menu.asm b/engine/menus/link_menu.asm
new file mode 100644
index 00000000..e1a60161
--- /dev/null
+++ b/engine/menus/link_menu.asm
@@ -0,0 +1,918 @@
+Func_f531b::
+ ld c, $14
+ call DelayFrames
+ ld a, $1
+ ld [wBuffer], a
+ xor a
+ ld [wUnknownSerialFlag_d499], a
+ hlcoord 0, 0
+ lb bc, 4, 5
+ call TextBoxBorder
+ ld de, Text_f5791
+ hlcoord 1, 2
+ call PlaceString
+ hlcoord 8, 0
+ lb bc, 8, 10
+ call TextBoxBorder
+ hlcoord 10, 2
+ ld de, Text_f579c
+ call PlaceString
+ hlcoord 0, 10
+ lb bc, 6, 18
+ call TextBoxBorder
+ call UpdateSprites
+ xor a
+ ld [wUnusedLinkMenuByte], a
+ ld [wCableClubDestinationMap], a
+ ld [wNamedObjectIndex], a
+ ld hl, wTopMenuItemY
+ ld a, $2
+ ld [hli], a
+ ld a, $9
+ ld [hli], a
+ xor a
+ ld [hli], a
+ inc hl
+ ld a, $3
+ ld [hli], a
+ ld a, $3
+ ld [hli], a
+ xor a
+ ld [hl], a
+.asm_f5377
+ call Func_f56bd
+ call HandleMenuInput
+ and $3
+ add a
+ add a
+ ld b, a
+ ld a, [wCurrentMenuItem]
+ cp $3
+ jr nz, .asm_f5390
+ bit 2, b
+ jr z, .asm_f5390
+ dec a
+ ld b, $8
+.asm_f5390
+ add b
+ add $c0
+ ld [wLinkMenuSelectionSendBuffer], a
+ ld [wLinkMenuSelectionSendBuffer+1], a
+.asm_f5399
+ ld hl, wLinkMenuSelectionSendBuffer
+ ld a, [hl]
+ ldh [hSerialSendData], a
+ call Serial_ExchangeByte
+ push af
+ ld hl, wLinkMenuSelectionSendBuffer
+ ld a, [hl]
+ ldh [hSerialSendData], a
+ call Serial_ExchangeByte
+ pop bc
+ cp b
+ jr nz, .asm_f5399
+ and $f0
+ cp $c0
+ jr nz, .asm_f5399
+ ld a, b
+ and $c
+ jr nz, .asm_f53c4
+ ld a, [wLinkMenuSelectionSendBuffer]
+ and $c
+ jr z, .asm_f5377
+ jr .asm_f53df
+.asm_f53c4
+ ld a, [wLinkMenuSelectionSendBuffer]
+ and $c
+ jr z, .asm_f53d1
+ ldh a, [hSerialConnectionStatus]
+ cp $2
+ jr z, .asm_f53df
+.asm_f53d1
+ ld a, $1
+ ld [wNamedObjectIndex], a
+ ld a, b
+ ld [wLinkMenuSelectionSendBuffer], a
+ and $3
+ ld [wCurrentMenuItem], a
+.asm_f53df
+ call DelayFrame
+ call DelayFrame
+ ld hl, wLinkMenuSelectionSendBuffer
+ ld a, [hl]
+ ldh [hSerialSendData], a
+ call Serial_ExchangeByte
+ call Serial_ExchangeByte
+ ld b, $14
+.loop
+ call DelayFrame
+ call Serial_SendZeroByte
+ dec b
+ jr nz, .loop
+ ld b, ' '
+ ld c, ' '
+ ld d, ' '
+ ld e, '▷'
+ ld a, [wLinkMenuSelectionSendBuffer]
+ bit 3, a
+ jr nz, .asm_f541a
+ ld b, e
+ ld e, c
+ ld a, [wCurrentMenuItem]
+ and a
+ jr z, .asm_f541a
+ ld c, b
+ ld b, d
+ dec a
+ jr z, .asm_f541a
+ ld d, c
+ ld c, b
+.asm_f541a
+ ld a, b
+ ldcoord_a 9, 2
+ ld a, c
+ ldcoord_a 9, 4
+ ld a, d
+ ldcoord_a 9, 6
+ ld a, e
+ ldcoord_a 9, 8
+ ld c, 40
+ call DelayFrames
+ ld a, [wLinkMenuSelectionSendBuffer]
+ bit 3, a
+ jr nz, asm_f547f
+ ld a, [wCurrentMenuItem]
+ cp $3
+ jr z, asm_f547f
+ inc a
+ ld [wUnknownSerialFlag_d499], a
+ ld a, [wCurrentMenuItem]
+ ld hl, PointerTable_f5488
+ ld c, a
+ ld b, $0
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .returnaddress
+ push de
+ jp hl
+.returnaddress
+ ld [wLinkMenuSelectionSendBuffer], a
+ xor a
+ ld [wUnknownSerialCounter], a
+ ld [wUnknownSerialCounter+1], a
+ call Serial_SyncAndExchangeNybble
+ ld a, [wLinkMenuSelectionSendBuffer]
+ and a
+ jr nz, asm_f547c
+ ld a, [wLinkMenuSelectionReceiveBuffer]
+ and a
+ jr nz, Func_f5476
+ xor a
+ ld [wUnknownSerialCounter], a
+ ld [wUnknownSerialCounter+1], a
+ and a
+ ret
+
+Func_f5476::
+ ld hl, ColosseumIneligibleText
+ call PrintText
+asm_f547c::
+ jp Func_f531b
+
+asm_f547f::
+ xor a
+ ld [wUnknownSerialCounter], a
+ ld [wUnknownSerialCounter+1], a
+ scf
+ ret
+
+PointerTable_f5488::
+ dw PokeCup
+ dw PikaCup
+ dw PetitCup
+
+PokeCup::
+ ld hl, wPartyCount
+ ld a, [hli]
+ cp $3
+ jp nz, NotThreeMonsInParty
+ ld b, $3
+.loop
+ ld a, [hli]
+ cp MEW
+ jp z, MewInParty
+ dec b
+ jr nz, .loop
+ dec hl
+ dec hl
+ cp [hl] ; is third mon second mon?
+ jp z, DuplicateSpecies
+ dec hl ; wPartySpecies
+ cp [hl] ; is third mon first mon?
+ jp z, DuplicateSpecies
+ ld a, [hli]
+ cp [hl] ; is first mon second mon?
+ jp z, DuplicateSpecies
+ ld a, [wPartyMon1Level]
+ cp 56
+ jp nc, LevelAbove55
+ cp 50
+ jp c, LevelUnder50
+ ld b, a
+ ld a, [wPartyMon2Level]
+ cp 56
+ jp nc, LevelAbove55
+ cp 50
+ jp c, LevelUnder50
+ ld c, a
+ ld a, [wPartyMon3Level]
+ cp 56
+ jp nc, LevelAbove55
+ cp 50
+ jp c, LevelUnder50
+ add b
+ add c
+ cp 156
+ jp nc, CombinedLevelsGreaterThan155
+ xor a
+ ret
+
+PikaCup::
+ ld hl, wPartyCount
+ ld a, [hli]
+ cp $3
+ jp nz, NotThreeMonsInParty
+ ld b, $3
+.loop
+ ld a, [hli] ; wPartySpecies
+ cp MEW
+ jp z, MewInParty
+ dec b
+ jr nz, .loop
+ dec hl
+ dec hl
+ cp [hl] ; is third mon second mon?
+ jp z, DuplicateSpecies
+ dec hl ; wPartySpecies
+ cp [hl] ; is third mon first mon?
+ jp z, DuplicateSpecies
+ ld a, [hli]
+ cp [hl] ; is first mon second mon?
+ jp z, DuplicateSpecies
+ ld a, [wPartyMon1Level]
+ cp 21
+ jp nc, LevelAbove20
+ cp 15
+ jp c, LevelUnder15
+ ld b, a
+ ld a, [wPartyMon2Level]
+ cp 21
+ jp nc, LevelAbove20
+ cp 15
+ jp c, LevelUnder15
+ ld c, a
+ ld a, [wPartyMon3Level]
+ cp 21
+ jp nc, LevelAbove20
+ cp 15
+ jp c, LevelUnder15
+ add b
+ add c
+ cp 51
+ jp nc, CombinedLevelsAbove50
+ xor a
+ ret
+
+PetitCup::
+ ld hl, wPartyCount
+ ld a, [hli]
+ cp $3
+ jp nz, NotThreeMonsInParty
+ ld b, $3
+.loop
+ ld a, [hli]
+ cp MEW
+ jp z, MewInParty
+ dec b
+ jr nz, .loop
+ dec hl
+ dec hl
+ cp [hl] ; is third mon second mon?
+ jp z, DuplicateSpecies
+ dec hl ; wPartySpecies
+ cp [hl] ; is third mon first mon?
+ jp z, DuplicateSpecies
+ ld a, [hli]
+ cp [hl] ; is first mon second mon?
+ jp z, DuplicateSpecies
+ dec hl
+ ld a, [hl]
+ ld [wCurPartySpecies], a
+ push hl
+ callfar Func_3b10f
+ pop hl
+ jp c, asm_f56ad
+ inc hl
+ ld a, [hl]
+ ld [wCurPartySpecies], a
+ push hl
+ callfar Func_3b10f
+ pop hl
+ jp c, asm_f56ad
+ inc hl
+ ld a, [hl]
+ ld [wCurPartySpecies], a
+ push hl
+ callfar Func_3b10f
+ pop hl
+ jp c, asm_f56ad
+ dec hl
+ dec hl
+ ld b, $3
+.bigloop
+ ld a, [hli]
+ push hl
+ push bc
+ push af
+ dec a
+ ld c, a
+ ld b, $0
+ ld hl, PokedexEntryPointers
+ add hl, bc
+ add hl, bc
+ ld de, wNameBuffer
+ ld bc, $2
+ ld a, BANK(PokedexEntryPointers)
+ call FarCopyData
+ ld hl, wNameBuffer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wNameBuffer
+ ld bc, $14
+ ld a, BANK(PokedexEntryPointers)
+ call FarCopyData
+ ld hl, wNameBuffer
+.loop2
+ ld a, [hli]
+ cp '@'
+ jr nz, .loop2
+ ld a, [hli]
+ cp $7
+ jp nc, asm_f5689
+ add a
+ add a
+ ld b, a
+ add a
+ add b
+ ld b, a
+ ld a, [hli]
+ add b
+ cp $51
+ jp nc, asm_f5689
+ ld a, [hli]
+ sub $b9
+ ld a, [hl]
+ sbc $1
+ jp nc, asm_f569b
+ pop af
+ pop bc
+ pop hl
+ dec b
+ jr nz, .bigloop
+ ld a, [wPartyMon1Level]
+ cp 31
+ jp nc, LevelAbove30
+ cp 25
+ jp c, LevelUnder25
+ ld b, a
+ ld a, [wPartyMon2Level]
+ cp 31
+ jp nc, LevelAbove30
+ cp 25
+ jp c, LevelUnder25
+ ld c, a
+ ld a, [wPartyMon3Level]
+ cp 31
+ jp nc, LevelAbove30
+ cp 25
+ jp c, LevelUnder25
+ add b
+ add c
+ cp 81
+ jp nc, CombinedLevelsAbove80
+ xor a
+ ret
+
+NotThreeMonsInParty::
+ ld hl, Colosseum3MonsText
+ call PrintText
+ ld a, $1
+ ret
+
+MewInParty::
+ ld hl, ColosseumMewText
+ call PrintText
+ ld a, $2
+ ret
+
+DuplicateSpecies::
+ ld hl, ColosseumDifferentMonsText
+ call PrintText
+ ld a, $3
+ ret
+
+LevelAbove55::
+ ld hl, ColosseumMaxL55Text
+ call PrintText
+ ld a, $4
+ ret
+
+LevelUnder50::
+ ld hl, ColosseumMinL50Text
+ call PrintText
+ ld a, $5
+ ret
+
+CombinedLevelsGreaterThan155::
+ ld hl, ColosseumTotalL155Text
+ call PrintText
+ ld a, $6
+ ret
+
+LevelAbove30::
+ ld hl, ColosseumMaxL30Text
+ call PrintText
+ ld a, $7
+ ret
+
+LevelUnder25::
+ ld hl, ColosseumMinL25Text
+ call PrintText
+ ld a, $8
+ ret
+
+CombinedLevelsAbove80::
+ ld hl, ColosseumTotalL80Text
+ call PrintText
+ ld a, $9
+ ret
+
+LevelAbove20::
+ ld hl, ColosseumMaxL20Text
+ call PrintText
+ ld a, $a
+ ret
+
+LevelUnder15::
+ ld hl, ColosseumMinL15Text
+ call PrintText
+ ld a, $b
+ ret
+
+CombinedLevelsAbove50::
+ ld hl, ColosseumTotalL50Text
+ call PrintText
+ ld a, $c
+ ret
+
+asm_f5689::
+ pop af
+ pop bc
+ pop hl
+ ld [wNamedObjectIndex], a
+ call GetMonName
+ ld hl, ColosseumHeightText
+ call PrintText
+ ld a, $d
+ ret
+
+asm_f569b::
+ pop af
+ pop bc
+ pop hl
+ ld [wNamedObjectIndex], a
+ call GetMonName
+ ld hl, ColosseumWeightText
+ call PrintText
+ ld a, $e
+ ret
+
+asm_f56ad::
+ ld a, [hl]
+ ld [wNamedObjectIndex], a
+ call GetMonName
+ ld hl, ColosseumEvolvedText
+ call PrintText
+ ld a, $f
+ ret
+
+Func_f56bd::
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ hlcoord 1, 11
+ lb bc, 6, 18
+ call ClearScreenArea
+ ld a, [wCurrentMenuItem]
+ cp $3
+ jr nc, .asm_f56e6
+ ld hl, PointerTable_f56ee
+ ld a, [wCurrentMenuItem]
+ ld c, a
+ ld b, $0
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld d, h
+ ld e, l
+ hlcoord 1, 12
+ call PlaceString
+.asm_f56e6
+ call Delay3
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ ret
+
+PointerTable_f56ee::
+ dw Text_f56f4
+ dw Text_f5728
+ dw Text_f575b
+
+Text_f56f4::
+ db "LVs of 3<PKMN>:50-55"
+ next "Sum of LVs:155 MAX"
+ next "MEW can't attend.@"
+
+Text_f5728::
+ db "LVs of 3<PKMN>:15-20"
+ next "Sum of LVs:50 MAX"
+ next "MEW can't attend.@"
+
+Text_f575b::
+ db "3 Basic <PKMN>.LV25-30"
+ next "Sum of LVs:80 MAX"
+ next "6’8” and 44lb MAX@"
+
+Text_f5791::
+ db "View"
+ next "Rules@"
+
+Text_f579c::
+ db "# Cup"
+ next "Pika Cup"
+ next "Petit Cup"
+ next "CANCEL@"
+
+Colosseum3MonsText::
+ text_far _Colosseum3MonsText
+ text_end
+
+ColosseumMewText::
+ text_far _ColosseumMewText
+ text_end
+
+ColosseumDifferentMonsText::
+ text_far _ColosseumDifferentMonsText
+ text_end
+
+ColosseumMaxL55Text::
+ text_far _ColosseumMaxL55Text
+ text_end
+
+ColosseumMinL50Text::
+ text_far _ColosseumMinL50Text
+ text_end
+
+ColosseumTotalL155Text::
+ text_far _ColosseumTotalL155Text
+ text_end
+
+ColosseumMaxL30Text::
+ text_far _ColosseumMaxL30Text
+ text_end
+
+ColosseumMinL25Text::
+ text_far _ColosseumMinL25Text
+ text_end
+
+ColosseumTotalL80Text::
+ text_far _ColosseumTotalL80Text
+ text_end
+
+ColosseumMaxL20Text::
+ text_far _ColosseumMaxL20Text
+ text_end
+
+ColosseumMinL15Text::
+ text_far _ColosseumMinL15Text
+ text_end
+
+ColosseumTotalL50Text::
+ text_far _ColosseumTotalL50Text
+ text_end
+
+ColosseumHeightText::
+ text_far _ColosseumHeightText
+ text_end
+
+ColosseumWeightText::
+ text_far _ColosseumWeightText
+ text_end
+
+ColosseumEvolvedText::
+ text_far _ColosseumEvolvedText
+ text_end
+
+ColosseumIneligibleText::
+ text_far _ColosseumIneligibleText
+ text_end
+
+LinkMenu:
+ xor a
+ ld [wLetterPrintingDelayFlags], a
+ ld hl, wStatusFlags4
+ set BIT_LINK_CONNECTED, [hl]
+ ld hl, TextTerminator_f5a16
+ call PrintText
+ call SaveScreenTilesToBuffer1
+ ld hl, ColosseumWhereToText
+ call PrintText
+ hlcoord 5, 3
+ lb bc, 8, 13
+ call TextBoxBorder
+ call UpdateSprites
+ hlcoord 7, 5
+ ld de, TradeCenterText
+ call PlaceString
+ xor a
+ ld [wUnusedLinkMenuByte], a
+ ld [wCableClubDestinationMap], a
+ ld [wNamedObjectIndex], a
+ ld hl, wTopMenuItemY
+ ld a, 5
+ ld [hli], a
+ ASSERT wTopMenuItemY + 1 == wTopMenuItemX
+ ld a, 6
+ ld [hli], a
+ ASSERT wTopMenuItemX + 1 == wCurrentMenuItem
+ xor a
+ ld [hli], a
+ inc hl
+ ASSERT wCurrentMenuItem + 2 == wMaxMenuItem
+ ld a, 3
+ ld [hli], a
+ ASSERT wMaxMenuItem + 1 == wMenuWatchedKeys
+ ASSERT 2 == PAD_B
+ ld [hli], a
+ ASSERT wMenuWatchedKeys + 1 == wLastMenuItem
+ xor a
+ ld [hl], a
+.waitForInputLoop
+ call HandleMenuInput
+ and PAD_A | PAD_B
+ add a
+ add a
+ ld b, a
+ ld a, [wCurrentMenuItem]
+ cp $3
+ jr nz, .asm_f586b
+ bit 2, b
+ jr z, .asm_f586b
+ dec a
+ ld b, $8
+.asm_f586b
+ add b
+ add $d0
+ ld [wLinkMenuSelectionSendBuffer], a
+ ld [wLinkMenuSelectionSendBuffer + 1], a
+.exchangeMenuSelectionLoop
+ call Serial_ExchangeLinkMenuSelection
+ ld a, [wLinkMenuSelectionReceiveBuffer]
+ ld b, a
+ and $f0
+ cp $d0
+ jr z, .checkEnemyMenuSelection
+ ld a, [wLinkMenuSelectionReceiveBuffer + 1]
+ ld b, a
+ and $f0
+ cp $d0
+ jr nz, .exchangeMenuSelectionLoop
+.checkEnemyMenuSelection
+ ld a, b
+ and $c ; did the enemy press A or B?
+ jr nz, .enemyPressedAOrB
+; the enemy didn't press A or B
+ ld a, [wLinkMenuSelectionSendBuffer]
+ and $c ; did the player press A or B?
+ jr z, .waitForInputLoop ; if neither the player nor the enemy pressed A or B, try again
+ jr .doneChoosingMenuSelection ; if the player pressed A or B but the enemy didn't, use the player's selection
+.enemyPressedAOrB
+ ld a, [wLinkMenuSelectionSendBuffer]
+ and $c ; did the player press A or B?
+ jr z, .useEnemyMenuSelection ; if the enemy pressed A or B but the player didn't, use the enemy's selection
+; the enemy and the player both pressed A or B
+; The gameboy that is clocking the connection wins.
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr z, .doneChoosingMenuSelection
+.useEnemyMenuSelection
+ ld a, $1
+ ld [wNamedObjectIndex], a
+ ld a, b
+ ld [wLinkMenuSelectionSendBuffer], a
+ and $3
+ ld [wCurrentMenuItem], a
+.doneChoosingMenuSelection
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr nz, .skipStartingTransfer
+ call DelayFrame
+ call DelayFrame
+ ld a, SC_START | SC_INTERNAL
+ ldh [rSC], a
+.skipStartingTransfer
+ ld b, ' '
+ ld c, ' '
+ ld d, ' '
+ ld e, '▷'
+ ld a, [wLinkMenuSelectionSendBuffer]
+ and PAD_B << 2 ; was B button pressed?
+ jr nz, .updateCursorPosition
+; A button was pressed
+ ld a, [wCurrentMenuItem]
+ cp $2
+ jp z, .asm_f5963
+ ld b, e
+ ld e, c
+ ld a, [wCurrentMenuItem]
+ and a
+ jr z, .updateCursorPosition
+ ld c, b
+ ld b, d
+ dec a
+ jr z, .updateCursorPosition
+ ld d, c
+ ld c, b
+.updateCursorPosition
+ call Func_f59ec
+ call LoadScreenTilesFromBuffer1
+ ld a, [wLinkMenuSelectionSendBuffer]
+ and PAD_B << 2 ; was B button pressed?
+ jr nz, .choseCancel ; cancel if B pressed
+ ld a, [wCurrentMenuItem]
+ cp $2
+ jr z, .choseCancel
+ xor a
+ ld [wWalkBikeSurfState], a ; start walking
+ ld a, [wCurrentMenuItem]
+ and a
+ ld a, COLOSSEUM
+ jr nz, .next
+ ld a, TRADE_CENTER
+.next
+ ld [wCableClubDestinationMap], a
+ ld hl, ColosseumPleaseWaitText
+ call PrintText
+ ld c, 50
+ call DelayFrames
+ ld hl, wStatusFlags6
+ res BIT_DEBUG_MODE, [hl]
+ ld a, [wDefaultMap]
+ ld [wDestinationMap], a
+ callfar PrepareForSpecialWarp
+ ld c, 20
+ call DelayFrames
+ xor a
+ ld [wMenuJoypadPollCount], a
+ ld [wSerialExchangeNybbleSendData], a
+ inc a ; LINK_STATE_IN_CABLE_CLUB
+ ld [wLinkState], a
+ ld [wEnteringCableClub], a
+ jpfar SpecialEnterMap
+.choseCancel
+ xor a
+ ld [wMenuJoypadPollCount], a
+ call Delay3
+ callfar CloseLinkConnection
+ ld hl, ColosseumCanceledText
+ vc_hook Wireless_net_stop
+ call PrintText
+ ld hl, wStatusFlags4
+ res BIT_LINK_CONNECTED, [hl]
+ vc_hook Wireless_net_end
+ ret
+
+.asm_f5963
+ ld a, [wNamedObjectIndex]
+ and a
+ jr nz, .asm_f5974
+ ld b, ' '
+ ld c, ' '
+ ld d, '▷'
+ ld e, ' '
+ call Func_f59ec
+.asm_f5974
+ xor a
+ ld [wBuffer], a
+ ld a, $ff
+ ld [wSerialExchangeNybbleReceiveData], a
+ ld a, $b
+ ld [wLinkMenuSelectionSendBuffer], a
+ ld b, $78
+.loop
+ ldh a, [hSerialConnectionStatus]
+ cp $2
+ call z, DelayFrame
+ dec b
+ jr z, .asm_f59b2
+ call Serial_ExchangeNybble
+ call DelayFrame
+ ld a, [wSerialExchangeNybbleReceiveData]
+ inc a
+ jr z, .loop
+ ld b, $f
+.loop2
+ call DelayFrame
+ call Serial_ExchangeNybble
+ dec b
+ jr nz, .loop2
+ ld b, $f
+.loop3
+ call DelayFrame
+ call Serial_SendZeroByte
+ dec b
+ jr nz, .loop3
+ jr .asm_f59d6
+
+.asm_f59b2
+ xor a
+ ld [wUnknownSerialCounter], a
+ ld [wUnknownSerialCounter+1], a
+ ld a, [wNamedObjectIndex]
+ and a
+ jr z, .asm_f59cd
+ ld b, ' '
+ ld c, ' '
+ ld d, ' '
+ ld e, '▷'
+ call Func_f59ec
+ jp .choseCancel
+
+.asm_f59cd
+ ld hl, ColosseumVersionText
+ call PrintText
+ jp .choseCancel
+
+.asm_f59d6
+ ld b, ' '
+ ld c, ' '
+ ld d, '▷'
+ ld e, ' '
+ call Func_f59ec
+ call Func_f531b
+ jp c, .choseCancel
+ ld a, $f0
+ jp .next
+
+Func_f59ec::
+ ld a, b
+ ldcoord_a 6, 5
+ ld a, c
+ ldcoord_a 6, 7
+ ld a, d
+ ldcoord_a 6, 9
+ ld a, e
+ ldcoord_a 6, 11
+ ld c, 40
+ call DelayFrames
+ ret
+
+ColosseumWhereToText:
+ text_far _ColosseumWhereToText
+ text_end
+
+ColosseumPleaseWaitText:
+ text_far _ColosseumPleaseWaitText
+ text_end
+
+ColosseumCanceledText:
+ text_far _ColosseumCanceledText
+ text_end
+
+ColosseumVersionText:
+ text_far _ColosseumVersionText
+ text_end
+
+TextTerminator_f5a16:
+ text_end
+
+TradeCenterText:
+ db "TRADE CENTER"
+ next "COLOSSEUM"
+ next "COLOSSEUM2"
+ next "CANCEL@"
diff --git a/engine/menus/main_menu.asm b/engine/menus/main_menu.asm
index 84af085f..d0e1cc1b 100644
--- a/engine/menus/main_menu.asm
+++ b/engine/menus/main_menu.asm
@@ -34,8 +34,7 @@ MainMenu:
jr z, .noSaveFile
; there's a save file
hlcoord 0, 0
- ld b, 6
- ld c, 13
+ lb bc, 6, 13
call TextBoxBorder
hlcoord 2, 2
ld de, ContinueText
@@ -43,8 +42,7 @@ MainMenu:
jr .next2
.noSaveFile
hlcoord 0, 0
- ld b, 4
- ld c, 13
+ lb bc, 4, 13
call TextBoxBorder
hlcoord 2, 2
ld de, NewGameText
@@ -129,186 +127,21 @@ InitOptions:
ld [wLetterPrintingDelayFlags], a
ld a, TEXT_DELAY_MEDIUM
ld [wOptions], a
+ ld a, 64 ; audio?
+ ld [wPrinterSettings], a
ret
-LinkMenu:
- xor a
- ld [wLetterPrintingDelayFlags], a
- ld hl, wStatusFlags4
- set BIT_LINK_CONNECTED, [hl]
- ld hl, LinkMenuEmptyText
- call PrintText
- call SaveScreenTilesToBuffer1
- ld hl, WhereWouldYouLikeText
- call PrintText
- hlcoord 5, 5
- ld b, $6
- ld c, $d
- call TextBoxBorder
- call UpdateSprites
- hlcoord 7, 7
- ld de, CableClubOptionsText
- call PlaceString
- xor a
- ld [wUnusedLinkMenuByte], a
- ld [wCableClubDestinationMap], a
- ld hl, wTopMenuItemY
- ld a, 7
- ld [hli], a
- ASSERT wTopMenuItemY + 1 == wTopMenuItemX
- ld a, 6
- ld [hli], a
- ASSERT wTopMenuItemX + 1 == wCurrentMenuItem
- xor a
- ld [hli], a
- inc hl
- ASSERT wCurrentMenuItem + 2 == wMaxMenuItem
- ld a, 2
- ld [hli], a
- ASSERT wMaxMenuItem + 1 == wMenuWatchedKeys
- ASSERT 2 + 1 == PAD_A | PAD_B
- inc a
- ld [hli], a
- ASSERT wMenuWatchedKeys + 1 == wLastMenuItem
- xor a
- ld [hl], a
-.waitForInputLoop
- call HandleMenuInput
- and PAD_A | PAD_B
- add a
- add a
- ld b, a
- ld a, [wCurrentMenuItem]
- add b
- add $d0
- ld [wLinkMenuSelectionSendBuffer], a
- ld [wLinkMenuSelectionSendBuffer + 1], a
-.exchangeMenuSelectionLoop
- call Serial_ExchangeLinkMenuSelection
- ld a, [wLinkMenuSelectionReceiveBuffer]
- ld b, a
- and $f0
- cp $d0
- jr z, .checkEnemyMenuSelection
- ld a, [wLinkMenuSelectionReceiveBuffer + 1]
- ld b, a
- and $f0
- cp $d0
- jr nz, .exchangeMenuSelectionLoop
-.checkEnemyMenuSelection
- ld a, b
- and $c ; did the enemy press A or B?
- jr nz, .enemyPressedAOrB
-; the enemy didn't press A or B
- ld a, [wLinkMenuSelectionSendBuffer]
- and $c ; did the player press A or B?
- jr z, .waitForInputLoop ; if neither the player nor the enemy pressed A or B, try again
- jr .doneChoosingMenuSelection ; if the player pressed A or B but the enemy didn't, use the player's selection
-.enemyPressedAOrB
- ld a, [wLinkMenuSelectionSendBuffer]
- and $c ; did the player press A or B?
- jr z, .useEnemyMenuSelection ; if the enemy pressed A or B but the player didn't, use the enemy's selection
-; the enemy and the player both pressed A or B
-; The gameboy that is clocking the connection wins.
- ldh a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- jr z, .doneChoosingMenuSelection
-.useEnemyMenuSelection
- ld a, b
- ld [wLinkMenuSelectionSendBuffer], a
- and $3
- ld [wCurrentMenuItem], a
-.doneChoosingMenuSelection
- ldh a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- jr nz, .skipStartingTransfer
- call DelayFrame
- call DelayFrame
- ld a, SC_START | SC_INTERNAL
- ldh [rSC], a
-.skipStartingTransfer
- ld b, ' '
- ld c, ' '
- ld d, '▷'
- ld a, [wLinkMenuSelectionSendBuffer]
- and PAD_B << 2 ; was B button pressed?
- jr nz, .updateCursorPosition
-; A button was pressed
- ld a, [wCurrentMenuItem]
- cp $2
- jr z, .updateCursorPosition
- ld c, d
- ld d, b
- dec a
- jr z, .updateCursorPosition
- ld b, c
- ld c, d
-.updateCursorPosition
- ld a, b
- ldcoord_a 6, 7
- ld a, c
- ldcoord_a 6, 9
- ld a, d
- ldcoord_a 6, 11
- ld c, 40
- call DelayFrames
- call LoadScreenTilesFromBuffer1
- ld a, [wLinkMenuSelectionSendBuffer]
- and PAD_B << 2 ; was B button pressed?
- jr nz, .choseCancel ; cancel if B pressed
- ld a, [wCurrentMenuItem]
- cp $2
- jr z, .choseCancel
- xor a
- ld [wWalkBikeSurfState], a ; start walking
- ld a, [wCurrentMenuItem]
- and a
- ld a, COLOSSEUM
- jr nz, .next
- ld a, TRADE_CENTER
-.next
- ld [wCableClubDestinationMap], a
- ld hl, PleaseWaitText
- call PrintText
- ld c, 50
- call DelayFrames
- ld hl, wStatusFlags6
- res BIT_DEBUG_MODE, [hl]
- ld a, [wDefaultMap]
- ld [wDestinationMap], a
- call PrepareForSpecialWarp
- ld c, 20
- call DelayFrames
- xor a
- ld [wMenuJoypadPollCount], a
- ld [wSerialExchangeNybbleSendData], a
- inc a ; LINK_STATE_IN_CABLE_CLUB
- ld [wLinkState], a
- ld [wEnteringCableClub], a
- jr SpecialEnterMap
-.choseCancel
- xor a
- ld [wMenuJoypadPollCount], a
- vc_hook Wireless_net_stop
- call Delay3
- call CloseLinkConnection
- ld hl, LinkCanceledText
- vc_hook Wireless_net_end
+Func_5cc1:
+; unused?
+ ld a, $6d
+ cp $80
+ ret c ; will always be executed
+ ld hl, NotEnoughMemoryText
call PrintText
- ld hl, wStatusFlags4
- res BIT_LINK_CONNECTED, [hl]
ret
-WhereWouldYouLikeText:
- text_far _WhereWouldYouLikeText
- text_end
-
-PleaseWaitText:
- text_far _PleaseWaitText
- text_end
-
-LinkCanceledText:
- text_far _LinkCanceledText
+NotEnoughMemoryText:
+ text_far _NotEnoughMemoryText
text_end
StartNewGame:
@@ -320,6 +153,8 @@ StartNewGame:
; fallthrough
StartNewGameDebug:
call OakSpeech
+ ld a, $8
+ ld [wPlayerMovingDirection], a
ld c, 20
call DelayFrames
@@ -335,6 +170,7 @@ SpecialEnterMap::
call ResetPlayerSpriteData
ld c, 20
call DelayFrames
+ call Func_5cc1
ld a, [wEnteringCableClub]
and a
ret nz
@@ -349,17 +185,11 @@ NewGameText:
db "NEW GAME"
next "OPTION@"
-CableClubOptionsText:
- db "TRADE CENTER"
- next "COLOSSEUM"
- next "CANCEL@"
-
DisplayContinueGameInfo:
xor a
ldh [hAutoBGTransferEnabled], a
hlcoord 4, 7
- ld b, 8
- ld c, 14
+ lb bc, 8, 14
call TextBoxBorder
hlcoord 5, 9
ld de, SaveScreenInfoText
@@ -382,8 +212,7 @@ PrintSaveScreenText:
xor a
ldh [hAutoBGTransferEnabled], a
hlcoord 4, 0
- ld b, $8
- ld c, $e
+ lb bc, 8, 14
call TextBoxBorder
call LoadTextBoxTilePatterns
call UpdateSprites
@@ -441,265 +270,10 @@ SaveScreenInfoText:
next "TIME@"
DisplayOptionMenu:
- hlcoord 0, 0
- ld b, 3
- ld c, 18
- call TextBoxBorder
- hlcoord 0, 5
- ld b, 3
- ld c, 18
- call TextBoxBorder
- hlcoord 0, 10
- ld b, 3
- ld c, 18
- call TextBoxBorder
- hlcoord 1, 1
- ld de, TextSpeedOptionText
- call PlaceString
- hlcoord 1, 6
- ld de, BattleAnimationOptionText
- call PlaceString
- hlcoord 1, 11
- ld de, BattleStyleOptionText
- call PlaceString
- hlcoord 2, 16
- ld de, OptionMenuCancelText
- call PlaceString
- xor a
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- ASSERT BIT_FAST_TEXT_DELAY == 0
- inc a ; 1 << BIT_FAST_TEXT_DELAY
- ld [wLetterPrintingDelayFlags], a
- ld [wOptionsCancelCursorX], a
- ld a, 3 ; text speed cursor Y coordinate
- ld [wTopMenuItemY], a
- call SetCursorPositionsFromOptions
- ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
- ld [wTopMenuItemX], a
- ld a, $01
- ldh [hAutoBGTransferEnabled], a ; enable auto background transfer
- call Delay3
-.loop
- call PlaceMenuCursor
- call SetOptionsFromCursorPositions
-.getJoypadStateLoop
- call JoypadLowSensitivity
- ldh a, [hJoy5]
- ld b, a
- and ~PAD_SELECT ; any key besides select pressed?
- jr z, .getJoypadStateLoop
- bit B_PAD_B, b
- jr nz, .exitMenu
- bit B_PAD_START, b
- jr nz, .exitMenu
- bit B_PAD_A, b
- jr z, .checkDirectionKeys
-; A was pressed
- ld a, [wTopMenuItemY]
- cp 16 ; is the cursor on Cancel?
- jr nz, .loop
-.exitMenu
- ld a, SFX_PRESS_AB
- call PlaySound
+ callfar DisplayOptionMenu_
ret
-.eraseOldMenuCursor
- ld [wTopMenuItemX], a
- call EraseMenuCursor
- jp .loop
-.checkDirectionKeys
- ld a, [wTopMenuItemY]
- bit B_PAD_DOWN, b
- jr nz, .downPressed
- bit B_PAD_UP, b
- jr nz, .upPressed
- cp 8 ; cursor in Battle Animation section?
- jr z, .cursorInBattleAnimation
- cp 13 ; cursor in Battle Style section?
- jr z, .cursorInBattleStyle
- cp 16 ; cursor on Cancel?
- jr z, .loop
-; cursor in Text Speed
- bit B_PAD_LEFT, b
- jp nz, .pressedLeftInTextSpeed
- jp .pressedRightInTextSpeed
-.downPressed
- cp 16
- ld b, -13
- ld hl, wOptionsTextSpeedCursorX
- jr z, .updateMenuVariables
- ld b, 5
- cp 3
- inc hl
- jr z, .updateMenuVariables
- cp 8
- inc hl
- jr z, .updateMenuVariables
- ld b, 3
- inc hl
- jr .updateMenuVariables
-.upPressed
- cp 8
- ld b, -5
- ld hl, wOptionsTextSpeedCursorX
- jr z, .updateMenuVariables
- cp 13
- inc hl
- jr z, .updateMenuVariables
- cp 16
- ld b, -3
- inc hl
- jr z, .updateMenuVariables
- ld b, 13
- inc hl
-.updateMenuVariables
- add b
- ld [wTopMenuItemY], a
- ld a, [hl]
- ld [wTopMenuItemX], a
- call PlaceUnfilledArrowMenuCursor
- jp .loop
-.cursorInBattleAnimation
- ld a, [wOptionsBattleAnimCursorX] ; battle animation cursor X coordinate
- xor 1 ^ 10 ; toggle between 1 and 10
- ld [wOptionsBattleAnimCursorX], a
- jp .eraseOldMenuCursor
-.cursorInBattleStyle
- ld a, [wOptionsBattleStyleCursorX] ; battle style cursor X coordinate
- xor 1 ^ 10 ; toggle between 1 and 10
- ld [wOptionsBattleStyleCursorX], a
- jp .eraseOldMenuCursor
-.pressedLeftInTextSpeed
- ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
- cp 1
- jr z, .updateTextSpeedXCoord
- cp 7
- jr nz, .fromSlowToMedium
- sub 6
- jr .updateTextSpeedXCoord
-.fromSlowToMedium
- sub 7
- jr .updateTextSpeedXCoord
-.pressedRightInTextSpeed
- ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
- cp 14
- jr z, .updateTextSpeedXCoord
- cp 7
- jr nz, .fromFastToMedium
- add 7
- jr .updateTextSpeedXCoord
-.fromFastToMedium
- add 6
-.updateTextSpeedXCoord
- ld [wOptionsTextSpeedCursorX], a ; text speed cursor X coordinate
- jp .eraseOldMenuCursor
-
-TextSpeedOptionText:
- db "TEXT SPEED"
- next " FAST MEDIUM SLOW@"
-
-BattleAnimationOptionText:
- db "BATTLE ANIMATION"
- next " ON OFF@"
-
-BattleStyleOptionText:
- db "BATTLE STYLE"
- next " SHIFT SET@"
-
-OptionMenuCancelText:
- db "CANCEL@"
-
-; sets the options variable according to the current placement of the menu cursors in the options menu
-SetOptionsFromCursorPositions:
- ld hl, TextSpeedOptionData
- ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
- ld c, a
-.loop
- ld a, [hli]
- cp c
- jr z, .textSpeedMatchFound
- inc hl
- jr .loop
-.textSpeedMatchFound
- ld a, [hl]
- ld d, a
- ld a, [wOptionsBattleAnimCursorX] ; battle animation cursor X coordinate
- dec a
- jr z, .battleAnimationOn
-; battle animation Off
- set BIT_BATTLE_ANIMATION, d
- jr .checkBattleStyle
-.battleAnimationOn
- res BIT_BATTLE_ANIMATION, d
-.checkBattleStyle
- ld a, [wOptionsBattleStyleCursorX] ; battle style cursor X coordinate
- dec a
- jr z, .battleStyleShift
-; battle style Set
- set BIT_BATTLE_SHIFT, d
- jr .storeOptions
-.battleStyleShift
- res BIT_BATTLE_SHIFT, d
-.storeOptions
- ld a, d
- ld [wOptions], a
- ret
-
-; reads the options variable and places menu cursors in the correct positions within the options menu
-SetCursorPositionsFromOptions:
- ld hl, TextSpeedOptionData + 1
- ld a, [wOptions]
- ld c, a
- and $3f
- push bc
- ld de, 2
- call IsInArray
- pop bc
- dec hl
- ld a, [hl]
- ld [wOptionsTextSpeedCursorX], a ; text speed cursor X coordinate
- hlcoord 0, 3
- call .placeUnfilledRightArrow
- sla c
- ld a, 1 ; On
- jr nc, .storeBattleAnimationCursorX
- ld a, 10 ; Off
-.storeBattleAnimationCursorX
- ld [wOptionsBattleAnimCursorX], a ; battle animation cursor X coordinate
- hlcoord 0, 8
- call .placeUnfilledRightArrow
- sla c
- ld a, 1
- jr nc, .storeBattleStyleCursorX
- ld a, 10
-.storeBattleStyleCursorX
- ld [wOptionsBattleStyleCursorX], a ; battle style cursor X coordinate
- hlcoord 0, 13
- call .placeUnfilledRightArrow
-; cursor in front of Cancel
- hlcoord 0, 16
- ld a, 1
-.placeUnfilledRightArrow
- ld e, a
- ld d, 0
- add hl, de
- ld [hl], '▷'
- ret
-
-; table that indicates how the 3 text speed options affect frame delays
-; Format:
-; 00: X coordinate of menu cursor
-; 01: delay after printing a letter (in frames)
-TextSpeedOptionData:
- db 14, TEXT_DELAY_SLOW
- db 7, TEXT_DELAY_MEDIUM
- db 1, TEXT_DELAY_FAST
- db 7, -1 ; end (default X coordinate)
CheckForPlayerNameInSRAM:
-; Check if the player name data in SRAM has a string terminator character
-; (indicating that a name may have been saved there) and return whether it does
-; in carry.
ld a, RAMG_SRAM_ENABLE
ld [rRAMG], a
ld a, BMODE_ADVANCED
@@ -714,7 +288,6 @@ CheckForPlayerNameInSRAM:
jr z, .found
dec b
jr nz, .loop
-; not found
xor a
ld [rRAMG], a
ld [rBMODE], a
diff --git a/engine/menus/naming_screen.asm b/engine/menus/naming_screen.asm
index 9356cc66..5b4b2415 100644
--- a/engine/menus/naming_screen.asm
+++ b/engine/menus/naming_screen.asm
@@ -5,8 +5,7 @@ AskName:
ld a, [wIsInBattle]
dec a
hlcoord 0, 0
- ld b, 4
- ld c, 11
+ lb bc, 4, 11
call z, ClearScreenArea ; only if in wild battle
ld a, [wCurPartySpecies]
ld [wNamedObjectIndex], a
@@ -94,8 +93,7 @@ DisplayNamingScreen:
call LoadEDTile
farcall LoadMonPartySpriteGfx
hlcoord 0, 4
- ld b, 9
- ld c, 18
+ lb bc, 9, 18
call TextBoxBorder
call PrintNamingText
ld a, 3
@@ -324,11 +322,28 @@ DisplayNamingScreen:
jp EraseMenuCursor
LoadEDTile:
+; In Red/Blue, the bank for the ED_tile was defined incorrectly as bank0
+; Luckily, the MBC3 treats loading $0 into $2000-$2fff range as loading bank1 into $4000-$7fff range
+; Because Yellow uses the MBC5, loading $0 into $2000 - $2fff range will load bank0 instead of bank1 and thus incorrectly load the tile
+; Instead of defining the correct bank, GameFreak decided to simply copy the ED_Tile in the function during HBlank
ld de, ED_Tile
ld hl, vFont tile $70
- ; BUG: BANK("Home") should be BANK(ED_Tile), although it coincidentally works as-is
- lb bc, BANK("Home"), (ED_TileEnd - ED_Tile) / TILE_1BPP_SIZE
- jp CopyVideoDataDouble
+ ld c, $4 ; number of copies needed
+.waitForHBlankLoop
+ ldh a, [rSTAT]
+ and %10 ; in HBlank?
+ jr nz, .waitForHBlankLoop
+ ld a, [de]
+ ld [hli], a
+ ld [hli], a
+ inc de
+ ld a, [de]
+ ld [hli], a
+ ld [hli], a
+ inc de
+ dec c
+ jr nz, .waitForHBlankLoop
+ ret
ED_Tile:
INCBIN "gfx/font/ED.1bpp"
diff --git a/engine/menus/options.asm b/engine/menus/options.asm
new file mode 100644
index 00000000..8505cfac
--- /dev/null
+++ b/engine/menus/options.asm
@@ -0,0 +1,483 @@
+; OptionMenuJumpTable indexes
+ const_def
+ const OPT_TEXT_SPEED ; 0
+ const OPT_BATTLE_ANIMS ; 1
+ const OPT_BATTLE_STYLE ; 2
+ const OPT_SOUND ; 3
+ const OPT_PRINTER ; 4
+ const_skip 2
+ const OPT_CANCEL ; 7
+DEF NUM_OPTIONS EQU const_value ; 8
+
+DisplayOptionMenu_:
+ call InitOptionsMenu
+.optionMenuLoop
+ call JoypadLowSensitivity
+ ldh a, [hJoy5]
+ and PAD_START | PAD_B
+ jr nz, .exitOptionMenu
+ call OptionsControl
+ jr c, .dpadDelay
+ call GetOptionPointer
+ jr c, .exitOptionMenu
+.dpadDelay
+ call OptionsMenu_UpdateCursorPosition
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ jr .optionMenuLoop
+.exitOptionMenu
+ ret
+
+GetOptionPointer:
+ ld a, [wOptionsCursorLocation]
+ ld e, a
+ ld d, 0
+ ld hl, OptionMenuJumpTable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl ; jump to the function for the current highlighted option
+
+OptionMenuJumpTable:
+ dw OptionsMenu_TextSpeed
+ dw OptionsMenu_BattleAnimations
+ dw OptionsMenu_BattleStyle
+ dw OptionsMenu_SpeakerSettings
+ dw OptionsMenu_GBPrinterBrightness
+ dw OptionsMenu_Dummy
+ dw OptionsMenu_Dummy
+ dw OptionsMenu_Cancel
+
+ const_def
+ const OPT_TEXT_SPEED_FAST ; 0
+ const OPT_TEXT_SPEED_MID ; 1
+ const OPT_TEXT_SPEED_SLOW ; 2
+DEF NUM_TEXT_SPEED_OPTS EQU const_value ; 3
+
+OptionsMenu_TextSpeed:
+ call GetTextSpeed
+ ldh a, [hJoy5]
+ bit B_PAD_RIGHT, a
+ jr nz, .pressedRight
+ bit B_PAD_LEFT, a
+ jr nz, .pressedLeft
+ jr .nonePressed
+
+.pressedRight
+ ld a, c
+ cp NUM_TEXT_SPEED_OPTS - 1
+ jr c, .increase
+ ld c, -1
+.increase
+ inc c
+ ld a, e
+ jr .save
+
+.pressedLeft
+ ld a, c
+ and a
+ jr nz, .decrease
+ ld c, NUM_TEXT_SPEED_OPTS
+.decrease
+ dec c
+ ld a, d
+
+.save
+ ld b, a
+ ld a, [wOptions]
+ and ~TEXT_DELAY_MASK
+ or b
+ ld [wOptions], a
+
+.nonePressed
+ ld b, 0
+ ld hl, .Strings
+ add hl, bc
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ hlcoord 14, 2
+ call PlaceString
+ and a ; clear carry flag
+ ret
+
+.Strings:
+; entries correspond to OPT_TEXT_SPEED_* constants
+ dw .Fast
+ dw .Mid
+ dw .Slow
+
+.Fast: db "FAST@"
+.Mid: db "MID @"
+.Slow: db "SLOW@"
+
+; Loads the value of the current selection in c
+; Loads the text delay value of the options
+; to the left in d and to the right in e
+GetTextSpeed:
+ ld a, [wOptions]
+ and TEXT_DELAY_MASK
+ cp TEXT_DELAY_SLOW
+ jr z, .slowTextOption
+ cp TEXT_DELAY_FAST
+ jr z, .fastTextOption
+ ld c, OPT_TEXT_SPEED_MID
+ lb de, TEXT_DELAY_FAST, TEXT_DELAY_SLOW
+ ret
+
+.slowTextOption
+ ld c, OPT_TEXT_SPEED_SLOW
+ lb de, TEXT_DELAY_MEDIUM, TEXT_DELAY_FAST
+ ret
+
+.fastTextOption
+ ld c, OPT_TEXT_SPEED_FAST
+ lb de, TEXT_DELAY_SLOW, TEXT_DELAY_MEDIUM
+ ret
+
+OptionsMenu_BattleAnimations:
+ ldh a, [hJoy5]
+ and PAD_LEFT | PAD_RIGHT
+ jr nz, .buttonPressed
+ ld a, [wOptions]
+ and 1 << BIT_BATTLE_ANIMATION
+ jr .nothingPressed
+
+.buttonPressed
+ ld a, [wOptions]
+ xor 1 << BIT_BATTLE_ANIMATION
+ ld [wOptions], a
+
+.nothingPressed
+ ld bc, 0
+ sla a
+ rl c
+ ld hl, .Strings
+ add hl, bc
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ hlcoord 14, 4
+ call PlaceString
+ and a ; clear carry flag
+ ret
+
+.Strings:
+ dw .On
+ dw .Off
+
+.On: db "ON @"
+.Off: db "OFF@"
+
+OptionsMenu_BattleStyle:
+ ldh a, [hJoy5]
+ and PAD_LEFT | PAD_RIGHT
+ jr nz, .buttonPressed
+ ld a, [wOptions]
+ and 1 << BIT_BATTLE_SHIFT
+ jr .nothingPressed
+
+.buttonPressed
+ ld a, [wOptions]
+ xor 1 << BIT_BATTLE_SHIFT
+ ld [wOptions], a
+
+.nothingPressed
+ ld bc, 0
+ sla a
+ sla a
+ rl c
+ ld hl, .Strings
+ add hl, bc
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ hlcoord 14, 6
+ call PlaceString
+ and a ; clear carry flag
+ ret
+
+.Strings:
+ dw .Shift
+ dw .Set
+
+.Shift: db "SHIFT@"
+.Set: db "SET @"
+
+OptionsMenu_SpeakerSettings:
+ ld a, [wOptions]
+ and SOUND_MASK
+ swap a ; move sound option bits (4–5) into bits 0–1
+ ld c, a
+ ldh a, [hJoy5]
+ bit B_PAD_RIGHT, a
+ jr nz, .pressedRight
+ bit B_PAD_LEFT, a
+ jr nz, .pressedLeft
+ jr .nothingPressed
+
+.pressedRight
+ ld a, c
+ inc a
+ and SOUND_MASK >> 4
+ jr .save
+
+.pressedLeft
+ ld a, c
+ dec a
+ and SOUND_MASK >> 4
+
+.save
+ ld c, a
+ swap a
+ ld b, a
+ xor a
+ ldh [rAUDTERM], a
+ ld a, [wOptions]
+ and ~SOUND_MASK
+ or b
+ ld [wOptions], a
+
+.nothingPressed
+ ld b, 0
+ ld hl, .Strings
+ add hl, bc
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ hlcoord 8, 8
+ call PlaceString
+ and a ; clear carry flag
+ ret
+
+.Strings:
+ dw .Mono
+ dw .Earphone1
+ dw .Earphone2
+ dw .Earphone3
+
+.Mono: db "MONO @"
+.Earphone1: db "EARPHONE1@"
+.Earphone2: db "EARPHONE2@"
+.Earphone3: db "EARPHONE3@"
+
+ const_def
+ const OPT_PRINTER_LIGHTEST ; 0
+ const OPT_PRINTER_LIGHTER ; 1
+ const OPT_PRINTER_NORMAL ; 2
+ const OPT_PRINTER_DARKER ; 3
+ const OPT_PRINTER_DARKEST ; 4
+DEF NUM_PRINTER_OPTS EQU const_value ; 5
+
+OptionsMenu_GBPrinterBrightness:
+ call GetGBPrinterBrightness
+ ldh a, [hJoy5]
+ bit B_PAD_RIGHT, a
+ jr nz, .pressedRight
+ bit B_PAD_LEFT, a
+ jr nz, .pressedLeft
+ jr .nothingPressed
+
+.pressedRight
+ ld a, c
+ cp NUM_PRINTER_OPTS - 1
+ jr c, .increase
+ ld c, -1
+.increase
+ inc c
+ ld a, e
+ jr .save
+
+.pressedLeft
+ ld a, c
+ and a
+ jr nz, .decrease
+ ld c, NUM_PRINTER_OPTS
+.decrease
+ dec c
+ ld a, d
+
+.save
+ ld b, a
+ ld [wPrinterSettings], a
+
+.nothingPressed
+ ld b, 0
+ ld hl, .Strings
+ add hl, bc
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ hlcoord 8, 10
+ call PlaceString
+ and a ; clear carry flag
+ ret
+
+.Strings:
+ dw .Lightest
+ dw .Lighter
+ dw .Normal
+ dw .Darker
+ dw .Darkest
+
+.Lightest: db "LIGHTEST@"
+.Lighter: db "LIGHTER @"
+.Normal: db "NORMAL @"
+.Darker: db "DARKER @"
+.Darkest: db "DARKEST @"
+
+; Loads the value of the current selection in c
+; Loads the brightness value of the options
+; to the left in d and to the right in e
+GetGBPrinterBrightness:
+ ld a, [wPrinterSettings]
+ and a ; cp PRINTER_BRIGHTNESS_LIGHTEST
+ jr z, .setLightest
+ cp PRINTER_BRIGHTNESS_LIGHTER
+ jr z, .setLighter
+ cp PRINTER_BRIGHTNESS_DARKER
+ jr z, .setDarker
+ cp PRINTER_BRIGHTNESS_DARKEST
+ jr z, .setDarkest
+ ld c, OPT_PRINTER_NORMAL
+ lb de, PRINTER_BRIGHTNESS_LIGHTER, PRINTER_BRIGHTNESS_DARKER
+ ret
+
+.setLightest
+ ld c, OPT_PRINTER_LIGHTEST
+ lb de, PRINTER_BRIGHTNESS_DARKEST, PRINTER_BRIGHTNESS_LIGHTER
+ ret
+
+.setLighter
+ ld c, OPT_PRINTER_LIGHTER
+ lb de, PRINTER_BRIGHTNESS_LIGHTEST, PRINTER_BRIGHTNESS_NORMAL
+ ret
+
+.setDarker
+ ld c, OPT_PRINTER_DARKER
+ lb de, PRINTER_BRIGHTNESS_NORMAL, PRINTER_BRIGHTNESS_DARKEST
+ ret
+
+.setDarkest
+ ld c, OPT_PRINTER_DARKEST
+ lb de, PRINTER_BRIGHTNESS_DARKER, PRINTER_BRIGHTNESS_LIGHTEST
+ ret
+
+OptionsMenu_Dummy:
+ and a ; clear carry flag
+ ret
+
+OptionsMenu_Cancel:
+ ldh a, [hJoy5]
+ and PAD_A
+ jr nz, .pressedCancel
+ and a ; clear carry flag
+ ret
+
+.pressedCancel
+ scf
+ ret
+
+OptionsControl:
+ ld hl, wOptionsCursorLocation
+ ldh a, [hJoy5]
+ cp PAD_DOWN
+ jr z, .pressedDown
+ cp PAD_UP
+ jr z, .pressedUp
+ and a ; clear carry flag
+ ret
+
+.pressedDown
+ ld a, [hl]
+ cp NUM_OPTIONS - 1
+ jr nz, .doNotWrap
+ ld [hl], 0
+ scf
+ ret
+.doNotWrap
+ cp OPT_PRINTER ; skip the next two dummy options
+ jr c, .increase
+ ld [hl], OPT_CANCEL - 1 ; Cancel is after Print
+.increase
+ inc [hl]
+ scf
+ ret
+
+.pressedUp
+ ld a, [hl]
+ cp OPT_CANCEL ; skip the previous two dummy options
+ jr nz, .doNotSkip
+ ld [hl], OPT_PRINTER ; Print is before Cancel
+ scf
+ ret
+.doNotSkip
+ and a
+ jr nz, .decrease
+ ld [hl], NUM_OPTIONS
+.decrease
+ dec [hl]
+ scf
+ ret
+
+OptionsMenu_UpdateCursorPosition:
+ hlcoord 1, 1
+ ld de, SCREEN_WIDTH
+ ld c, 16
+.loop
+ ld [hl], ' '
+ add hl, de
+ dec c
+ jr nz, .loop
+ hlcoord 1, 2
+ ld bc, SCREEN_WIDTH * 2
+ ld a, [wOptionsCursorLocation]
+ call AddNTimes
+ ld [hl], '▶'
+ ret
+
+InitOptionsMenu:
+ hlcoord 0, 0
+ lb bc, SCREEN_HEIGHT - 2, SCREEN_WIDTH - 2
+ call TextBoxBorder
+ hlcoord 2, 2
+ ld de, AllOptionsText
+ call PlaceString
+ hlcoord 2, 16
+ ld de, OptionMenuCancelText
+ call PlaceString
+ xor a
+ ld [wOptionsCursorLocation], a
+ ld c, 5 ; the number of options to loop through
+.loop
+ push bc
+ call GetOptionPointer ; updates the next option
+ pop bc
+ ld hl, wOptionsCursorLocation
+ inc [hl] ; moves the cursor for the highlighted option
+ dec c
+ jr nz, .loop
+ xor a
+ ld [wOptionsCursorLocation], a
+ inc a
+ ldh [hAutoBGTransferEnabled], a
+ call Delay3
+ ret
+
+AllOptionsText:
+ db "TEXT SPEED :"
+ next "ANIMATION :"
+ next "BATTLESTYLE:"
+ next "SOUND:"
+ next "PRINT:@"
+
+OptionMenuCancelText:
+ db "CANCEL@"
diff --git a/engine/menus/party_menu.asm b/engine/menus/party_menu.asm
index 15fd62be..24d2aa13 100644
--- a/engine/menus/party_menu.asm
+++ b/engine/menus/party_menu.asm
@@ -30,9 +30,17 @@ RedrawPartyMenu_::
call GetPartyMonName
pop hl
call PlaceString ; print the pokemon's name
- farcall WriteMonPartySpriteOAMByPartyIndex ; place the appropriate pokemon icon
ldh a, [hPartyMonIndex]
ld [wWhichPokemon], a
+ callfar IsThisPartyMonStarterPikachu
+ jr nc, .regularMon
+ call CheckPikachuFollowingPlayer
+ jr z, .regularMon
+ ld a, $ff
+ ldh [hPartyMonIndex], a
+.regularMon
+ farcall WriteMonPartySpriteOAMByPartyIndex ; place the appropriate pokemon icon
+ ld a, [wWhichPokemon]
inc a
ldh [hPartyMonIndex], a
call LoadMonData
@@ -90,8 +98,8 @@ RedrawPartyMenu_::
jr nz, .placeMoveLearnabilityString
ld de, .notAbleToLearnMoveText
.placeMoveLearnabilityString
- ld bc, SCREEN_WIDTH + 9 ; 1 row down and 9 columns right
push hl
+ ld bc, 20 + 9 ; down 1 row and right 9 columns
add hl, bc
call PlaceString
pop hl
@@ -157,9 +165,9 @@ RedrawPartyMenu_::
; if it does match
ld de, .ableToEvolveText
.placeEvolutionStoneString
- ld bc, 20 + 9 ; down 1 row and right 9 columns
pop hl
push hl
+ ld bc, 20 + 9 ; down 1 row and right 9 columns
add hl, bc
call PlaceString
pop hl
diff --git a/engine/menus/players_pc.asm b/engine/menus/players_pc.asm
index f2b7770b..01d13afa 100644
--- a/engine/menus/players_pc.asm
+++ b/engine/menus/players_pc.asm
@@ -1,6 +1,4 @@
PlayerPC::
- ld hl, wStatusFlags5
- set BIT_NO_TEXT_DELAY, [hl]
ld a, ITEM_NAME
ld [wNameListType], a
call SaveScreenTilesToBuffer1
@@ -17,14 +15,15 @@ PlayerPC::
call PrintText
PlayerPCMenu:
+ ld hl, wStatusFlags5
+ set BIT_NO_TEXT_DELAY, [hl]
ld a, [wParentMenuItem]
ld [wCurrentMenuItem], a
ld hl, wMiscFlags
set BIT_NO_MENU_BUTTON_SOUND, [hl]
call LoadScreenTilesFromBuffer2
hlcoord 0, 0
- ld b, $8
- ld c, $e
+ lb bc, 8, 14
call TextBoxBorder
call UpdateSprites
hlcoord 2, 2
diff --git a/engine/menus/pokedex.asm b/engine/menus/pokedex.asm
index 3d2fcbca..dcf55820 100644
--- a/engine/menus/pokedex.asm
+++ b/engine/menus/pokedex.asm
@@ -12,9 +12,10 @@ ShowPokedexMenu:
ld [wPokedexNum], a
ldh [hJoy7], a
.setUpGraphics
+ callfar LoadPokedexTilePatterns
+.loop
ld b, SET_PAL_GENERIC
call RunPaletteCommand
- callfar LoadPokedexTilePatterns
.doPokemonListMenu
ld hl, wTopMenuItemY
ld a, 3
@@ -43,12 +44,15 @@ ShowPokedexMenu:
call GBPalWhiteOutWithDelay3
call RunDefaultPaletteCommand
jp ReloadMapData
+
.goToSideMenu
call HandlePokedexSideMenu
dec b
jr z, .exitPokedex ; if the player chose Quit
dec b
jr z, .doPokemonListMenu ; if pokemon not seen or player pressed B button
+ dec b
+ jr z, .loop
jp .setUpGraphics ; if pokemon data or area was shown
; handles the menu on the lower right in the pokedex screen
@@ -79,20 +83,21 @@ HandlePokedexSideMenu:
jr z, .exitSideMenu
call PokedexToIndex
ld hl, wTopMenuItemY
- ld a, 10
+ ld a, 8
ld [hli], a ; top menu item Y
ld a, 15
ld [hli], a ; top menu item X
xor a
ld [hli], a ; current menu item ID
inc hl
- ld a, 3
+ ld a, 4
ld [hli], a ; max menu item ID
- ;ld a, PAD_A | PAD_B
+ ld a, PAD_A | PAD_B
ld [hli], a ; menu watched keys (A button and B button)
xor a
ld [hli], a ; old menu item ID
ld [wMenuWatchMovingOutOfBounds], a
+ ldh [hJoy7], a
.handleMenuInput
call HandleMenuInput
bit B_PAD_B, a
@@ -105,6 +110,14 @@ HandlePokedexSideMenu:
jr z, .choseCry
dec a
jr z, .choseArea
+ dec a
+ vc_patch Forbid_printing_Pokedex
+IF DEF (_YELLOW_VC)
+ jr z, .handleMenuInput
+ELSE
+ jr z, .chosePrint
+ENDC
+ vc_patch_end
; chose Quit
ld b, 1
.exitSideMenu
@@ -118,6 +131,8 @@ HandlePokedexSideMenu:
ld [wLastMenuItem], a
pop af
ld [wCurrentMenuItem], a
+ ld a, $1
+ ldh [hJoy7], a
push bc
hlcoord 0, 3
ld de, 20
@@ -128,9 +143,9 @@ HandlePokedexSideMenu:
.buttonBPressed
push bc
- hlcoord 15, 10
+ hlcoord 15, 8
ld de, 20
- lb bc, ' ', 7
+ lb bc, ' ', 9
call DrawTileLine ; cover up the menu cursor in the side menu
pop bc
jr .exitSideMenu
@@ -152,13 +167,105 @@ HandlePokedexSideMenu:
ld b, 0
jr .exitSideMenu
+.chosePrint
+ ldh a, [hTileAnimations]
+ push af
+ xor a
+ ldh [hTileAnimations], a
+ ld a, [wPokedexNum]
+ ld [wCurPartySpecies], a
+ callfar PrintPokedexEntry
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call ClearScreen
+ pop af
+ ldh [hTileAnimations], a
+ ld b, $3
+ jr .exitSideMenu
+
; handles the list of pokemon on the left of the pokedex screen
; sets carry flag if player presses A, unsets carry flag if player presses B
HandlePokedexListMenu:
+ call Pokedex_DrawInterface
+.loop
+ call Pokedex_PlacePokemonList
+ call GBPalNormal
+ call HandleMenuInput
+ bit B_PAD_B, a ; was the B button pressed?
+ jp nz, .buttonBPressed
+ bit B_PAD_A, a ; was the A button pressed?
+ jp nz, .buttonAPressed
+.checkIfUpPressed
+ bit B_PAD_UP, a ; was Up pressed?
+ jr z, .checkIfDownPressed
+.upPressed ; scroll up one row
+ ld a, [wListScrollOffset]
+ and a
+ jp z, .loop
+ dec a
+ ld [wListScrollOffset], a
+ jp .loop
+
+.checkIfDownPressed
+ bit B_PAD_DOWN, a ; was Down pressed?
+ jr z, .checkIfRightPressed
+.downPressed ; scroll down one row
+ ld a, [wDexMaxSeenMon]
+ cp 7
+ jp c, .loop ; can't if the list is shorter than 7
+ sub 7
+ ld b, a
+ ld a, [wListScrollOffset]
+ cp b
+ jp z, .loop
+ inc a
+ ld [wListScrollOffset], a
+ jp .loop
+
+.checkIfRightPressed
+ bit B_PAD_RIGHT, a ; was Right pressed?
+ jr z, .checkIfLeftPressed
+.rightPressed ; scroll down 7 rows
+ ld a, [wDexMaxSeenMon]
+ cp 7
+ jp c, .loop ; can't if the list is shorter than 7
+ sub 6
+ ld b, a
+ ld a, [wListScrollOffset]
+ add 7
+ ld [wListScrollOffset], a
+ cp b
+ jp c, .loop
+ dec b
+ ld a, b
+ ld [wListScrollOffset], a
+ jp .loop
+
+.checkIfLeftPressed ; scroll up 7 rows
+ bit B_PAD_LEFT, a ; was Left pressed?
+ jr z, .buttonAPressed
+.leftPressed
+ ld a, [wListScrollOffset]
+ sub 7
+ ld [wListScrollOffset], a
+ jp nc, .loop
+ xor a
+ ld [wListScrollOffset], a
+ jp .loop
+
+.buttonAPressed
+ scf
+ ret
+
+.buttonBPressed
+ and a
+ ret
+
+Pokedex_DrawInterface:
xor a
ldh [hAutoBGTransferEnabled], a
; draw the horizontal line separating the seen and owned amounts from the menu
- hlcoord 15, 8
+ hlcoord 15, 6
ld a, '─'
ld [hli], a
ld [hli], a
@@ -175,26 +282,26 @@ HandlePokedexListMenu:
ld b, wPokedexSeenEnd - wPokedexSeen
call CountSetBits
ld de, wNumSetBits
- hlcoord 16, 3
+ hlcoord 16, 2
lb bc, 1, 3
call PrintNumber ; print number of seen pokemon
ld hl, wPokedexOwned
ld b, wPokedexOwnedEnd - wPokedexOwned
call CountSetBits
ld de, wNumSetBits
- hlcoord 16, 6
+ hlcoord 16, 5
lb bc, 1, 3
call PrintNumber ; print number of owned pokemon
- hlcoord 16, 2
+ hlcoord 16, 1
ld de, PokedexSeenText
call PlaceString
- hlcoord 16, 5
+ hlcoord 16, 4
ld de, PokedexOwnText
call PlaceString
hlcoord 1, 1
ld de, PokedexContentsText
call PlaceString
- hlcoord 16, 10
+ hlcoord 16, 8
ld de, PokedexMenuItemsText
call PlaceString
; find the highest pokedex number among the pokemon the player has seen
@@ -214,7 +321,37 @@ HandlePokedexListMenu:
.storeMaxSeenPokemon
ld a, b
ld [wDexMaxSeenMon], a
+ ret
+
+DrawPokedexVerticalLine:
+ ld c, 9 ; height of line
+ ld de, SCREEN_WIDTH ; width of screen
+ ld a, $71 ; vertical line tile
.loop
+ ld [hl], a
+ add hl, de
+ xor 1 ; toggle between vertical line tile and box tile
+ dec c
+ jr nz, .loop
+ ret
+
+PokedexSeenText:
+ db "SEEN@"
+
+PokedexOwnText:
+ db "OWN@"
+
+PokedexContentsText:
+ db "CONTENTS@"
+
+PokedexMenuItemsText:
+ db "DATA"
+ next "CRY"
+ next "AREA"
+ next "PRNT"
+ next "QUIT@"
+
+Pokedex_PlacePokemonList:
xor a
ldh [hAutoBGTransferEnabled], a
hlcoord 4, 2
@@ -282,98 +419,8 @@ HandlePokedexListMenu:
ld a, 01
ldh [hAutoBGTransferEnabled], a
call Delay3
- call GBPalNormal
- call HandleMenuInput
- bit B_PAD_B, a
- jp nz, .buttonBPressed
-; check if Up pressed
- bit B_PAD_UP, a
- jr z, .checkIfDownPressed
-.upPressed ; scroll up one row
- ld a, [wListScrollOffset]
- and a
- jp z, .loop
- dec a
- ld [wListScrollOffset], a
- jp .loop
-.checkIfDownPressed
- bit B_PAD_DOWN, a
- jr z, .checkIfRightPressed
-; Down pressed, scroll down one row
- ld a, [wDexMaxSeenMon]
- cp 7
- jp c, .loop ; can't if the list is shorter than 7
- sub 7
- ld b, a
- ld a, [wListScrollOffset]
- cp b
- jp z, .loop
- inc a
- ld [wListScrollOffset], a
- jp .loop
-.checkIfRightPressed
- bit B_PAD_RIGHT, a
- jr z, .checkIfLeftPressed
-; Right pressed, scroll down 7 rows
- ld a, [wDexMaxSeenMon]
- cp 7
- jp c, .loop ; can't if the list is shorter than 7
- sub 6
- ld b, a
- ld a, [wListScrollOffset]
- add 7
- ld [wListScrollOffset], a
- cp b
- jp c, .loop
- dec b
- ld a, b
- ld [wListScrollOffset], a
- jp .loop
-.checkIfLeftPressed ; scroll up 7 rows
- bit B_PAD_LEFT, a
- jr z, .buttonAPressed
-; Left pressed
- ld a, [wListScrollOffset]
- sub 7
- ld [wListScrollOffset], a
- jp nc, .loop
- xor a
- ld [wListScrollOffset], a
- jp .loop
-.buttonAPressed
- scf
- ret
-.buttonBPressed
- and a
ret
-DrawPokedexVerticalLine:
- ld c, 9 ; height of line
- ld de, SCREEN_WIDTH
- ld a, $71 ; vertical line tile
-.loop
- ld [hl], a
- add hl, de
- xor 1 ; toggle between vertical line tile and box tile
- dec c
- jr nz, .loop
- ret
-
-PokedexSeenText:
- db "SEEN@"
-
-PokedexOwnText:
- db "OWN@"
-
-PokedexContentsText:
- db "CONTENTS@"
-
-PokedexMenuItemsText:
- db "DATA"
- next "CRY"
- next "AREA"
- next "QUIT@"
-
; tests if a pokemon's bit is set in the seen or owned pokemon bit fields
; INPUT:
; [wPokedexNum] = pokedex number
@@ -401,8 +448,11 @@ ShowPokedexDataInternal:
set BIT_NO_AUDIO_FADE_OUT, [hl]
ld a, $33 ; 3/7 volume
ldh [rAUDVOL], a
+ ldh a, [hTileAnimations]
+ push af
+ xor a
+ ldh [hTileAnimations], a
call GBPalWhiteOut ; zero all palettes
- call ClearScreen
ld a, [wPokedexNum]
ld [wCurPartySpecies], a
push af
@@ -410,10 +460,42 @@ ShowPokedexDataInternal:
call RunPaletteCommand
pop af
ld [wPokedexNum], a
- ldh a, [hTileAnimations]
- push af
- xor a
+ call DrawDexEntryOnScreen
+ call c, Pokedex_PrintFlavorTextAtRow11
+.waitForButtonPress
+ call JoypadLowSensitivity
+ ldh a, [hJoy5]
+ and PAD_A | PAD_B
+ jr z, .waitForButtonPress
+ pop af
ldh [hTileAnimations], a
+ call GBPalWhiteOut
+ call ClearScreen
+ call RunDefaultPaletteCommand
+ call LoadTextBoxTilePatterns
+ call GBPalNormal
+ ld hl, wStatusFlags2
+ res BIT_NO_AUDIO_FADE_OUT, [hl]
+ ld a, $77 ; max volume
+ ldh [rAUDVOL], a
+ ret
+
+HeightWeightText:
+ db "HT ?′??″"
+ next "WT ???lb@"
+
+; leftover from JPN Pokedex, where species have the suffix "Pokemon"
+PokeText: ; unreferenced
+ db "#@"
+
+; horizontal line that divides the pokedex text description from the rest of the data
+PokedexDataDividerLine:
+ db $68, $69, $6B, $69, $6B, $69, $6B, $69, $6B, $6B
+ db $6B, $6B, $69, $6B, $69, $6B, $69, $6B, $69, $6A
+ db "@"
+
+DrawDexEntryOnScreen:
+ call ClearScreen
hlcoord 0, 0
ld de, 1
@@ -512,7 +594,8 @@ ShowPokedexDataInternal:
ld a, c
and a
- jp z, .waitForButtonPress ; if the pokemon has not been owned, don't print the height, weight, or description
+ ret z ; if the pokemon has not been owned, don't print the height, weight, or description
+
inc de ; de = address of feet (height)
ld a, [de] ; reads feet, but a is overwritten without being used
hlcoord 12, 6
@@ -565,43 +648,48 @@ ShowPokedexDataInternal:
ldh [hDexWeight], a ; restore original value of [hDexWeight]
pop hl
inc hl ; hl = address of pokedex description text
+ scf
+ ret
+
+Pokedex_PrintFlavorTextAtRow11:
bccoord 1, 11
+Pokedex_PrintFlavorTextAtBC:
ld a, %10
ldh [hClearLetterPrintingDelayFlags], a
call TextCommandProcessor ; print pokedex description text
xor a
ldh [hClearLetterPrintingDelayFlags], a
-.waitForButtonPress
- call JoypadLowSensitivity
- ldh a, [hJoy5]
- and PAD_A | PAD_B
- jr z, .waitForButtonPress
- pop af
- ldh [hTileAnimations], a
- call GBPalWhiteOut
- call ClearScreen
- call RunDefaultPaletteCommand
- call LoadTextBoxTilePatterns
- call GBPalNormal
- ld hl, wStatusFlags2
- res BIT_NO_AUDIO_FADE_OUT, [hl]
- ld a, $77 ; max volume
- ldh [rAUDVOL], a
ret
-HeightWeightText:
- db "HT ?′??″"
- next "WT ???lb@"
-
-; leftover from JPN Pokedex, where species have the suffix "Pokemon"
-PokeText: ; unreferenced
- db "#@"
-
-; horizontal line that divides the pokedex text description from the rest of the data
-PokedexDataDividerLine:
- db $68, $69, $6B, $69, $6B, $69, $6B, $69, $6B, $6B
- db $6B, $6B, $69, $6B, $69, $6B, $69, $6B, $69, $6A
- db "@"
+Pokedex_PrepareDexEntryForPrinting:
+ hlcoord 0, 0
+ ld de, SCREEN_WIDTH
+ lb bc, $66, $d
+ call DrawTileLine
+ hlcoord 19, 0
+ ld b, $67
+ call DrawTileLine
+ hlcoord 0, 13
+ ld de, $1
+ lb bc, $6f, SCREEN_WIDTH
+ call DrawTileLine
+ ld a, $6c
+ ldcoord_a 0, 13
+ ld a, $6e
+ ldcoord_a 19, 13
+ ld a, [wPrinterPokedexEntryTextPointer]
+ ld l, a
+ ld a, [wPrinterPokedexEntryTextPointer + 1]
+ ld h, a
+ bccoord 1, 1
+ ldh a, [hUILayoutFlags]
+ set BIT_PAGE_CHAR_IS_NEXT, a
+ ldh [hUILayoutFlags], a
+ call Pokedex_PrintFlavorTextAtBC
+ ldh a, [hUILayoutFlags]
+ res BIT_PAGE_CHAR_IS_NEXT, a
+ ldh [hUILayoutFlags], a
+ ret
; draws a line of tiles
; INPUT:
diff --git a/engine/menus/save.asm b/engine/menus/save.asm
index 3fab0d01..bc427936 100644
--- a/engine/menus/save.asm
+++ b/engine/menus/save.asm
@@ -30,11 +30,8 @@ FileDataDestroyedText:
text_end
LoadMainData:
- ld a, RAMG_SRAM_ENABLE
- ld [rRAMG], a
- ld a, BMODE_ADVANCED
- ld [rBMODE], a
- ASSERT BANK("Save Data") == BMODE_ADVANCED
+ call EnableSRAM
+ ld a, BANK("Save Data")
ld [rRAMB], a
; This vc_hook does not have to be in any particular location.
; It is defined here because it refers to the same labels as the two lines below.
@@ -84,11 +81,8 @@ LoadMainData:
jp GoodCheckSum
LoadCurrentBoxData:
- ld a, RAMG_SRAM_ENABLE
- ld [rRAMG], a
- ld a, BMODE_ADVANCED
- ld [rBMODE], a
- ASSERT BANK("Save Data") == BMODE_ADVANCED
+ call EnableSRAM
+ ld a, BANK("Save Data")
ld [rRAMB], a
ld hl, sGameData
ld bc, sGameDataEnd - sGameData
@@ -105,11 +99,8 @@ LoadCurrentBoxData:
jp GoodCheckSum
LoadPartyAndDexData:
- ld a, RAMG_SRAM_ENABLE
- ld [rRAMG], a
- ld a, BMODE_ADVANCED
- ld [rBMODE], a
- ASSERT BANK("Save Data") == BMODE_ADVANCED
+ call EnableSRAM
+ ld a, BANK("Save Data")
ld [rRAMB], a
ld hl, sGameData
ld bc, sGameDataEnd - sGameData
@@ -134,10 +125,7 @@ CheckSumFailed:
; fallthrough
GoodCheckSum:
- ld a, BMODE_SIMPLE ; preserve flags
- ld [rBMODE], a
- ASSERT RAMG_SRAM_DISABLE == BMODE_SIMPLE
- ld [rRAMG], a
+ call DisableSRAM
ret
TryLoadSaveFileIgnoreChecksum: ; unreferenced
@@ -149,12 +137,16 @@ TryLoadSaveFileIgnoreChecksum: ; unreferenced
SaveMenu:
farcall PrintSaveScreenText
+ ld c, 10
+ call DelayFrames
ld hl, WouldYouLikeToSaveText
call SaveTheGame_YesOrNo
and a ;|0 = Yes|1 = No|
ret nz
+ ld c, 10
+ call DelayFrames
ld a, [wSaveFileStatus]
- dec a
+ cp $1
jr z, .save
call CheckPreviousSaveFile
jr z, .save
@@ -164,24 +156,20 @@ SaveMenu:
ret nz
.save
call SaveGameData
- hlcoord 1, 13
- lb bc, 4, 18
- call ClearScreenArea
- hlcoord 1, 14
- ld de, NowSavingString
- call PlaceString
- ld c, 120
+ ld hl, SavingText
+ call PrintText
+ ld c, 128
call DelayFrames
ld hl, GameSavedText
call PrintText
+ ld c, 10
+ call DelayFrames
ld a, SFX_SAVE
call PlaySoundWaitForCurrent
call WaitForSoundToFinish
ld c, 30
- jp DelayFrames
-
-NowSavingString:
- db "Now saving...@"
+ call DelayFrames
+ ret
SaveTheGame_YesOrNo:
call PrintText
@@ -197,6 +185,10 @@ WouldYouLikeToSaveText:
text_far _WouldYouLikeToSaveText
text_end
+SavingText:
+ text_far _SavingText
+ text_end
+
GameSavedText:
text_far _GameSavedText
text_end
@@ -206,11 +198,8 @@ OlderFileWillBeErasedText:
text_end
SaveMainData:
- ld a, RAMG_SRAM_ENABLE
- ld [rRAMG], a
- ld a, BMODE_ADVANCED
- ld [rBMODE], a
- ASSERT BANK("Save Data") == BMODE_ADVANCED
+ call EnableSRAM
+ ld a, BANK("Save Data")
ld [rRAMB], a
ld hl, wPlayerName
@@ -238,17 +227,12 @@ SaveMainData:
ld bc, sGameDataEnd - sGameData
call CalcCheckSum
ld [sMainDataCheckSum], a
- xor a
- ld [rBMODE], a
- ld [rRAMG], a
+ call DisableSRAM
ret
SaveCurrentBoxData:
- ld a, RAMG_SRAM_ENABLE
- ld [rRAMG], a
- ld a, BMODE_ADVANCED
- ld [rBMODE], a
- ASSERT BANK("Save Data") == BMODE_ADVANCED
+ call EnableSRAM
+ ld a, BANK("Save Data")
ld [rRAMB], a
ld hl, wBoxDataStart
ld de, sCurBoxData
@@ -258,17 +242,12 @@ SaveCurrentBoxData:
ld bc, sGameDataEnd - sGameData
call CalcCheckSum
ld [sMainDataCheckSum], a
- xor a
- ld [rBMODE], a
- ld [rRAMG], a
+ call DisableSRAM
ret
SavePartyAndDexData:
- ld a, RAMG_SRAM_ENABLE
- ld [rRAMG], a
- ld a, BMODE_ADVANCED
- ld [rBMODE], a
- ASSERT BANK("Save Data") == BMODE_ADVANCED
+ call EnableSRAM
+ ld a, BANK("Save Data")
ld [rRAMB], a
ld hl, wPartyDataStart
ld de, sPartyData
@@ -278,13 +257,18 @@ SavePartyAndDexData:
ld de, sMainData
ld bc, wPokedexSeenEnd - wPokedexOwned
call CopyData
+ ld hl, wPikachuHappiness
+ ld de, sMainData + (wPikachuHappiness - wMainDataStart)
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
ld hl, sGameData
ld bc, sGameDataEnd - sGameData
call CalcCheckSum
ld [sMainDataCheckSum], a
- xor a
- ld [rBMODE], a
- ld [rRAMG], a
+ call DisableSRAM
ret
SaveGameData::
@@ -374,6 +358,9 @@ ChangeBox::
res BIT_DOUBLE_SPACED_MENU, [hl]
bit B_PAD_B, a
ret nz
+ ld a, SFX_SAVE
+ call PlaySoundWaitForCurrent
+ call WaitForSoundToFinish
call GetBoxSRAMLocation
ld e, l
ld d, h
@@ -396,9 +383,6 @@ ChangeBox::
call SaveGameData
ld hl, wChangeBoxSavedMapTextPointer
call SetMapTextPointer
- ld a, SFX_SAVE
- call PlaySoundWaitForCurrent
- call WaitForSoundToFinish
ret
WhenYouChangeBoxText:
@@ -408,10 +392,7 @@ WhenYouChangeBoxText:
CopyBoxToOrFromSRAM:
; copy an entire box from hl to de with b as the SRAM bank
push hl
- ld a, RAMG_SRAM_ENABLE
- ld [rRAMG], a
- ld a, BMODE_ADVANCED
- ld [rBMODE], a
+ call EnableSRAM
ld a, b
ld [rRAMB], a
ld bc, wBoxDataEnd - wBoxDataStart
@@ -429,9 +410,7 @@ CopyBoxToOrFromSRAM:
call CalcCheckSum
ld [sBank2AllBoxesChecksum], a ; sBank3AllBoxesChecksum
call CalcIndividualBoxCheckSums
- xor a
- ld [rBMODE], a
- ld [rRAMG], a
+ call DisableSRAM
ret
DisplayChangeBoxMenu:
@@ -452,14 +431,12 @@ DisplayChangeBoxMenu:
ld [wCurrentMenuItem], a
ld [wLastMenuItem], a
hlcoord 0, 0
- ld b, 2
- ld c, 9
+ lb bc, 2, 9
call TextBoxBorder
ld hl, ChooseABoxText
call PrintText
hlcoord 11, 0
- ld b, 12
- ld c, 7
+ lb bc, 12, 7
call TextBoxBorder
ld hl, hUILayoutFlags
set BIT_SINGLE_SPACED_LINES, [hl]
@@ -529,19 +506,14 @@ BoxNoText:
EmptyAllSRAMBoxes:
; marks all boxes in SRAM as empty (initialisation for the first time the
; player changes the box)
- ld a, RAMG_SRAM_ENABLE
- ld [rRAMG], a
- ld a, BMODE_ADVANCED
- ld [rBMODE], a
+ call EnableSRAM
ld a, BANK("Saved Boxes 1")
ld [rRAMB], a
call EmptySRAMBoxesInBank
ld a, BANK("Saved Boxes 2")
ld [rRAMB], a
call EmptySRAMBoxesInBank
- xor a
- ld [rBMODE], a
- ld [rRAMG], a
+ call DisableSRAM
ret
EmptySRAMBoxesInBank:
@@ -575,19 +547,14 @@ EmptySRAMBox:
GetMonCountsForAllBoxes:
ld hl, wBoxMonCounts
push hl
- ld a, RAMG_SRAM_ENABLE
- ld [rRAMG], a
- ld a, BMODE_ADVANCED
- ld [rBMODE], a
+ call EnableSRAM
ld a, BANK("Saved Boxes 1")
ld [rRAMB], a
call GetMonCountsForBoxesInBank
ld a, BANK("Saved Boxes 2")
ld [rRAMB], a
call GetMonCountsForBoxesInBank
- xor a
- ld [rBMODE], a
- ld [rRAMG], a
+ call DisableSRAM
pop hl
; copy the count for the current box from WRAM
@@ -620,11 +587,8 @@ GetMonCountsForBoxesInBank:
; return result in zero flag
; z set: a valid save file was found, and saved PlayerID is different from wPlayerID
CheckPreviousSaveFile:
- ld a, RAMG_SRAM_ENABLE
- ld [rRAMG], a
- ld a, BMODE_ADVANCED
- ld [rBMODE], a
- ASSERT BANK("Save Data") == BMODE_ADVANCED
+ call EnableSRAM
+ ld a, BANK("Save Data")
ld [rRAMB], a
ld a, [sPlayerName]
and a
@@ -688,35 +652,24 @@ LoadHallOfFameTeams:
; fallthrough
HallOfFame_Copy:
- ld a, RAMG_SRAM_ENABLE
- ld [rRAMG], a
- ld a, BMODE_ADVANCED
- ld [rBMODE], a
+ call EnableSRAM
xor a
ld [rRAMB], a
call CopyData
- xor a
- ld [rBMODE], a
- ld [rRAMG], a
+ call DisableSRAM
ret
; Fill SRAM with $ff, erasing save data. Used by DoClearSaveDialogue
ClearAllSRAMBanks:
- ld a, RAMG_SRAM_ENABLE
- ld [rRAMG], a
- ld a, BMODE_ADVANCED
- ld [rBMODE], a
- xor a
- call .PadSRAM_FF
- ld a, 1
- call .PadSRAM_FF
- ld a, 2
- call .PadSRAM_FF
- ld a, 3
+ call EnableSRAM
+ ld a, $4
+.loop
+ dec a
+ push af
call .PadSRAM_FF
- xor a
- ld [rBMODE], a
- ld [rRAMG], a
+ pop af
+ jr nz, .loop
+ call DisableSRAM
ret
.PadSRAM_FF
@@ -725,3 +678,17 @@ ClearAllSRAMBanks:
ld bc, SIZEOF(SRAM)
ld a, $ff
jp FillMemory
+
+EnableSRAM:
+ ld a, BMODE_ADVANCED
+ ld [rBMODE], a
+ ld a, RAMG_SRAM_ENABLE
+ ld [rRAMG], a
+ ret
+
+DisableSRAM:
+ ld a, BMODE_SIMPLE ; preserve flags
+ ld [rBMODE], a
+ ASSERT RAMG_SRAM_DISABLE == BMODE_SIMPLE
+ ld [rRAMG], a
+ ret
diff --git a/engine/menus/start_sub_menus.asm b/engine/menus/start_sub_menus.asm
index 817dceb8..dfbb0f13 100644
--- a/engine/menus/start_sub_menus.asm
+++ b/engine/menus/start_sub_menus.asm
@@ -144,11 +144,14 @@ StartMenu_Pokemon::
call ChooseFlyDestination
ld a, [wStatusFlags6]
bit BIT_FLY_WARP, a
- jp nz, .goBackToMap
+ jr nz, .asm_5d4c
call LoadFontTilePatterns
ld hl, wStatusFlags4
set BIT_UNKNOWN_4_1, [hl]
jp StartMenu_Pokemon
+.asm_5d4c
+ call Func_1510
+ jp .goBackToMap
.cut
bit BIT_CASCADEBADGE, a
jp z, .newBadgeRequired
@@ -165,15 +168,28 @@ StartMenu_Pokemon::
bit BIT_SURF_ALLOWED, [hl]
res BIT_SURF_ALLOWED, [hl]
jp z, .loop
+ ld a, [wCurPartySpecies]
+ cp STARTER_PIKACHU
+ jr z, .surfingPikachu
+ ld a, $1
+ jr .continue
+.surfingPikachu
+ ld a, $2
+.continue
+ ld [wd472], a
ld a, SURFBOARD
ld [wCurItem], a
ld [wPseudoItemID], a
call UseItem
ld a, [wActionResultOrTookBattleTurn]
and a
- jp z, .loop
+ jr z, .reloadNormalSprite
call GBPalWhiteOutWithDelay3
jp .goBackToMap
+.reloadNormalSprite
+ xor a
+ ld [wd472], a
+ jp .loop
.strength
bit BIT_RAINBOWBADGE, a
jp z, .newBadgeRequired
@@ -217,6 +233,7 @@ StartMenu_Pokemon::
ld hl, wStatusFlags6
set BIT_FLY_WARP, [hl]
set BIT_ESCAPE_WARP, [hl]
+ call Func_1510
ld hl, wStatusFlags4
set BIT_UNKNOWN_4_1, [hl]
res BIT_NO_BATTLES, [hl]
@@ -307,11 +324,11 @@ StartMenu_Item::
call PrintText
jr .exitMenu
.notInCableClubRoom
- ld bc, wNumBagItems
+ ; store item bag pointer in wListPointer (for DisplayListMenuID)
ld hl, wListPointer
- ld a, c
- ld [hli], a
- ld [hl], b ; store item bag pointer in wListPointer (for DisplayListMenuID)
+ ld [hl], LOW(wNumBagItems)
+ inc hl
+ ld [hl], HIGH(wNumBagItems)
xor a
ld [wPrintItemPrices], a
ld a, ITEMLISTMENU
@@ -469,10 +486,11 @@ StartMenu_TrainerInfo::
call LoadScreenTilesFromBuffer2
call RunDefaultPaletteCommand
call ReloadMapData
+ farcall DrawStartMenu ; XXX what difference does this make?
call LoadGBPal
pop af
ldh [hTileAnimations], a
- jp RedisplayStartMenu
+ jp RedisplayStartMenu_DoNotDrawStartMenu
; loads tile patterns and draws everything except for gym leader faces / badges
DrawTrainerInfo:
@@ -506,7 +524,7 @@ DrawTrainerInfo:
ld de, vChars2 tile $20
ld bc, 8 * 8 tiles
ld a, BANK(GymLeaderFaceAndBadgeTileGraphics)
- call FarCopyData2
+ call FarCopyData
ld hl, TextBoxGraphics
ld de, 13 tiles
add hl, de ; hl = colon tile pattern
@@ -514,7 +532,7 @@ DrawTrainerInfo:
ld bc, TILE_SIZE
ld a, BANK(TextBoxGraphics)
push bc
- call FarCopyData2
+ call FarCopyData
pop bc
ld hl, TrainerInfoTextBoxTileGraphics tile 8 ; background tile pattern
ld de, vChars1 tile $57
@@ -566,7 +584,7 @@ DrawTrainerInfo:
TrainerInfo_FarCopyData:
ld a, BANK(TrainerInfoTextBoxTileGraphics)
- jp FarCopyData2
+ jp FarCopyData
TrainerInfo_NameMoneyTimeText:
db "NAME/"
diff --git a/engine/menus/text_box.asm b/engine/menus/text_box.asm
index e618b1d0..d3144386 100644
--- a/engine/menus/text_box.asm
+++ b/engine/menus/text_box.asm
@@ -134,8 +134,7 @@ DisplayMoneyBox:
ld [wTextBoxID], a
call DisplayTextBoxID
hlcoord 13, 1
- ld b, 1
- ld c, 6
+ lb bc, 1, 6
call ClearScreenArea
hlcoord 12, 1
ld de, wPlayerMoney
@@ -277,36 +276,10 @@ DisplayTwoOptionMenu:
pop hl
add hl, bc
call PlaceString
- ld hl, wStatusFlags5
- res BIT_NO_TEXT_DELAY, [hl]
- ld a, [wTwoOptionMenuID]
- cp NO_YES_MENU
- jr nz, .notNoYesMenu
-; No/Yes menu
-; this menu type ignores the B button
-; it only seems to be used when confirming the deletion of a save file
- xor a
- ld [wTwoOptionMenuID], a
- ld a, [wMiscFlags]
- push af
- push hl
- ld hl, wMiscFlags
- bit BIT_NO_MENU_BUTTON_SOUND, [hl]
- set BIT_NO_MENU_BUTTON_SOUND, [hl]
- pop hl
-.noYesMenuInputLoop
- call HandleMenuInput
- bit B_PAD_B, a
- jr nz, .noYesMenuInputLoop ; try again if B was not pressed
- pop af
- pop hl
- ld [wMiscFlags], a
- ld a, SFX_PRESS_AB
- call PlaySound
- jr .pressedAButton
-.notNoYesMenu
xor a
ld [wTwoOptionMenuID], a
+ ld hl, wStatusFlags5
+ res BIT_NO_TEXT_DELAY, [hl]
call HandleMenuInput
pop hl
bit B_PAD_B, a
@@ -395,8 +368,7 @@ DisplayFieldMoveMonMenu:
; no field moves
hlcoord 11, 11
- ld b, 5
- ld c, 7
+ lb bc, 5, 7
call TextBoxBorder
call UpdateSprites
ld a, 12
diff --git a/engine/menus/unused_input.asm b/engine/menus/unused_input.asm
new file mode 100644
index 00000000..2eb79373
--- /dev/null
+++ b/engine/menus/unused_input.asm
@@ -0,0 +1,129 @@
+HandleMenuInputDuplicate: ; unreferenced
+ xor a
+ ld [wPartyMenuAnimMonEnabled], a
+
+HandleMenuInputPokemonSelectionDuplicate: ; unreferenced
+ ldh a, [hDownArrowBlinkCount1]
+ push af
+ ldh a, [hDownArrowBlinkCount2]
+ push af ; save existing values on stack
+ xor a
+ ldh [hDownArrowBlinkCount1], a ; blinking down arrow timing value 1
+ ld a, 6
+ ldh [hDownArrowBlinkCount2], a ; blinking down arrow timing value 2
+.loop1
+ xor a
+ ld [wAnimCounter], a ; counter for pokemon shaking animation
+ call PlaceMenuCursorDuplicate
+ call JoypadLowSensitivity
+ ldh a, [hJoy5]
+ and a ; was a key pressed?
+ jr nz, .keyPressed
+ pop af
+ ldh [hDownArrowBlinkCount2], a
+ pop af
+ ldh [hDownArrowBlinkCount1], a ; restore previous values
+ xor a
+ ld [wMenuWrappingEnabled], a ; disable menu wrapping
+ ret
+.keyPressed
+ xor a
+ ld [wCheckFor180DegreeTurn], a
+ ldh a, [hJoy5]
+ ld b, a
+ bit B_PAD_UP, a
+ jr z, .checkIfDownPressed
+.upPressed
+ ld a, [wCurrentMenuItem] ; selected menu item
+ and a ; already at the top of the menu?
+ jr z, .checkOtherKeys
+.notAtTop
+ dec a
+ ld [wCurrentMenuItem], a ; move selected menu item up one space
+ jr .checkOtherKeys
+.checkIfDownPressed
+ bit B_PAD_DOWN, a
+ jr z, .checkOtherKeys
+.downPressed
+ ld a, [wCurrentMenuItem]
+ inc a
+ ld c, a
+ ld a, [wMaxMenuItem]
+ cp c
+ jr c, .checkOtherKeys
+ ld a, c
+ ld [wCurrentMenuItem], a
+.checkOtherKeys
+ ld a, [wMenuWatchedKeys]
+ and b ; does the menu care about any of the pressed keys?
+ jp z, .loop1
+.checkIfAButtonOrBButtonPressed
+ ldh a, [hJoy5]
+ and PAD_A | PAD_B
+ jr z, .skipPlayingSound
+.AButtonOrBButtonPressed
+ ld a, SFX_PRESS_AB
+ call PlaySound ; play sound
+.skipPlayingSound
+ pop af
+ ldh [hDownArrowBlinkCount2], a
+ pop af
+ ldh [hDownArrowBlinkCount1], a ; restore previous values
+ ldh a, [hJoy5]
+ ret
+
+PlaceMenuCursorDuplicate:
+ ld a, [wTopMenuItemY]
+ and a
+ jr z, .asm_f5ac0
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH
+.loop
+ add hl, bc
+ dec a
+ jr nz, .loop
+.asm_f5ac0
+ ld a, [wTopMenuItemX]
+ ld b, $0
+ ld c, a
+ add hl, bc
+ push hl
+ ld a, [wLastMenuItem]
+ and a
+ jr z, .asm_f5ad5
+ ld bc, $28
+.loop2
+ add hl, bc
+ dec a
+ jr nz, .loop2
+.asm_f5ad5
+ ld a, [hl]
+ cp '▶'
+ jr nz, .asm_f5ade
+ ld a, [wTileBehindCursor]
+ ld [hl], a
+.asm_f5ade
+ pop hl
+ ld a, [wCurrentMenuItem]
+ and a
+ jr z, .asm_f5aec
+ ld bc, $28
+.loop3
+ add hl, bc
+ dec a
+ jr nz, .loop3
+.asm_f5aec
+ ld a, [hl]
+ cp '▶'
+ jr z, .asm_f5af4
+ ld [wTileBehindCursor], a
+.asm_f5af4
+ ld a, '▶'
+ ld [hl], a
+ ld a, l
+ ld [wMenuCursorLocation], a
+ ld a, h
+ ld [wMenuCursorLocation + 1], a
+ ld a, [wCurrentMenuItem]
+ ld [wLastMenuItem], a
+ ret
diff --git a/engine/minigame/surfing_pikachu.asm b/engine/minigame/surfing_pikachu.asm
new file mode 100644
index 00000000..27e91ba1
--- /dev/null
+++ b/engine/minigame/surfing_pikachu.asm
@@ -0,0 +1,2863 @@
+SurfingPikachuMinigame::
+ call SurfingPikachuMinigame_BlankPals
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ ldh a, [hTileAnimations]
+ push af
+ xor a
+ ldh [hTileAnimations], a
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ ldh a, [rIE]
+ push af
+ xor a
+ ldh [rIF], a
+ ld a, $f
+ ldh [rIE], a
+ ld a, $8
+ ldh [rSTAT], a
+ ldh a, [hAutoBGTransferDest + 1]
+ push af
+ ld a, $98
+ ldh [hAutoBGTransferDest + 1], a
+ call SurfingPikachuMinigameIntro
+ call SurfingPikachuLoop
+ xor a
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ldh [rOBP1], a
+ call UpdateCGBPal_BGP
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
+ call ClearObjectAnimationBuffers
+ call ClearSprites
+ xor a
+ ldh [hLCDCPointer], a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ld a, $90
+ ldh [hWY], a
+ call DelayFrame
+ pop af
+ ldh [hAutoBGTransferDest + 1], a
+ xor a
+ ldh [rIF], a
+ pop af
+ ldh [rIE], a
+ xor a
+ ldh [rSTAT], a
+ call RunDefaultPaletteCommand
+ call ReloadMapAfterSurfingMinigame
+ call PlayDefaultMusic
+ call GBPalNormal
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ pop af
+ ldh [hTileAnimations], a
+ ret
+
+SurfingPikachuLoop:
+ call SurfingPikachuMinigame_LoadGFXAndLayout
+ call DelayFrame
+ ld b, SET_PAL_SURFING_PIKACHU_TITLE
+ call RunPaletteCommand
+.loop
+ ld a, [wSurfingMinigameRoutineNumber]
+ bit 7, a
+ ret nz
+ call SurfingPikachu_GetJoypad_3FrameBuffer
+ call SurfingPikachu_CheckPressedSelect
+ ret nz
+ call RunSurfingMinigameRoutine
+ ld a, $3c
+ ld [wCurrentAnimatedObjectOAMBufferOffset], a
+ call RunObjectAnimations
+ call SurfingMinigame_MoveClouds
+ call .DelayFrame
+ call SurfingMinigame_UpdateMusicTempo
+ jr .loop
+
+.DelayFrame:
+ call DelayFrame
+ ret
+
+SurfingPikachu_CheckPressedSelect:
+ ld hl, wd492
+ bit 1, [hl]
+ ret z
+ ldh a, [hJoyPressed]
+ and PAD_SELECT
+ ret
+
+Func_f80b7:
+ ldh a, [hJoyPressed]
+ and PAD_START
+ ret z
+ ld hl, wc5e2
+ ld a, [hl]
+ xor $1
+ ld [hl], a
+ ret
+
+SurfingMinigame_UpdateMusicTempo:
+ ld a, [wc634]
+ and a
+ ret z
+
+ ; check that all channels are on their last frame of note delay
+ ld hl, wChannelNoteDelayCounters
+ ld a, $1
+ cp [hl]
+ ret nz
+ inc hl
+ cp [hl]
+ ret nz
+ inc hl
+ cp [hl]
+ ret nz
+
+ ; de = ([wSurfingMinigamePikachuSpeed] & 0x3f) * 2
+ ld a, [wSurfingMinigamePikachuSpeed]
+ ld e, a
+ ld a, [wSurfingMinigamePikachuSpeed + 1]
+ and $3
+ ld d, a
+ sla e
+ rl d
+ ld e, d
+ ld d, $0
+ ld hl, .Tempos
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld [wMusicTempo + 1], a
+ ld a, [hl]
+ ld [wMusicTempo], a
+ ret
+
+.Tempos:
+ dw 117
+ dw 109
+ dw 101
+ dw 93
+ dw 85
+
+SurfingMinigame_ResetMusicTempo:
+ ld hl, wChannelNoteDelayCounters
+ ld a, $1
+ cp [hl]
+ ret nz
+ inc hl
+ cp [hl]
+ ret nz
+ inc hl
+ cp [hl]
+ ret nz
+ ld a, 117
+ ld [wMusicTempo + 1], a
+ xor a
+ ld [wMusicTempo], a
+ ret
+
+SurfingPikachuMinigame_LoadGFXAndLayout:
+ call SurfingPikachu_ClearTileMap
+ call ClearSprites
+ call DisableLCD
+ ld hl, wSurfingMinigameData
+ ld bc, wSurfingMinigameDataEnd - wSurfingMinigameData
+ xor a
+ call FillMemory
+ ld hl, wLYOverrides
+ ld bc, wLYOverridesBufferEnd - wLYOverrides
+ xor a
+ call FillMemory
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call ClearObjectAnimationBuffers
+
+ ld hl, SurfingPikachu1Graphics1
+ ld de, $9000
+ ld bc, $500
+ ld a, BANK(SurfingPikachu1Graphics1)
+ call FarCopyData
+
+ ld hl, SurfingPikachu1Graphics2
+ ld de, $8000
+ ld bc, $1000
+ ld a, BANK(SurfingPikachu1Graphics2)
+ call FarCopyData
+
+ ld a, LOW(SurfingPikachuSpawnStateDataPointer)
+ ld [wAnimatedObjectSpawnStateDataPointer], a
+ ld a, HIGH(SurfingPikachuSpawnStateDataPointer)
+ ld [wAnimatedObjectSpawnStateDataPointer + 1], a
+
+ ld a, LOW(SurfingPikachuObjectJumptable)
+ ld [wAnimatedObjectJumptablePointer], a
+ ld a, HIGH(SurfingPikachuObjectJumptable)
+ ld [wAnimatedObjectJumptablePointer + 1], a
+
+ ld a, LOW(SurfingPikachuOAMData)
+ ld [wAnimatedObjectOAMDataPointer], a
+ ld a, HIGH(SurfingPikachuOAMData)
+ ld [wAnimatedObjectOAMDataPointer + 1], a
+
+ ld a, LOW(SurfingPikachuFrames)
+ ld [wAnimatedObjectFramesDataPointer], a
+ ld a, HIGH(SurfingPikachuFrames)
+ ld [wAnimatedObjectFramesDataPointer + 1], a
+
+ ld hl, vBGMap0
+ ld bc, $80 tiles
+ ld a, $0
+ call FillMemory
+
+ ld hl, $98c0
+ ld bc, $18 tiles
+ ld a, $b
+ call FillMemory
+
+ ld a, $1
+ lb de, $74, $58
+ call SpawnAnimatedObject
+
+ ld a, $74
+ ld [wSurfingMinigamePikachuObjectHeight], a
+
+ call SurfingMinigame_InitScanlineOverrides
+
+ xor a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ld a, $7e
+ ldh [hWY], a
+ ld a, rSCY - $ff00
+ ldh [hLCDCPointer], a
+ ld a, $40
+ ld [wSurfingMinigamePikachuSpeed], a
+ xor a
+ ld [wSurfingMinigamePikachuSpeed + 1], a
+ xor a
+ ld [wSurfingMinigamePikachuHP], a
+ ld a, $60
+ ld [wSurfingMinigamePikachuHP + 1], a
+ ld hl, wSurfingMinigameWaveHeight
+ ld bc, $14
+ ld a, $74
+ call FillMemory
+ call Func_f81ff
+ call Func_f8256
+ ld a, $e3
+ ldh [rLCDC], a
+ call SurfingPikachuMinigame_SetBGPals
+ ld a, $e4
+ ldh [rOBP0], a
+ ld a, $e0
+ ldh [rOBP1], a
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
+ ret
+
+SurfingPikachuMinigame_SetBGPals:
+ ld a, [wOnSGB]
+ and a
+ jr nz, .sgb
+ ld a, $d0
+ ldh [rBGP], a
+ call UpdateCGBPal_BGP
+ ret
+
+.sgb
+ ld a, $e4
+ ldh [rBGP], a
+ call UpdateCGBPal_BGP
+ ret
+
+Func_f81ff:
+ ld hl, wSpriteDataEnd
+ ld de, Unkn_f8249
+ ld b, $97
+ ld c, $80
+ ld a, $4
+ call Func_f8233
+ ld de, Unkn_f8248
+ ld b, $96
+ ld c, $50
+ ld a, $1
+ call Func_f8233
+ ld de, Unkn_f824d
+ ld b, $14
+ ld c, $20
+ ld a, $5
+ call Func_f8233
+ ld de, Unkn_f8252
+ ld b, $20
+ ld c, $80
+ ld a, $4
+ call Func_f8233
+ ret
+
+Func_f8233:
+.asm_f8233
+ push af
+ ld [hl], b
+ inc hl
+ ld [hl], c
+ inc hl
+ ld a, [de]
+ ld [hl], a
+ inc hl
+ ld [hl], $0
+ inc hl
+ ld a, c
+ add $8
+ ld c, a
+ inc de
+ pop af
+ dec a
+ jr nz, .asm_f8233
+ ret
+
+Unkn_f8248:
+ db $fe
+
+Unkn_f8249:
+ db $d0
+ db $d0
+ db $d0
+ db $d0
+
+Unkn_f824d:
+ db $ec
+ db $ed
+ db $ed
+ db $ee
+ db $ef
+
+Unkn_f8252:
+ db $ec
+ db $ed
+ db $ee
+ db $ef
+
+Func_f8256:
+ ld de, $9c21
+ ld hl, Unkn_f8279
+ ld c, $9
+.asm_f825e
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .asm_f825e
+ ld hl, $9c01
+ ld [hl], $15
+ ld hl, $9c02
+ ld [hl], $16
+ ld hl, $9c2c
+ ld [hl], $1b
+ ld hl, $9c2d
+ ld [hl], $1c
+ ret
+
+Unkn_f8279:
+ db $17
+ db $18
+ db $19
+ db $19
+ db $19
+ db $19
+ db $19
+ db $19
+ db $19
+
+RunSurfingMinigameRoutine:
+ ld a, [wSurfingMinigameRoutineNumber]
+ 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 SurfingMinigameRoutine_SpawnPikachu ; 0
+ dw SurfingMinigame_RunGame ; 1
+ dw Func_f8324 ; 2
+ dw Func_f835c ; 3
+ dw SurfingMinigame_DrawResultsScreenAndWait ; 4
+ dw SurfingMinigame_WriteHPLeftAndWait ; 5
+ dw SurfingMinigame_WriteRadnessAndWait ; 6
+ dw SurfingMinigame_WriteTotalAndWait ; 7
+ dw SurfingMinigame_AddRemainingHPToTotalAndWait ; 8
+ dw SurfingMinigame_AddRadnessToTotalAndWait ; 9
+ dw SurfingMinigame_WaitLast ; a
+ dw SurfingMinigame_ExitOnPressA ; b
+ dw SurfingMinigame_GameOver ; c
+
+SurfingMinigameRoutine_SpawnPikachu:
+ ld a, $2
+ lb de, $48, $e0
+ call SpawnAnimatedObject
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ ld a, $1
+ ld [wc634], a
+ ret
+
+SurfingMinigame_RunGame:
+ ld a, [wc5e5]
+ cp $18
+ jr nc, .asm_f82e8
+ ld hl, wSurfingMinigamePikachuHP
+ ld a, [hli]
+ or [hl]
+ and a
+ jr z, .dead
+ call Random
+ ld [wc5d5], a
+ call SurfingMinigame_UpdateLYOverrides
+ call SurfingMinigame_SetPikachuHeight
+ call SurfingMinigame_ReadBGMapBuffer
+ call SurfingMinigame_ScrollAndGenerateBGMap
+ call SurfingMinigame_UpdatePikachuDistance
+ call SurfingMinigame_Deduct1HP
+ call SurfingMinigame_DrawHP
+ ret
+
+.asm_f82e8
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ xor a
+ ld [wc634], a
+ ld a, 192
+ ld [wSurfingMinigameRoutineDelay], a
+ ret
+
+.dead
+ ld a, $1
+ ld [wc630], a
+ ld a, $c
+ ld [wSurfingMinigameRoutineNumber], a
+ ld a, $80
+ ld [wc631], a
+ ld a, $b
+ lb de, $88, $58
+ call SpawnAnimatedObject
+ ld hl, ANIM_OBJ_Y_OFFSET
+ add hl, bc
+ ld [hl], $80
+ ld hl, ANIM_OBJ_FIELD_B
+ add hl, bc
+ ld [hl], $80
+ ld hl, ANIM_OBJ_FIELD_C
+ add hl, bc
+ ld [hl], $30
+ xor a
+ ld [wc634], a
+ ret
+
+Func_f8324:
+ call SurfingMinigame_RunDelayTimer
+ jr c, .done_delay
+ xor a
+ ld [wc5d5], a
+ call SurfingMinigame_UpdateLYOverrides
+ call SurfingMinigame_SetPikachuHeight
+ call SurfingMinigame_ReadBGMapBuffer
+ call Func_f8c97
+ call SurfingMinigame_ResetMusicTempo
+ ret
+
+.done_delay
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ ld a, $90
+ ldh [hSCX], a
+ ld a, $72
+ ld [wSurfingMinigameWaveFunctionNumber], a
+ ld a, $4
+ ld [wc5d2], a
+ xor a
+ ldh [hLCDCPointer], a
+ ld [wSurfingMinigameSCX], a
+ ld [wSurfingMinigameSCX2], a
+ ld [wSurfingMinigameSCXHi], a
+ ret
+
+Func_f835c:
+ ldh a, [hSCX]
+ and a
+ jr z, .asm_f837b
+ call SurfingMinigame_UpdateLYOverrides
+ call SurfingMinigame_SetPikachuHeight
+ call SurfingMinigame_ReadBGMapBuffer
+ ldh a, [hSCX]
+ dec a
+ dec a
+ dec a
+ dec a
+ ldh [hSCX], a
+ ld a, $e0
+ ld [wSurfingMinigameXOffset], a
+ call SurfingMinigame_GenerateBGMap
+ ret
+
+.asm_f837b
+ xor a
+ ld [wSurfingMinigamePikachuSpeed], a
+ ld [wSurfingMinigamePikachuSpeed + 1], a
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ ld a, $5
+ ld [wc5d2], a
+ ret
+
+SurfingMinigame_DrawResultsScreenAndWait:
+ call SurfingMinigame_DrawResultsScreen
+ ld a, 32
+ ld [wSurfingMinigameRoutineDelay], a
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ ret
+
+SurfingMinigame_WriteHPLeftAndWait:
+ call SurfingMinigame_RunDelayTimer
+ ret nc
+ call SurfingMinigame_WriteHPLeft
+ ld a, 64
+ ld [wSurfingMinigameRoutineDelay], a
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ ret
+
+SurfingMinigame_WriteRadnessAndWait:
+ call SurfingMinigame_RunDelayTimer
+ ret nc
+ call SurfingMinigame_WriteRadness
+ ld a, 64
+ ld [wSurfingMinigameRoutineDelay], a
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ ret
+
+SurfingMinigame_WriteTotalAndWait:
+ call SurfingMinigame_RunDelayTimer
+ ret nc
+ call SurfingMinigame_WriteTotal
+ ld a, 64
+ ld [wSurfingMinigameRoutineDelay], a
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ ret
+
+SurfingMinigame_AddRemainingHPToTotalAndWait:
+ call SurfingMinigame_RunDelayTimer
+ ret nc
+ call SurfingMinigame_AddRemainingHPToTotal
+ push af
+ call SurfingMinigame_BCDPrintTotalScore
+ pop af
+ ret nc
+ ld a, 64
+ ld [wSurfingMinigameRoutineDelay], a
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ ret
+
+SurfingMinigame_AddRadnessToTotalAndWait:
+ call SurfingMinigame_RunDelayTimer
+ ret nc
+ call SurfingMinigame_AddRadnessToTotal
+ push af
+ call SurfingMinigame_BCDPrintTotalScore
+ pop af
+ ret nc
+ ld a, 128
+ ld [wSurfingMinigameRoutineDelay], a
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ call DidPlayerGetAHighScore
+ ret nc
+ call SurfingMinigame_PrintTextHiScore
+ ld a, $6
+ ld [wc5d2], a
+ ret
+
+SurfingMinigame_WaitLast:
+ call SurfingMinigame_RunDelayTimer
+ ret nc
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ ret
+
+SurfingMinigame_ExitOnPressA:
+ call SurfingMinigame_UpdateLYOverrides
+ ldh a, [hJoyPressed]
+ and PAD_A
+ ret z
+ ld hl, wSurfingMinigameRoutineNumber
+ set 7, [hl]
+ ret
+
+SurfingMinigame_GameOver:
+ call SurfingMinigame_UpdateLYOverrides
+ call SurfingMinigame_SetPikachuHeight
+ call SurfingMinigame_ReadBGMapBuffer
+ call SurfingMinigame_ScrollAndGenerateBGMap
+ call SurfingMinigame_ResetMusicTempo
+ ld hl, wc631
+ ld a, [hl]
+ and a
+ jr z, .wait_press_a
+ dec [hl]
+ ret
+
+.wait_press_a
+ ldh a, [hJoyPressed]
+ and PAD_A
+ ret z
+ ld hl, wSurfingMinigameRoutineNumber
+ set 7, [hl]
+ ret
+
+SurfingMinigame_RunDelayTimer:
+ ld hl, wSurfingMinigameRoutineDelay
+ ld a, [hl]
+ and a
+ jr z, .set_carry
+ dec [hl]
+ and a
+ ret
+
+.set_carry
+ scf
+ ret
+
+SurfingMinigame_UpdatePikachuDistance:
+ ld a, [wc5e5 + 1]
+ ld h, a
+ ld a, [wc5e5 + 2]
+ ld l, a
+ ld a, [wSurfingMinigamePikachuSpeed]
+ ld e, a
+ ld a, [wSurfingMinigamePikachuSpeed + 1]
+ ld d, a
+ add hl, de
+ ld a, h
+ ld [wc5e5 + 1], a
+ ld a, l
+ ld [wc5e5 + 2], a
+ ret nc
+ ld hl, wc5e5
+ inc [hl]
+ ld hl, wShadowOAMSprite04XCoord
+ dec [hl]
+ dec [hl]
+ ret
+
+SurfingMinigameAnimatedObjectFn_Pikachu:
+ ld a, [wc5d2]
+ ld e, a
+ ld d, $0
+ ld hl, Jumptable_f847f
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+Jumptable_f847f:
+ dw Func_f848d
+ dw SurfingMinigame_ScoreCurrentWave
+ dw Func_f8516
+ dw Func_f8545
+ dw Func_f8561
+ dw Func_f856d
+ dw Func_f8579
+
+Func_f848d:
+ ld a, [wc630]
+ and a
+ jr nz, .asm_f84d2
+ call Func_f87b5
+ ld a, [wSurfingMinigamePikachuObjectHeight]
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld [hl], a
+ call Func_f871e
+ jr c, .splash
+ call Func_f8742
+ call SurfingMinigame_SpeedUpPikachu
+ ret
+
+.splash
+ call Func_f8742
+ ld a, $1 ; on a wave
+ ld [wc5d2], a
+ xor a
+ ld hl, ANIM_OBJ_FIELD_C
+ add hl, bc
+ ld [hl], a
+ ld hl, ANIM_OBJ_FIELD_D
+ add hl, bc
+ ld [hl], a
+ ld hl, ANIM_OBJ_FIELD_E
+ add hl, bc
+ ld [hl], a
+ ld [wSurfingMinigameRadnessMeter], a
+ ld [wSurfingMinigameTrickFlags], a
+ xor a
+ ld [wChannelSoundIDs + CHAN8], a
+ ld a, SFX_SURFING_JUMP
+ call PlaySound
+ ret
+
+.asm_f84d2
+ xor a
+ ld [wSurfingMinigamePikachuSpeed], a
+ ld [wSurfingMinigamePikachuSpeed + 1], a
+ ld a, $4
+ ld [wc5d2], a
+ call Func_f8742
+ ret
+
+SurfingMinigame_ScoreCurrentWave:
+ call SurfingMinigame_DPadAction
+ call SurfingMinigame_UpdatePikachuHeight
+ ret nc
+ call SurfingMinigame_TileInteraction
+ jr c, .splash
+ call SurfingMinigame_CalculateAndAddRadnessFromStunt
+ ld hl, ANIM_OBJ_FIELD_C
+ add hl, bc
+ ld [hl], $0
+ ld a, $2
+ ld [wc5d2], a
+ ret
+
+.splash
+ ld a, $3
+ ld [wc5d2], a
+ ld a, $60
+ ld [wc5e1], a
+ ld a, $10
+ call SetCurrentAnimatedObjectCallbackAndResetFrameStateRegisters
+ xor a
+ ld [wChannelSoundIDs + CHAN8], a
+ ld a, SFX_SURFING_CRASH
+ call PlaySound
+ ret
+
+Func_f8516:
+ ld hl, ANIM_OBJ_FIELD_C
+ add hl, bc
+ ld a, [hl]
+ cp $20
+ jr nc, .asm_f8539
+ inc [hl]
+ inc [hl]
+ inc [hl]
+ inc [hl]
+ ld d, $4
+ call SurfingPikachu_Sine
+ ld hl, ANIM_OBJ_Y_OFFSET
+ add hl, bc
+ ld [hl], a
+ call Func_f87b5
+ ld a, [wSurfingMinigamePikachuObjectHeight]
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld [hl], a
+ ret
+
+.asm_f8539
+ ld hl, ANIM_OBJ_Y_OFFSET
+ add hl, bc
+ ld [hl], $0
+ ld a, $0
+ ld [wc5d2], a
+ ret
+
+Func_f8545:
+ ld hl, wc5e1
+ ld a, [hl]
+ and a
+ jr z, .asm_f8556
+ dec [hl]
+ ld a, [wSurfingMinigamePikachuObjectHeight]
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld [hl], a
+ ret
+
+.asm_f8556
+ ld a, $0
+ ld [wc5d2], a
+ ld a, $4
+ call SetCurrentAnimatedObjectCallbackAndResetFrameStateRegisters
+ ret
+
+Func_f8561:
+ ld a, [wSurfingMinigamePikachuObjectHeight]
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld [hl], a
+ call Func_f8742
+ ret
+
+Func_f856d:
+ ld a, $f
+ call SetCurrentAnimatedObjectCallbackAndResetFrameStateRegisters
+ ld hl, ANIM_OBJ_FIELD_C
+ add hl, bc
+ ld [hl], $0
+ ret
+
+Func_f8579:
+ ld hl, ANIM_OBJ_FIELD_C
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ inc [hl]
+ and $3f
+ cp $20
+ jr c, .asm_f8591
+ ld d, $10
+ call SurfingPikachu_Sine
+ ld hl, ANIM_OBJ_Y_OFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.asm_f8591
+ ld hl, ANIM_OBJ_Y_OFFSET
+ add hl, bc
+ ld [hl], $0
+ ret
+
+SurfingMinigame_DPadAction:
+ ld de, hJoy5
+ ld a, [de]
+ and PAD_LEFT
+ jr nz, .d_left
+ ld a, [de]
+ and PAD_RIGHT
+ jr nz, .d_right
+ ret
+
+.d_left
+ ld hl, ANIM_OBJ_FIELD_E
+ add hl, bc
+ ld [hl], $0
+ ld hl, ANIM_OBJ_FIELD_D
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ cp $b
+ jr c, .d_left_skip
+ call .StartTrick
+ ld hl, wSurfingMinigameTrickFlags
+ set 0, [hl]
+.d_left_skip
+ ld hl, ANIM_OBJ_FRAME_SET
+ add hl, bc
+ ld a, [hl]
+ cp $e
+ jr nc, .d_left_reset
+ inc [hl]
+ ret
+
+.d_left_reset
+ ld [hl], $1
+ ret
+
+.d_right
+ ld hl, ANIM_OBJ_FIELD_D
+ add hl, bc
+ ld [hl], $0
+ ld hl, ANIM_OBJ_FIELD_E
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ cp $d
+ jr c, .d_right_skip
+ call .StartTrick
+ ld hl, wSurfingMinigameTrickFlags
+ set 1, [hl]
+.d_right_skip
+ ld hl, ANIM_OBJ_FRAME_SET
+ add hl, bc
+ ld a, [hl]
+ cp $1
+ jr z, .d_right_reset
+ dec [hl]
+ ret
+
+.d_right_reset
+ ld [hl], $e
+ ret
+
+.StartTrick:
+ call SurfingMinigame_IncreaseRadnessMeter
+ xor a
+ ld hl, ANIM_OBJ_FIELD_D
+ add hl, bc
+ ld [hl], a
+ ld hl, ANIM_OBJ_FIELD_E
+ add hl, bc
+ ld [hl], a
+ ld a, SFX_SURFING_FLIP
+ call PlaySound
+ ret
+
+SurfingMinigame_TileInteraction:
+ ld hl, ANIM_OBJ_FRAME_SET
+ add hl, bc
+ ld a, [wSurfingMinigameBGMapReadBuffer]
+ cp $6
+ jr z, .tile_06
+ cp $14
+ jr z, .tile_14
+ cp $12
+ jr z, .tile_12
+ cp $7
+ jr z, .tile_07
+ ld a, [hl]
+ cp $1
+ jp z, .action_0
+ cp $2
+ jr z, .action_1
+ cp $3
+ jr z, .action_2
+ cp $4
+ jr z, .action_3
+ cp $5
+ jr z, .action_2
+ cp $6
+ jr z, .action_1
+ cp $7
+ jr z, .action_0
+ jr .action_0
+
+.tile_06
+ ld a, [hl]
+ cp $1
+ jr z, .action_0
+ cp $2
+ jr z, .action_0
+ cp $3
+ jr z, .action_0
+ cp $4
+ jr z, .action_1
+ cp $5
+ jr z, .action_2
+ cp $6
+ jr z, .action_3
+ cp $7
+ jr z, .action_2
+ jr .action_0
+
+.tile_07
+ ld a, [hl]
+ cp $1
+ jr z, .action_2
+ cp $2
+ jr z, .action_3
+ cp $3
+ jr z, .action_2
+ cp $4
+ jr z, .action_1
+ cp $5
+ jr z, .action_0
+ cp $6
+ jr z, .action_0
+ cp $7
+ jr z, .action_0
+ jr .action_0
+
+.tile_12
+.tile_14
+ ld a, [hl]
+ cp $1
+ jr z, .action_0
+ cp $2
+ jr z, .action_1
+ cp $3
+ jr z, .action_2
+ cp $4
+ jr z, .action_3
+ cp $5
+ jr z, .action_3
+ cp $6
+ jr z, .action_2
+ cp $7
+ jr z, .action_1
+ jr .action_0
+
+.action_1
+ call SufingMinigame_ReduceSpeedBy128
+ jr .action_3
+
+.action_2
+ call SufingMinigame_ReduceSpeedBy64
+.action_3
+ xor a
+ ld [wChannelSoundIDs + CHAN8], a
+ ld a, SFX_SURFING_LAND
+ call PlaySound
+ and a
+ ret
+
+.action_0
+ ld a, $40
+ ld [wSurfingMinigamePikachuSpeed], a
+ xor a
+ ld [wSurfingMinigamePikachuSpeed + 1], a
+ scf
+ ret
+
+SurfingMinigame_SpeedUpPikachu:
+ ld a, [wSurfingMinigamePikachuSpeed + 1]
+ cp $2
+ ret nc
+ ld h, a
+ ld a, [wSurfingMinigamePikachuSpeed]
+ ld l, a
+ ld de, $2
+ add hl, de
+ ld a, h
+ ld [wSurfingMinigamePikachuSpeed + 1], a
+ ld a, l
+ ld [wSurfingMinigamePikachuSpeed], a
+ ret
+
+SufingMinigame_ReduceSpeedBy64:
+ ld a, [wSurfingMinigamePikachuSpeed + 1]
+ and a
+ jr nz, .go
+ ld a, [wSurfingMinigamePikachuSpeed]
+ cp $40
+ jr nc, .go
+ xor a
+ ld [wSurfingMinigamePikachuSpeed], a
+ ret
+
+.go
+ ld a, [wSurfingMinigamePikachuSpeed + 1]
+ ld h, a
+ ld a, [wSurfingMinigamePikachuSpeed]
+ ld l, a
+ ld de, -$40
+ add hl, de
+ ld a, h
+ ld [wSurfingMinigamePikachuSpeed + 1], a
+ ld a, l
+ ld [wSurfingMinigamePikachuSpeed], a
+ ret
+
+SufingMinigame_ReduceSpeedBy128:
+ ld a, [wSurfingMinigamePikachuSpeed + 1]
+ and a
+ jr nz, .go
+ ld a, [wSurfingMinigamePikachuSpeed]
+ cp $80
+ jr nc, .go
+ xor a
+ ld [wSurfingMinigamePikachuSpeed], a
+ ret
+
+.go
+ ld a, [wSurfingMinigamePikachuSpeed + 1]
+ ld h, a
+ ld a, [wSurfingMinigamePikachuSpeed]
+ ld l, a
+ ld de, -$80
+ add hl, de
+ ld a, h
+ ld [wSurfingMinigamePikachuSpeed + 1], a
+ ld a, l
+ ld [wSurfingMinigamePikachuSpeed], a
+ ret
+
+Func_f871e:
+ ldh a, [hSCX]
+ and $7
+ cp $3
+ jr c, .asm_f8740
+ cp $5
+ jr nc, .asm_f8740
+ ld a, [wSurfingMinigameBGMapReadBuffer]
+ cp $14
+ jr nz, .asm_f8740
+ call SufingMinigame_GetSpeedDividedBy32
+ cp $a
+ jr c, .asm_f8740
+ ld [wc5ec], a
+ call Func_f9284
+ scf
+ ret
+
+.asm_f8740
+ and a
+ ret
+
+Func_f8742:
+ ldh a, [hSCX]
+ and $7
+ cp $3
+ ret c
+ cp $5
+ ret nc
+ ld a, [wSurfingMinigameBGMapReadBuffer]
+ cp $6
+ jr z, .asm_f8766
+ cp $14
+ jr z, .asm_f8766
+ cp $7
+ jr z, .asm_f876a
+ call Func_f8778
+ ld a, $4
+ ld hl, ANIM_OBJ_FRAME_SET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.asm_f8766
+ ld a, $6
+ jr .asm_f876c
+
+.asm_f876a
+ ld a, $2
+.asm_f876c
+ ld e, a
+ ld a, [wc5de]
+ dec a
+ add e
+ ld hl, ANIM_OBJ_FRAME_SET
+ add hl, bc
+ ld [hl], a
+ ret
+
+Func_f8778:
+ ld hl, wc5e0
+ ld a, [hl]
+ inc [hl]
+ and $7
+ ret nz
+ ld a, [wc5df]
+ and a
+ jr z, .asm_f8796
+ ld a, [wc5de]
+ and a
+ jr z, .asm_f8791
+ dec a
+ ld [wc5de], a
+ ret
+
+.asm_f8791
+ xor a
+ ld [wc5df], a
+ ret
+
+.asm_f8796
+ ld a, [wc5de]
+ cp $2
+ jr z, .asm_f87a2
+ inc a
+ ld [wc5de], a
+ ret
+
+.asm_f87a2
+ ld a, $1
+ ld [wc5df], a
+ ret
+
+SufingMinigame_GetSpeedDividedBy32:
+ ld a, [wSurfingMinigamePikachuSpeed]
+ ld l, a
+ ld a, [wSurfingMinigamePikachuSpeed + 1]
+ ld h, a
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld a, h
+ ret
+
+Func_f87b5:
+ ld hl, wc5eb
+ ld a, [hl]
+ inc [hl]
+ and $3
+ ret nz
+ call .GetYCoord
+ ld d, a
+ ld hl, ANIM_OBJ_X_COORD
+ add hl, bc
+ ld e, [hl]
+ ld a, $a
+ push bc
+ call SpawnAnimatedObject
+ pop bc
+ ret
+
+.GetYCoord:
+ ldh a, [hSCX]
+ and $8
+ jr nz, .get_height_plus_9
+ ld hl, wSurfingMinigameWaveHeight + 8
+ jr .got_hl
+
+.get_height_plus_9
+ ld hl, wSurfingMinigameWaveHeight + 9
+.got_hl
+ ld a, [wSurfingMinigameBGMapReadBuffer + 1]
+ cp $6
+ jr z, .six_or_twenty
+ cp $14
+ jr z, .six_or_twenty
+ cp $7
+ jr z, .seven
+ ld a, [hl]
+ ret
+
+.six_or_twenty
+ ldh a, [hSCX]
+ and $7
+ ld e, a
+ ld a, [hl]
+ sub e
+ ret
+
+.seven
+ ldh a, [hSCX]
+ and $7
+ add [hl]
+ ret
+
+Func_f87fb:
+ ld hl, ANIM_OBJ_X_COORD
+ add hl, bc
+ ld a, [hl]
+ cp $58
+ ret z
+ add $4
+ ld [hl], a
+ ret
+
+Func_f8807: ; unreferenced
+ call MaskCurrentAnimatedObjectStruct
+ ret
+
+SurfingMinigameAnimatedObjectFn_FlippingPika:
+ ld hl, ANIM_OBJ_FIELD_B
+ add hl, bc
+ ld a, [hl]
+ and a
+ ret z
+ dec [hl]
+ dec [hl]
+ ld d, a
+ ld hl, ANIM_OBJ_FIELD_C
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ call SurfingPikachu_Sine
+ cp $80
+ jr nc, .positive
+ xor $ff
+ inc a
+.positive
+ ld hl, ANIM_OBJ_Y_OFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+SurfingMinigameAnimatedObjectFn_IntroAnimationPikachu:
+ ld hl, ANIM_OBJ_FIELD_B
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ and $1
+ ret z
+ ld hl, ANIM_OBJ_X_COORD
+ add hl, bc
+ ld a, [hl]
+ cp $c0
+ jr z, .done
+ inc [hl]
+ ret
+
+.done
+ ld a, $1
+ ld [wSurfingMinigameIntroAnimationFinished], a
+ call MaskCurrentAnimatedObjectStruct
+ ret
+
+SurfingMinigame_MoveClouds:
+ ld a, [wc635]
+ ld e, a
+ ld d, $0
+ ld a, [wSurfingMinigamePikachuSpeed]
+ ld l, a
+ ld a, [wSurfingMinigamePikachuSpeed + 1]
+ ld h, a
+ add hl, de
+ ld a, l
+ ld [wc635], a
+ ld d, h
+ ld hl, wShadowOAMSprite05XCoord
+ ld e, $9
+.loop
+ ld a, [hl]
+ add d
+ ld [hli], a
+ inc hl
+ inc hl
+ inc hl
+ dec e
+ jr nz, .loop
+ ret
+
+SurfingMinigame_ReadBGMapBuffer:
+ ld a, [wSurfingMinigameBGMapReadBuffer] ; ???
+ ldh a, [hSCX]
+ add $48
+ ld e, a
+ srl e
+ srl e
+ srl e
+ ld d, $0
+ ld hl, vBGMap0
+ add hl, de
+ ld a, [wSurfingMinigamePikachuObjectHeight]
+ srl a
+ srl a
+ srl a
+ ld c, a
+.loop
+ ld a, c
+ and a
+ jr z, .copy
+ dec c
+ ld de, $20
+ add hl, de
+ ld a, h
+ and $3
+ or $98
+ ld h, a
+ jr .loop
+
+.copy
+ ld de, wSurfingMinigameBGMapReadBuffer
+ ld a, e
+ ldh [hVBlankCopyDest], a
+ ld a, d
+ ldh [hVBlankCopyDest + 1], a
+ ld a, l
+ ldh [hVBlankCopySource], a
+ ld a, h
+ ldh [hVBlankCopySource + 1], a
+ ld a, 16 / $10
+ ldh [hVBlankCopySize], a
+ ret
+
+SurfingMinigame_SetPikachuHeight:
+ ldh a, [hSCX]
+ and $8
+ jr nz, .asm_f88b9
+ ld hl, wSurfingMinigameWaveHeight + 7
+ jr .asm_f88bc
+
+.asm_f88b9
+ ld hl, wSurfingMinigameWaveHeight + 8
+.asm_f88bc
+ ld a, [wSurfingMinigameBGMapReadBuffer]
+ cp $6
+ jr z, .asm_f88d0
+ cp $14
+ jr z, .asm_f88d0
+ cp $7
+ jr z, .asm_f88db
+ ld a, [hl]
+ ld [wSurfingMinigamePikachuObjectHeight], a
+ ret
+
+.asm_f88d0
+ ldh a, [hSCX]
+ and $7
+ ld e, a
+ ld a, [hl]
+ sub e
+ ld [wSurfingMinigamePikachuObjectHeight], a
+ ret
+
+.asm_f88db
+ ldh a, [hSCX]
+ and $7
+ add [hl]
+ ld [wSurfingMinigamePikachuObjectHeight], a
+ ret
+
+SurfingMinigame_Deduct1HP:
+ ld hl, wSurfingMinigamePikachuHP
+ ld e, $99
+ call .BCD_Deduct
+ ret nc
+ inc hl
+ ld e, $99
+.BCD_Deduct:
+ ld a, [hl]
+ and a
+ jr z, .roll_over
+ sub $1
+ daa
+ ld [hl], a
+ and a
+ ret
+
+.roll_over
+ ld [hl], e
+ scf
+ ret
+
+SurfingMinigame_DrawHP:
+ ld de, wSurfingMinigamePikachuHP + 1
+ ld hl, wShadowOAMSprite00TileID
+ ld a, [de]
+ call .PlaceBCDNumber
+ ld hl, wShadowOAMSprite02TileID
+ ld a, [de]
+.PlaceBCDNumber:
+ ld c, a
+ swap a
+ and $f
+ add $d0
+ ld [hli], a
+ inc hl
+ inc hl
+ inc hl
+ ld a, c
+ and $f
+ add $d0
+ ld [hl], a
+ dec de
+ ret
+
+SurfingMinigame_DrawResultsScreen:
+ ld hl, wTileMap
+ ld bc, SCREEN_AREA
+ xor a
+ call FillMemory
+ ld hl, .BeachTilemap
+ decoord 0, 6
+ ld bc, .BeachTilemapEnd - .BeachTilemap
+ call CopyData
+ call .PlaceTextbox
+ ld hl, wShadowOAMSprite05XCoord
+ ld bc, 9 * 4
+ xor a
+ call FillMemory
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ ret
+
+.BeachTilemap:
+INCBIN "gfx/surfing_pikachu/unknown_f8946.tilemap"
+.BeachTilemapEnd:
+
+.PlaceTextbox:
+ hlcoord 1, 1
+ lb de, $3b, $3c
+ ld a, $40
+ call .place_row
+ hlcoord 1, 2
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ hlcoord 1, 3
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ hlcoord 1, 4
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ hlcoord 1, 5
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ hlcoord 1, 6
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ hlcoord 1, 7
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ hlcoord 1, 8
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ hlcoord 1, 9
+ lb de, $3d, $3e
+ ld a, $40
+ call .place_row
+ ret
+
+.place_row:
+ ld [hl], d
+ inc hl
+ ld c, $10
+.loop
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ld [hl], e
+ ret
+
+SurfingMinigame_PrintTextHiScore:
+ ld hl, .Hi_Score
+ decoord 6, 8
+ ld bc, $9
+ call CopyData
+ ret
+
+.Hi_Score:
+ db $20,$2e,$2f,$30,$31,$2c,$32,$23,$33 ; Hi-Score!!
+
+SurfingMinigame_WriteHPLeft:
+ ld hl, .HP_Left
+ decoord 2, 2
+ ld bc, $7
+ call CopyData
+ call SurfingMinigame_BCDPrintHPLeft
+ ret
+
+.HP_Left:
+ db $20,$21,$ff,$22,$23,$24,$25 ; HP Left
+
+SurfingMinigame_AddRemainingHPToTotal:
+ ld c, 99
+.loop
+ push bc
+ ld hl, wSurfingMinigamePikachuHP
+ ld a, [hli]
+ or [hl]
+ and a
+ jr z, .dead
+ call SurfingMinigame_Deduct1HP
+ ld e, $1
+ call SurfingMinigame_AddPointsToTotal
+ pop bc
+ dec c
+ jr nz, .loop
+ ld a, SFX_PRESS_AB
+ call PlaySound
+ and a
+ ret
+
+.dead
+ pop bc
+ scf
+ ret
+
+SurfingMinigame_BCDPrintHPLeft:
+ hlcoord 10, 2
+ ld de, wSurfingMinigamePikachuHP + 1
+ ld a, [de]
+ call SurfingPikachu_PlaceBCDNumber
+ inc hl
+ ld a, [de]
+ call SurfingPikachu_PlaceBCDNumber
+ inc hl
+ inc hl
+ ld [hl], $21 ; P
+ inc hl
+ ld [hl], $25 ; t
+ inc hl
+ ld [hl], $26 ; s
+ ret
+
+SurfingMinigame_WriteRadness:
+ ld hl, .Radness
+ decoord 2, 4
+ ld bc, $7
+ call CopyData
+ call SurfingMinigame_BCDPrintRadness
+ ret
+
+.Radness:
+ db $27,$28,$29,$2a,$23,$26,$26 ; Radness
+
+SurfingMinigame_AddRadnessToTotal:
+ ld c, 99
+.loop
+ push bc
+ ld hl, wSurfingMinigameRadnessScore
+ ld a, [hli]
+ ld e, a
+ or [hl]
+ jr z, .done
+ ld d, [hl]
+ ld a, e
+ sub $1
+ daa
+ ld e, a
+ ld a, d
+ sbc $0
+ daa
+ ld [hld], a
+ ld [hl], e
+ ld e, $1
+ call SurfingMinigame_AddPointsToTotal
+ pop bc
+ dec c
+ jr nz, .loop
+ ld a, SFX_PRESS_AB
+ call PlaySound
+ and a
+ ret
+
+.done
+ pop bc
+ scf
+ ret
+
+SurfingMinigame_BCDPrintRadness:
+ ld a, [wSurfingMinigameRadnessScore + 1]
+ hlcoord 10, 4
+ call SurfingPikachu_PlaceBCDNumber
+ ld a, [wSurfingMinigameRadnessScore]
+ hlcoord 12, 4
+ call SurfingPikachu_PlaceBCDNumber
+ inc hl
+ inc hl
+ ld [hl], $21 ; P
+ inc hl
+ ld [hl], $25 ; t
+ inc hl
+ ld [hl], $26 ; s
+ ret
+
+SurfingMinigame_AddPointsToTotal:
+ ld a, [wSurfingMinigameTotalScore]
+ add e
+ daa
+ ld [wSurfingMinigameTotalScore], a
+ ld a, [wSurfingMinigameTotalScore + 1]
+ adc $0
+ daa
+ ld [wSurfingMinigameTotalScore + 1], a
+ ret nc
+ ld a, $99
+ ld [wSurfingMinigameTotalScore], a
+ ld [wSurfingMinigameTotalScore + 1], a
+ ret
+
+SurfingMinigame_BCDPrintTotalScore:
+ ld a, [wSurfingMinigameTotalScore + 1]
+ hlcoord 10, 6
+ call SurfingPikachu_PlaceBCDNumber
+ ld a, [wSurfingMinigameTotalScore]
+ hlcoord 12, 6
+ call SurfingPikachu_PlaceBCDNumber
+ inc hl
+ inc hl
+ ld [hl], $21 ; P
+ inc hl
+ ld [hl], $25 ; t
+ inc hl
+ ld [hl], $26 ; s
+ ret
+
+SurfingMinigame_WriteTotal:
+ ld hl, .Total
+ decoord 2, 6
+ ld bc, $5
+ call CopyData
+ call SurfingMinigame_BCDPrintRadness
+ call SurfingMinigame_BCDPrintTotalScore
+ ret
+
+.Total:
+ db $2b,$2c,$25,$28,$2d ; Total
+
+DidPlayerGetAHighScore:
+ ld hl, wSurfingMinigameHiScore + 1
+ ld a, [wSurfingMinigameTotalScore + 1]
+ cp [hl]
+ jr c, .not_high_score
+ jr nz, .high_score
+ dec hl
+ ld a, [wSurfingMinigameTotalScore]
+ cp [hl]
+ jr c, .not_high_score
+ jr nz, .high_score
+.not_high_score
+ call WaitForSoundToFinish
+ ldpikacry e, PikachuCry28
+ call SurfingMinigame_PlayPikaCryIfSurfingPikaInParty
+ and a
+ ret
+
+.high_score
+ ld a, [wSurfingMinigameTotalScore]
+ ld [wSurfingMinigameHiScore], a
+ ld a, [wSurfingMinigameTotalScore + 1]
+ ld [wSurfingMinigameHiScore + 1], a
+ call WaitForSoundToFinish
+ ldpikacry e, PikachuCry34
+ call SurfingMinigame_PlayPikaCryIfSurfingPikaInParty
+ ld a, SFX_GET_ITEM2_4_2
+ call PlaySound
+ scf
+ ret
+
+SurfingMinigame_PlayPikaCryIfSurfingPikaInParty:
+ push de
+ callfar IsSurfingStarterPikachuInParty
+ pop de
+ ret nc
+ callfar PlayPikachuSoundClip
+ ret
+
+SurfingMinigame_IncreaseRadnessMeter:
+ ld a, [wSurfingMinigameRadnessMeter]
+ inc a
+ cp $4
+ jr c, .cap
+ ld a, $3
+.cap
+ ld [wSurfingMinigameRadnessMeter], a
+ ret
+
+SurfingMinigame_CalculateAndAddRadnessFromStunt:
+ ; Compute the amount of radness points from the
+ ; current trick based on the number of
+ ; consecutive flips
+ ; Single flip: +0050
+ ; 2 of the same flip: +0150
+ ; 3 or more of the same flip: +0350
+ ; 2 different flips: +0180
+ ; 3 or more different flips: +0500
+ ld a, [wSurfingMinigameRadnessMeter]
+ and a
+ ret z
+ ld a, [wSurfingMinigameTrickFlags]
+ and $3
+ cp $3 ; did a combination of front and back flips
+ jr z, .mixed_chain
+ ld a, [wSurfingMinigameRadnessMeter]
+ ld d, a
+ ld e, $1
+ ld a, $0
+.get_amount_of_radness
+ add e
+ sla e
+ dec d
+ jr nz, .get_amount_of_radness
+.add_radness_50_at_a_time
+ push af
+ ld e, $50
+ call SurfingMinigame_AddRadness
+ pop af
+ dec a
+ jr nz, .add_radness_50_at_a_time
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld a, [hl]
+ sub $10
+ ld d, a
+ ld hl, ANIM_OBJ_X_COORD
+ add hl, bc
+ ld e, [hl]
+ ld a, [wSurfingMinigameRadnessMeter]
+ add $3
+ push bc
+ call SpawnAnimatedObject
+ pop bc
+ ret
+
+.mixed_chain
+ ld a, [wSurfingMinigameRadnessMeter]
+ cp $3
+ jr c, .add_180_radness_points
+ ld a, 10
+.add_500_radness_50_at_a_time
+ push af
+ ld e, $50
+ call SurfingMinigame_AddRadness
+ pop af
+ dec a
+ jr nz, .add_500_radness_50_at_a_time
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld a, [hl]
+ sub $10
+ ld d, a
+ ld hl, ANIM_OBJ_X_COORD
+ add hl, bc
+ ld e, [hl]
+ ld a, $9
+ push bc
+ call SpawnAnimatedObject
+ pop bc
+ ret
+
+.add_180_radness_points
+ ld e, $50
+ call SurfingMinigame_AddRadness
+ ld e, $50
+ call SurfingMinigame_AddRadness
+ ld e, $50
+ call SurfingMinigame_AddRadness
+ ld e, $30
+ call SurfingMinigame_AddRadness
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld a, [hl]
+ sub $10
+ ld d, a
+ ld hl, ANIM_OBJ_X_COORD
+ add hl, bc
+ ld e, [hl]
+ ld a, $8
+ push bc
+ call SpawnAnimatedObject
+ pop bc
+ ret
+
+SurfingMinigame_AddRadness:
+ ld a, [wSurfingMinigameRadnessScore]
+ add e
+ daa
+ ld [wSurfingMinigameRadnessScore], a
+ ld a, [wSurfingMinigameRadnessScore + 1]
+ adc $0
+ daa
+ ld [wSurfingMinigameRadnessScore + 1], a
+ ret nc
+ ld a, $99
+ ld [wSurfingMinigameRadnessScore], a
+ ld [wSurfingMinigameRadnessScore + 1], a
+ ret
+
+Func_f8c97:
+ ld a, $a0
+ ld [wSurfingMinigameXOffset], a
+ ldh a, [hSCX]
+ ld h, a
+ ld a, [wSurfingMinigameSCX]
+ ld l, a
+ ld de, $900
+ add hl, de
+ ld a, l
+ ld [wSurfingMinigameSCX], a
+ ld a, h
+ ldh [hSCX], a
+ jr SurfingMinigame_GenerateBGMap
+
+SurfingMinigame_ScrollAndGenerateBGMap:
+ ld a, $a0
+ ld [wSurfingMinigameXOffset], a
+ ldh a, [hSCX]
+ ld h, a
+ ld a, [wSurfingMinigameSCX]
+ ld l, a
+ ld de, $180
+ add hl, de
+ ld a, l
+ ld [wSurfingMinigameSCX], a
+ ld a, h
+ ldh [hSCX], a
+SurfingMinigame_GenerateBGMap:
+ ld hl, wSurfingMinigameSCX2
+ ldh a, [hSCX]
+ cp [hl]
+ ret z
+ ld [hl], a
+ and $f0
+ ld hl, wSurfingMinigameSCXHi
+ cp [hl]
+ ret z
+ ld [hl], a
+ call SurfingMinigame_GetWaveDataPointers
+ ; b and c contain the height of the next wave to appear
+ ; on screen, in number of pixels from the top of the screen
+ ld a, b
+ ld [wSurfingMinigameWaveHeightBuffer], a
+ ld a, c
+ ld [wSurfingMinigameWaveHeightBuffer + 1], a
+ push de
+ ld hl, wSurfingMinigameWaveHeight
+ ld de, wSurfingMinigameWaveHeight + 2
+ ld c, SCREEN_WIDTH - 2
+.copy_loop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .copy_loop
+ ld a, [wSurfingMinigameWaveHeightBuffer]
+ ld [hli], a
+ ld a, [wSurfingMinigameWaveHeightBuffer + 1]
+ ld [hl], a
+ pop de
+ ld hl, wRedrawRowOrColumnSrcTiles
+ ld c, $8
+.loop
+ ld a, [de]
+ call .CopyRedrawSrcTiles
+ inc de
+ dec c
+ jr nz, .loop
+ ld a, [wSurfingMinigameXOffset]
+ ld e, a
+ ldh a, [hSCX]
+ add e
+ and $f0
+ srl a
+ srl a
+ srl a
+ ld e, a
+ ld d, $0
+ ld hl, vBGMap0
+ add hl, de
+ ld a, l
+ ldh [hRedrawRowOrColumnDest], a
+ ld a, h
+ ldh [hRedrawRowOrColumnDest + 1], a
+ ld a, $1
+ ldh [hRedrawRowOrColumnMode], a
+ ret
+
+.CopyRedrawSrcTiles:
+ push de
+ push hl
+ ld l, a
+ ld h, $0
+ ld de, Unkn_f96e5
+ add hl, hl
+ add hl, hl
+ add hl, de
+ ld e, l
+ ld d, h
+ pop hl
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ inc de
+ ld [hli], a
+ pop de
+ ret
+
+SurfingMinigame_GetWaveDataPointers:
+ ld a, [wSurfingMinigameWaveFunctionNumber]
+ ld e, a
+ ld d, $0
+ ld hl, Jumptable_f8d53
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+Jumptable_f8d53:
+ dw SurfingMinigameWaveFunction_NoWave ; 00
+
+ dw Func_f8f28 ; 01
+ dw Func_f8f31 ; 02
+ dw Func_f8f3a ; 03
+ dw Func_f8f43 ; 04
+ dw Func_f8e7d ; 05
+ dw Func_f8f4c ; 06
+ dw Func_f8f55 ; 07
+ dw Func_f8f5e ; 08
+ dw Func_f8e7d ; 09
+ dw Func_f8e7d ; 0a
+ dw Func_f8e7d ; 0b
+ dw Func_f8e7d ; 0c
+ dw Func_f8f94 ; 0d
+
+ dw Func_f8ec5 ; 0e
+ dw Func_f8ece ; 0f
+ dw Func_f8ed7 ; 10
+ dw Func_f8ee0 ; 11
+ dw Func_f8ee9 ; 12
+ dw Func_f8ef2 ; 13
+ dw Func_f8e7d ; 14
+ dw Func_f8e7d ; 15
+ dw Func_f8e7d ; 16
+ dw Func_f8e7d ; 17
+ dw Func_f8e7d ; 18
+ dw Func_f8f94 ; 19
+
+ dw Func_f8efb ; 1a
+ dw Func_f8f04 ; 1b
+ dw Func_f8f0d ; 1c
+ dw Func_f8f16 ; 1d
+ dw Func_f8f1f ; 1e
+ dw Func_f8efb ; 1f
+ dw Func_f8f04 ; 20
+ dw Func_f8f0d ; 21
+ dw Func_f8f16 ; 22
+ dw Func_f8f1f ; 23
+ dw Func_f8e7d ; 24
+ dw Func_f8e7d ; 25
+ dw Func_f8e7d ; 26
+ dw Func_f8e7d ; 27
+ dw Func_f8f94 ; 28
+
+ dw Func_f8f28 ; 29
+ dw Func_f8f31 ; 2a
+ dw Func_f8f3a ; 2b
+ dw Func_f8f43 ; 2c
+ dw Func_f8e7d ; 2d
+ dw Func_f8e7d ; 2e
+ dw Func_f8e7d ; 2f
+ dw Func_f8e7d ; 30
+ dw Func_f8f94 ; 31
+
+ dw Func_f8f4c ; 32
+ dw Func_f8f55 ; 33
+ dw Func_f8f5e ; 34
+ dw Func_f8f4c ; 35
+ dw Func_f8f55 ; 36
+ dw Func_f8f5e ; 37
+ dw Func_f8f4c ; 38
+ dw Func_f8f55 ; 39
+ dw Func_f8f5e ; 3a
+ dw Func_f8e7d ; 3b
+ dw Func_f8e7d ; 3c
+ dw Func_f8e7d ; 3d
+ dw Func_f8e7d ; 3e
+ dw Func_f8f94 ; 3f
+
+ dw Func_f8f67 ; 40
+ dw Func_f8f70 ; 41
+ dw Func_f8efb ; 42
+ dw Func_f8f04 ; 43
+ dw Func_f8f0d ; 44
+ dw Func_f8f16 ; 45
+ dw Func_f8f1f ; 46
+ dw Func_f8f67 ; 47
+ dw Func_f8f70 ; 48
+ dw Func_f8e7d ; 49
+ dw Func_f8e7d ; 4a
+ dw Func_f8e7d ; 4b
+ dw Func_f8f94 ; 4c
+
+ dw Func_f8ec5 ; 4d
+ dw Func_f8ece ; 4e
+ dw Func_f8ed7 ; 4f
+ dw Func_f8ee0 ; 50
+ dw Func_f8ee9 ; 51
+ dw Func_f8ef2 ; 52
+ dw Func_f8e7d ; 53
+ dw Func_f8f67 ; 54
+ dw Func_f8f70 ; 55
+ dw Func_f8f67 ; 56
+ dw Func_f8f70 ; 57
+ dw Func_f8e7d ; 58
+ dw Func_f8e7d ; 59
+ dw Func_f8e7d ; 5a
+ dw Func_f8f94 ; 5b
+
+ dw Func_f8efb ; 5c
+ dw Func_f8f04 ; 5d
+ dw Func_f8f0d ; 5e
+ dw Func_f8f16 ; 5f
+ dw Func_f8f1f ; 60
+ dw Func_f8f28 ; 61
+ dw Func_f8f31 ; 62
+ dw Func_f8f3a ; 63
+ dw Func_f8f43 ; 64
+ dw Func_f8e7d ; 65
+ dw Func_f8e7d ; 66
+ dw Func_f8e7d ; 67
+ dw Func_f8e7d ; 68
+ dw Func_f8f94 ; 69
+
+ dw Func_f8e86 ; 6a
+ dw Func_f8e8f ; 6b
+ dw Func_f8e98 ; 6c
+ dw Func_f8ea1 ; 6d
+ dw Func_f8eaa ; 6e
+ dw Func_f8eb3 ; 6f
+ dw Func_f8ebc ; 70
+ dw Func_f8f9d ; 71
+
+ dw Func_f8e7d ; 72
+ dw Func_f8f79 ; 73
+ dw Func_f8f82 ; 74
+ dw Func_f8f82 ; 75
+ dw Func_f8f82 ; 76
+ dw Func_f8f82 ; 77
+ dw Func_f8f82 ; 78
+ dw Func_f8f82 ; 79
+ dw Func_f8f82 ; 7a
+ dw Func_f8f8b ; 7b
+
+SurfingMinigameWaveFunction_NoWave:
+ ld a, [wc5e5]
+ cp $16
+ jr c, .check_param
+ jr z, .big_kahuna
+ jr nc, .got_wave
+.big_kahuna
+ ld a, $6a
+ jr .got_next_fn
+
+.check_param
+ ld a, [wc5d5]
+ and a
+ jr z, .got_wave
+ dec a
+ and $7
+ ld e, a
+ ld d, $0
+ ld hl, Unkn_f8e75
+ add hl, de
+ ld a, [hl]
+.got_next_fn
+ ld [wSurfingMinigameWaveFunctionNumber], a
+.got_wave
+ lb bc, $74, $74
+ ld de, Unkn_f973d
+ ret
+
+Unkn_f8e75:
+ db $01,$0e,$1a,$29,$32,$40,$4d,$5c
+
+Func_f8e7d:
+ lb bc, $74, $74
+ ld de, Unkn_f973d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8e86:
+ lb bc, $74, $6c
+ ld de, Unkn_f9745
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8e8f:
+ lb bc, $64, $5c
+ ld de, Unkn_f974d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8e98:
+ lb bc, $54, $4c
+ ld de, Unkn_f9755
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8ea1:
+ lb bc, $44, $44
+ ld de, Unkn_f975d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8eaa:
+ lb bc, $44, $4c
+ ld de, Unkn_f9765
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8eb3:
+ lb bc, $54, $5c
+ ld de, Unkn_f976d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8ebc:
+ lb bc, $64, $6c
+ ld de, Unkn_f9775
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8ec5:
+ lb bc, $74, $6c
+ ld de, Unkn_f977d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8ece:
+ lb bc, $64, $5c
+ ld de, Unkn_f9785
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8ed7:
+ lb bc, $54, $4c
+ ld de, Unkn_f978d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8ee0:
+ lb bc, $4c, $4c
+ ld de, Unkn_f9795
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8ee9:
+ lb bc, $54, $5c
+ ld de, Unkn_f979d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8ef2:
+ lb bc, $64, $6c
+ ld de, Unkn_f97a5
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8efb:
+ lb bc, $74, $6c
+ ld de, Unkn_f97ad
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f04:
+ lb bc, $64, $5c
+ ld de, Unkn_f97b5
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f0d:
+ lb bc, $54, $54
+ ld de, Unkn_f97bd
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f16:
+ lb bc, $54, $5c
+ ld de, Unkn_f97c5
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f1f:
+ lb bc, $64, $6c
+ ld de, Unkn_f97cd
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f28:
+ lb bc, $74, $6c
+ ld de, Unkn_f97d5
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f31:
+ lb bc, $64, $5c
+ ld de, Unkn_f97dd
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f3a:
+ lb bc, $5c, $5c
+ ld de, Unkn_f97e5
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f43:
+ lb bc, $64, $6c
+ ld de, Unkn_f97ed
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f4c:
+ lb bc, $74, $6c
+ ld de, Unkn_f97f5
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f55:
+ lb bc, $64, $64
+ ld de, Unkn_f97fd
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f5e:
+ lb bc, $64, $6c
+ ld de, Unkn_f9805
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f67:
+ lb bc, $74, $6c
+ ld de, Unkn_f980d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f70:
+ lb bc, $6c, $6c
+ ld de, Unkn_f9815
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f79:
+ lb bc, $74, $74
+ ld de, Unkn_f981d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f82:
+ lb bc, $74, $74
+ ld de, Unkn_f9825
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f8b:
+ lb bc, $74, $74
+ ld de, Unkn_f9825
+ jp SurfingMinigameWaveFunction_ResetWaveFunction
+
+Func_f8f94:
+ lb bc, $74, $74
+ ld de, Unkn_f973d
+ jp SurfingMinigameWaveFunction_ResetWaveFunction
+
+Func_f8f9d:
+ lb bc, $74, $74
+ ld de, Unkn_f973d
+ ret
+
+Func_f8fa4: ; unused
+ inc a
+ ld [wSurfingMinigameWaveFunctionNumber], a
+ ret
+
+SurfingMinigameWaveFunction_GoToNextWaveFunction:
+ ld hl, wSurfingMinigameWaveFunctionNumber
+ inc [hl]
+ ret
+
+SurfingMinigameWaveFunction_ResetWaveFunction:
+ xor a
+ ld [wSurfingMinigameWaveFunctionNumber], a
+ ret
+
+SurfingPikachuMinigameIntro:
+ call SurfingPikachu_ClearTileMap
+ call ClearSprites
+ call DisableLCD
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call ClearObjectAnimationBuffers
+ ld hl, SurfingPikachu1Graphics3
+ ld de, $8800
+ ld bc, $900
+ ld a, BANK(SurfingPikachu1Graphics3)
+ call FarCopyData
+ ld a, LOW(SurfingPikachuSpawnStateDataPointer)
+ ld [wAnimatedObjectSpawnStateDataPointer], a
+ ld a, HIGH(SurfingPikachuSpawnStateDataPointer)
+ ld [wAnimatedObjectSpawnStateDataPointer + 1], a
+ ld a, LOW(SurfingPikachuObjectJumptable)
+ ld [wAnimatedObjectJumptablePointer], a
+ ld a, HIGH(SurfingPikachuObjectJumptable)
+ ld [wAnimatedObjectJumptablePointer + 1], a
+ ld a, LOW(SurfingPikachuOAMData)
+ ld [wAnimatedObjectOAMDataPointer], a
+ ld a, HIGH(SurfingPikachuOAMData)
+ ld [wAnimatedObjectOAMDataPointer + 1], a
+ ld a, LOW(SurfingPikachuFrames)
+ ld [wAnimatedObjectFramesDataPointer], a
+ ld a, HIGH(SurfingPikachuFrames)
+ ld [wAnimatedObjectFramesDataPointer + 1], a
+ ld a, $c
+ lb de, $74, $58
+ call SpawnAnimatedObject
+ call DrawSurfingPikachuMinigameIntroBackground
+ xor a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ld a, $90
+ ldh [hWY], a
+ ld b, SET_PAL_SURFING_PIKACHU_MINIGAME
+ call RunPaletteCommand
+ ld a, $e3
+ ldh [rLCDC], a
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ call SurfingPikachuMinigame_SetBGPals
+ ld a, $e4
+ ldh [rOBP0], a
+ ld a, $e0
+ ldh [rOBP1], a
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
+ call DelayFrame
+ ld a, MUSIC_SURFING_PIKACHU
+ ld c, BANK(Music_SurfingPikachu)
+ call PlayMusic
+ xor a
+ ld [wSurfingMinigameIntroAnimationFinished], a
+.loop
+ ld a, [wSurfingMinigameIntroAnimationFinished]
+ and a
+ ret nz
+ ld a, $0
+ ld [wCurrentAnimatedObjectOAMBufferOffset], a
+ call RunObjectAnimations
+ call DelayFrame
+ jr .loop
+
+DrawSurfingPikachuMinigameIntroBackground:
+ ld hl, wTileMap
+ ld bc, SCREEN_AREA
+ ld a, $ff
+ call FillMemory
+ ld hl, Tilemap_f90bc
+ decoord 0, 6
+ ld bc, 12 * SCREEN_WIDTH
+ call CopyData
+ ld de, Tilemap_f91c8
+ hlcoord 4, 0
+ lb bc, 6, 12
+ call .CopyBox
+ hlcoord 3, 7
+ lb bc, 3, 15
+ call .FillBoxWithFF
+ ld hl, Tilemap_f91ac
+ decoord 3, 7
+ ld bc, 15
+ call CopyData
+ ld hl, Tilemap_f91bb
+ decoord 4, 9
+ ld bc, 13
+ call CopyData
+ ret
+
+.CopyBox:
+.copy_row
+ push bc
+ push hl
+.copy_col
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .copy_col
+ ld bc, SCREEN_WIDTH
+ pop hl
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .copy_row
+ ret
+
+.FillBoxWithFF:
+.fill_row
+ push bc
+ push hl
+.fill_col
+ ld [hl], $ff
+ inc hl
+ dec c
+ jr nz, .fill_col
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .fill_row
+ ret
+
+Tilemap_f90bc: INCBIN "gfx/surfing_pikachu/unknown_f90bc.tilemap"
+Tilemap_f91ac: INCBIN "gfx/surfing_pikachu/unknown_f91ac.tilemap"
+Tilemap_f91bb: INCBIN "gfx/surfing_pikachu/unknown_f91bb.tilemap"
+Tilemap_f91c8: INCBIN "gfx/surfing_pikachu/unknown_f91c8.tilemap"
+
+SurfingMinigame_UpdateLYOverrides:
+ ld hl, wLYOverrides + $10
+ ld de, wLYOverrides + $11
+ ld c, $80
+ ld a, [hl]
+ push af
+.loop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ pop af
+ ld [hl], a
+ ret
+
+SurfingMinigame_InitScanlineOverrides:
+ ld hl, wLYOverrides
+ ld bc, wLYOverridesEnd - wLYOverrides
+ ld de, $0
+.loop
+ ld a, e
+ and $1f
+ ld e, a
+ push hl
+ ld hl, SurfingMinigame_LYOverridesInitialSineWave
+ add hl, de
+ ld a, [hl]
+ pop hl
+ ld [hli], a
+ inc e
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ ret
+
+SurfingPikachu_GetJoypad_3FrameBuffer:
+ call Joypad
+ ldh a, [hFrameCounter]
+ and a
+ jr nz, .delayed
+ ldh a, [hJoyHeld]
+ ldh [hJoy5], a
+ ld a, $2
+ ldh [hFrameCounter], a
+ ret
+
+.delayed
+ xor a
+ ldh [hJoy5], a
+ ret
+
+SurfingPikachuMinigame_BlankPals:
+ xor a
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ldh [rOBP1], a
+ call UpdateCGBPal_BGP
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
+ ret
+
+SurfingPikachuMinigame_NormalPals:
+ ld a, $e4
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ld a, $e0
+ ldh [rOBP1], a
+ call UpdateCGBPal_BGP
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
+ ret
+
+SurfingPikachu_ClearTileMap:
+ ld hl, wTileMap
+ ld bc, SCREEN_AREA
+ xor a
+ call FillMemory
+ ret
+
+Func_f9284:
+ xor a
+ ld [wc5ed], a
+ ld [wc5ee], a
+ ret
+
+SurfingMinigame_UpdatePikachuHeight:
+ ld a, [wc5ed]
+ and a
+ jr nz, .positive
+ ld a, [wc5ec]
+ ld d, a
+ ld a, [wc5ee]
+ or d
+ jr z, .done
+ ld a, [wc5ee]
+ ld e, a
+ ld hl, -$80
+ add hl, de
+ ld a, l
+ ld [wc5ee], a
+ ld a, h
+ ld [wc5ec], a
+
+ ; -(4 * a ** 2)
+ ld e, a
+ ld d, $0
+ call SurfingMinigame_NTimesDE
+ ld e, l
+ ld d, h
+ ld a, $4
+ call SurfingMinigame_NTimesDE
+ ld a, l
+ xor $ff
+ inc a
+ ld l, a
+ ld a, h
+ xor $ff
+ ld h, a
+
+ push hl
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld d, [hl]
+ ld hl, ANIM_OBJ_FIELD_C
+ add hl, bc
+ ld e, [hl]
+ pop hl
+
+ add hl, de
+ ld e, l
+ ld d, h
+
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld [hl], d
+ ld hl, ANIM_OBJ_FIELD_C
+ add hl, bc
+ ld [hl], e
+ and a
+ ret
+
+.done
+ ld a, $1
+ ld [wc5ed], a
+ and a
+ ret
+
+.positive
+ ld a, [wSurfingMinigamePikachuObjectHeight]
+ ld e, a
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld a, [hl]
+ cp $90
+ jr nc, .okay
+ cp e
+ jr nc, .reset
+.okay
+ ld a, [wc5ec]
+ ld d, a
+ ld a, [wc5ee]
+ ld e, a
+ ld hl, $80
+ add hl, de
+ ld a, l
+ ld [wc5ee], a
+ ld a, h
+ ld [wc5ec], a
+
+ ; 4 * a ** 2
+ ld e, a
+ ld d, $0
+ call SurfingMinigame_NTimesDE
+ ld e, l
+ ld d, h
+ ld a, $4
+ call SurfingMinigame_NTimesDE
+
+ push hl
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld d, [hl]
+ ld hl, ANIM_OBJ_FIELD_C
+ add hl, bc
+ ld e, [hl]
+ pop hl
+
+ add hl, de
+ ld e, l
+ ld d, h
+
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld [hl], d
+ ld hl, ANIM_OBJ_FIELD_C
+ add hl, bc
+ ld [hl], e
+ and a
+ ret
+
+.reset
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld a, [wSurfingMinigamePikachuObjectHeight]
+ ld [hl], a
+ ld hl, ANIM_OBJ_FIELD_C
+ add hl, bc
+ ld [hl], $0
+ scf
+ ret
+
+SurfingMinigame_NTimesDE:
+ 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
+
+SurfingPikachu_PlaceBCDNumber:
+ ld c, a
+ swap a
+ and $f
+ add $d0
+ ld [hli], a
+ ld a, c
+ and $f
+ add $d0
+ ld [hl], a
+ dec de
+ ret
+
+SurfingPikachu_Cosine: ; cosine
+ add $10
+SurfingPikachu_Sine: ; sine
+ and $3f
+ cp $20
+ jr nc, .positive
+ call .GetSine
+ ld a, h
+ ret
+
+.positive
+ and $1f
+ call .GetSine
+ ld a, h
+ xor $ff
+ inc a
+ ret
+
+.GetSine:
+ 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 32
+
+SurfingPikachuSpawnStateDataPointer:
+ db $00, $00, $00 ; 0
+ db $04, $01, $00 ; 1
+ db $11, $02, $00 ; 2
+ db $12, $02, $00 ; 3
+ db $15, $00, $00 ; 4
+ db $16, $00, $00 ; 5
+ db $17, $00, $00 ; 6
+ db $18, $00, $00 ; 7
+ db $19, $00, $00 ; 8
+ db $1a, $00, $00 ; 9
+ db $14, $00, $00 ; a
+ db $13, $03, $00 ; b
+ db $1b, $04, $00 ; c
+
+SurfingPikachuObjectJumptable:
+ dw SurfingMinigameAnimatedObjectFn_nop ; 0
+ dw SurfingMinigameAnimatedObjectFn_Pikachu ; 1
+ dw Func_f87fb ; 2
+ dw SurfingMinigameAnimatedObjectFn_FlippingPika ; 3
+ dw SurfingMinigameAnimatedObjectFn_IntroAnimationPikachu ; 4
+
+SurfingMinigameAnimatedObjectFn_nop:
+ ret
+
+INCLUDE "data/sprite_anims/surfing_pikachu_frames.asm"
+INCLUDE "data/sprite_anims/surfing_pikachu_oam.asm"
+
+SurfingMinigame_LYOverridesInitialSineWave:
+; a sine wave with amplitude 2
+ db 0, 0, 0, 1, 1, 1, 1, 2
+ db 2, 2, 1, 1, 1, 1, 0, 0
+ db 0, 0, 0, -1, -1, -1, -1, -2
+ db -2, -2, -1, -1, -1, -1, 0, 0
+
+Unkn_f96e5:
+ db $00, $00, $00, $00 ; 00
+ db $0b, $0b, $0b, $0b ; 01
+ db $0b, $02, $02, $06 ; 02
+ db $03, $0b, $07, $03 ; 03
+ db $06, $06, $06, $06 ; 04
+ db $07, $07, $07, $07 ; 05
+ db $06, $04, $04, $08 ; 06
+ db $05, $07, $08, $05 ; 07
+ db $0b, $0b, $11, $12 ; 08
+ db $0b, $0b, $13, $03 ; 09
+ db $14, $12, $04, $08 ; 0a
+ db $13, $07, $08, $05 ; 0b
+ db $06, $14, $06, $14 ; 0c
+ db $13, $07, $13, $07 ; 0d
+ db $08, $08, $08, $08 ; 0e
+ db $14, $12, $14, $12 ; 0f
+ db $0b, $11, $02, $14 ; 10
+ db $06, $14, $06, $14 ; 11
+ db $0c, $0c, $0d, $0d ; 12
+ db $0d, $0d, $0d, $0d ; 13
+ db $0e, $0f, $10, $0b ; 14
+ db $12, $13, $12, $13 ; 15
+
+Unkn_f973d:
+ db $00, $00, $00, $01, $01, $01, $01, $01
+Unkn_f9745:
+ db $00, $00, $00, $01, $01, $02, $04, $06
+Unkn_f974d:
+ db $00, $00, $00, $01, $02, $04, $06, $0e
+Unkn_f9755:
+ db $00, $00, $00, $10, $11, $06, $0e, $0e
+Unkn_f975d:
+ db $00, $00, $00, $15, $15, $0e, $0e, $0e
+Unkn_f9765:
+ db $00, $00, $00, $03, $05, $07, $0e, $0e
+Unkn_f976d:
+ db $00, $00, $00, $01, $03, $05, $07, $0e
+Unkn_f9775:
+ db $00, $00, $00, $01, $01, $03, $05, $07
+Unkn_f977d:
+ db $00, $00, $00, $01, $01, $02, $04, $06
+Unkn_f9785:
+ db $00, $00, $00, $01, $02, $04, $06, $0e
+Unkn_f978d:
+ db $00, $00, $00, $08, $0f, $0a, $0e, $0e
+Unkn_f9795:
+ db $00, $00, $00, $09, $0d, $0b, $0e, $0e
+Unkn_f979d:
+ db $00, $00, $00, $01, $03, $05, $07, $0e
+Unkn_f97a5:
+ db $00, $00, $00, $01, $01, $03, $05, $07
+Unkn_f97ad:
+ db $00, $00, $00, $01, $01, $02, $04, $06
+Unkn_f97b5:
+ db $00, $00, $00, $01, $10, $11, $06, $0e
+Unkn_f97bd:
+ db $00, $00, $00, $01, $15, $15, $0e, $0e
+Unkn_f97c5:
+ db $00, $00, $00, $01, $03, $05, $07, $0e
+Unkn_f97cd:
+ db $00, $00, $00, $01, $01, $03, $05, $07
+Unkn_f97d5:
+ db $00, $00, $00, $01, $01, $02, $04, $06
+Unkn_f97dd:
+ db $00, $00, $00, $01, $08, $0f, $0a, $0e
+Unkn_f97e5:
+ db $00, $00, $00, $01, $09, $0d, $0b, $0e
+Unkn_f97ed:
+ db $00, $00, $00, $01, $01, $03, $05, $07
+Unkn_f97f5:
+ db $00, $00, $00, $01, $01, $10, $11, $06
+Unkn_f97fd:
+ db $00, $00, $00, $01, $01, $15, $15, $0e
+Unkn_f9805:
+ db $00, $00, $00, $01, $01, $03, $05, $07
+Unkn_f980d:
+ db $00, $00, $00, $01, $01, $08, $0f, $0a
+Unkn_f9815:
+ db $00, $00, $00, $01, $01, $09, $0d, $0b
+Unkn_f981d:
+ db $00, $00, $00, $14, $14, $14, $14, $14
+Unkn_f9825:
+ db $00, $00, $00, $12, $13, $13, $13, $13
diff --git a/engine/movie/credits.asm b/engine/movie/credits.asm
index 77484a80..dd8050bf 100644
--- a/engine/movie/credits.asm
+++ b/engine/movie/credits.asm
@@ -1,140 +1,130 @@
HallOfFamePC:
- farcall AnimateHallOfFame
+ callfar AnimateHallOfFame
call ClearScreen
ld c, 100
call DelayFrames
+
call DisableLCD
- ld hl, vFont
- ld bc, ($80 tiles) / 2
- call ShiftFontColorIndex
- ld hl, vChars2 tile $60
- ld bc, ($20 tiles) / 2
- call ShiftFontColorIndex
- ld hl, vChars2 tile $7e
- ld bc, TILE_SIZE
- ld a, $ff ; solid black
- call FillMemory
+ ld a, $a7
+ ldh [rWX], a
+ xor a
+ ldh [rSCX], a
+ ldh [rSCY], a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ldh [hWY], a
+ ldh [rWY], a
+ call CreditsLoadFont
hlcoord 0, 0
call FillFourRowsWithBlack
hlcoord 0, 14
call FillFourRowsWithBlack
ld a, %11000000
ldh [rBGP], a
+ call UpdateCGBPal_BGP
call EnableLCD
- ld a, SFX_STOP_ALL_MUSIC
- call PlaySoundWaitForCurrent
+ call StopAllMusic
+ ld hl, vBGMap1
+ call CreditsCopyTileMapToVRAM
+ ld hl, vBGMap0
+ call CreditsCopyTileMapToVRAM
ld c, BANK(Music_Credits)
ld a, MUSIC_CREDITS
call PlayMusic
ld c, 128
call DelayFrames
xor a
- ld [wUnusedCreditsByte], a ; not read
+ ld [wHoFMonSpecies], a
ld [wNumCreditsMonsDisplayed], a
jp Credits
FadeInCredits:
+ ld a, 1
+ ldh [hAutoBGTransferEnabled], a
ld hl, HoFGBPalettes
ld b, 4
.loop
ld a, [hli]
ldh [rBGP], a
+ call UpdateCGBPal_BGP
ld c, 5
call DelayFrames
dec b
jr nz, .loop
ret
+HoFGBPalettes:
+ dc 3, 0, 0, 0
+ dc 3, 1, 0, 0
+ dc 3, 2, 0, 0
+ dc 3, 3, 0, 0
+
DisplayCreditsMon:
+ ld hl, vBGMap1
+ call CreditsCopyTileMapToVRAM
xor a
ldh [hAutoBGTransferEnabled], a
- call SaveScreenTilesToBuffer1
+ ld hl, rLCDC
+ set B_LCDC_BG_MAP, [hl]
+ call SaveScreenTilesToBuffer2
call FillMiddleOfScreenWithWhite
-
- ; display the next monster from CreditsMons
- ld hl, wNumCreditsMonsDisplayed
- ld c, [hl] ; how many monsters have we displayed so far?
- inc [hl]
- ld b, 0
- ld hl, CreditsMons
- add hl, bc ; go that far in the list of monsters and get the next one
- ld a, [hl]
- ld [wCurPartySpecies], a
- ld [wCurSpecies], a
- hlcoord 8, 6
- call GetMonHeader
- call LoadFrontSpriteByMonIndex
- ld hl, vBGMap0 + $c
+ call GetNextCreditsMon
+ ld hl, vBGMap0 + 12
call CreditsCopyTileMapToVRAM
xor a
ldh [hAutoBGTransferEnabled], a
- call LoadScreenTilesFromBuffer1
+ call LoadScreenTilesFromBuffer2DisableBGTransfer
ld hl, vBGMap0
call CreditsCopyTileMapToVRAM
- ld a, $A7
- ldh [rWX], a
- ld hl, vBGMap1
- call CreditsCopyTileMapToVRAM
- call FillMiddleOfScreenWithWhite
ld a, %11111100 ; make the mon a black silhouette
ldh [rBGP], a
-
-; scroll the mon left by one tile 7 times
- ld bc, 7
-.scrollLoop1
+ call UpdateCGBPal_BGP
+ ld hl, rLCDC
+ res B_LCDC_BG_MAP, [hl]
+ ld a, 1
+ ldh [hAutoBGTransferEnabled], a
+ ld b, 0
+ ld c, 10
call ScrollCreditsMonLeft
- dec c
- jr nz, .scrollLoop1
-
-; scroll the mon left by one tile 20 times
-; This time, we have to move the window left too in order to hide the text that
-; is wrapping around to the right side of the screen.
- ld c, 20
-.scrollLoop2
+ call FillLeftHalfOfScreenWithWhite
+ ld c, 10
+ call ScrollCreditsMonLeft
+ call FillRightHalfOfScreenWithWhite
+ ld c, 8
call ScrollCreditsMonLeft
- ldh a, [rWX]
- sub 8
- ldh [rWX], a
- dec c
- jr nz, .scrollLoop2
-
- xor a
- ldh [hWY], a
ld a, %11000000
ldh [rBGP], a
+ call UpdateCGBPal_BGP
+ xor a
+ ldh [hSCX], a
ret
-INCLUDE "data/credits/credits_mons.asm"
-
ScrollCreditsMonLeft:
- ld h, b
- ld l, $20
- call ScrollCreditsMonLeft_SetSCX
- ld h, $0
- ld l, $70
- call ScrollCreditsMonLeft_SetSCX
ld a, b
- add $8
+ ldh [hSCX], a
+ add 8
ld b, a
+ call DelayFrame
+ dec c
+ jr nz, ScrollCreditsMonLeft
ret
-ScrollCreditsMonLeft_SetSCX:
- ldh a, [rLY]
- cp l
- jr nz, ScrollCreditsMonLeft_SetSCX
- ld a, h
- ldh [rSCX], a
-.loop
- ldh a, [rLY]
- cp h
- jr z, .loop
+GetNextCreditsMon:
+ ld hl, wNumCreditsMonsDisplayed
+ ld c, [hl]
+ inc [hl]
+ ld b, 0
+ ld hl, CreditsMons
+ add hl, bc
+ ld a, [hl]
+ ld [wCurPartySpecies], a
+ ld [wCurSpecies], a
+ hlcoord 8, 6
+ call GetMonHeader
+ call LoadFrontSpriteByMonIndex
ret
-HoFGBPalettes:
- dc 3, 0, 0, 0
- dc 3, 1, 0, 0
- dc 3, 2, 0, 0
- dc 3, 3, 0, 0
+INCLUDE "data/credits/credits_mons.asm"
CreditsCopyTileMapToVRAM:
ld a, l
@@ -145,6 +135,23 @@ CreditsCopyTileMapToVRAM:
ldh [hAutoBGTransferEnabled], a
jp Delay3
+CreditsLoadFont:
+ call LoadFontTilePatterns
+ ld hl, vFont
+ ld bc, ($80 tiles) / 2
+ call ShiftFontColorIndex
+
+ call LoadTextBoxTilePatterns
+ ld hl, vChars2 tile $60
+ ld bc, ($20 tiles) / 2
+ call ShiftFontColorIndex
+
+ ld hl, vChars2 tile $7e
+ ld bc, TILE_SIZE
+ ld a, $ff ; solid black
+ call FillMemory
+ ret
+
ShiftFontColorIndex:
; Zero every second byte at hl, writing a total of bc bytes.
; When used on VRAM font characters that contain only black and white shades,
@@ -170,7 +177,40 @@ FillMiddleOfScreenWithWhite:
ld a, ' '
jp FillMemory
-Credits:
+FillLeftHalfOfScreenWithWhite:
+ hlcoord 0, 4
+ push bc
+ call FillHalfOfScreenWithWhite
+ pop bc
+ ret
+
+FillRightHalfOfScreenWithWhite:
+ hlcoord 10, 4
+ push bc
+ call FillHalfOfScreenWithWhite
+ pop bc
+ ret
+
+FillHalfOfScreenWithWhite:
+ ld b, 10
+ ld c, 10
+ ld a, ' '
+.loop
+ push bc
+ push hl
+.innerLoop
+ ld [hli], a
+ dec c
+ jr nz, .innerLoop
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .loop
+ ret
+
+Credits: ; Roll credits
ld de, CreditsOrder
push de
.nextCreditsScreen
@@ -195,58 +235,47 @@ Credits:
jr z, .showCopyrightText
cp CRED_THE_END
jr z, .showTheEnd
- push hl
- push hl
- ld hl, CreditsTextPointers
- add a
- ld c, a
- ld b, 0
- add hl, bc
- ld e, [hl]
- inc hl
- ld d, [hl]
- ld a, [de]
- inc de
- ld c, a
- ld b, -1
- pop hl
- add hl, bc
- call PlaceString
- pop hl
- ld bc, SCREEN_WIDTH * 2
- add hl, bc
+ call PlaceCreditsText
pop de
jr .nextCreditsCommand
+
+.showCopyrightText
+ farcall LoadCopyrightTiles
+ pop de
+ jr .nextCreditsCommand
+
+
.fadeInTextAndShowMon
call FadeInCredits
- ld c, 90
+ ld c, 102
jr .next1
+
.showTextAndShowMon
- ld c, 110
+ ld c, 122
.next1
call DelayFrames
call DisplayCreditsMon
jr .nextCreditsScreen
+
.fadeInText
call FadeInCredits
- ld c, 120
+ ld c, 132
jr .next2
+
.showText
- ld c, 140
+ ld c, 152
.next2
call DelayFrames
jr .nextCreditsScreen
-.showCopyrightText
- push de
- farcall LoadCopyrightTiles
- pop de
- pop de
- jr .nextCreditsCommand
.showTheEnd
- ld c, 16
+ call ShowTheEndGFX
+ pop de
+ ret
+
+ShowTheEndGFX:
+ ld c, 24
call DelayFrames
call FillMiddleOfScreenWithWhite
- pop de
ld de, TheEndGfx
ld hl, vChars2 tile $60
lb bc, BANK(TheEndGfx), (TheEndGfxEnd - TheEndGfx) / TILE_SIZE
@@ -261,8 +290,31 @@ Credits:
TheEndTextString:
; "T H E E N D"
- db $60," ",$62," ",$64," ",$64," ",$66," ",$68,"@"
- db $61," ",$63," ",$65," ",$65," ",$67," ",$69,"@"
+ db $60, " ", $62, " ", $64, " ", $64, " ", $66, " ", $68, "@"
+ db $61, " ", $63, " ", $65, " ", $65, " ", $67, " ", $69, "@"
+
+PlaceCreditsText:
+ push hl
+ push hl
+ ld hl, CreditsTextPointers
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ pop hl
+ ld a, [de]
+ inc de
+ ld c, a
+ ld b, -1
+ add hl, bc
+ call PlaceString
+ pop hl
+ ld bc, SCREEN_WIDTH * 2
+ add hl, bc
+ ret
INCLUDE "data/credits/credits_order.asm"
diff --git a/engine/movie/evolution.asm b/engine/movie/evolution.asm
index b6e541c5..d3b91b4f 100644
--- a/engine/movie/evolution.asm
+++ b/engine/movie/evolution.asm
@@ -9,9 +9,7 @@ EvolveMon:
xor a
ld [wLowHealthAlarm], a
ld [wChannelSoundIDs + CHAN5], a
- dec a ; SFX_STOP_ALL_MUSIC
- ld [wNewSoundID], a
- call PlaySound
+ call StopAllMusic
ld a, $1
ldh [hAutoBGTransferEnabled], a
ld a, SFX_TINK
@@ -67,9 +65,7 @@ EvolveMon:
ld a, [wEvoNewSpecies]
.done
ld [wWholeScreenPaletteMonSpecies], a
- ld a, SFX_STOP_ALL_MUSIC
- ld [wNewSoundID], a
- call PlaySound
+ call StopAllMusic
ld a, [wWholeScreenPaletteMonSpecies]
call PlayCry
ld c, 0
diff --git a/engine/movie/hall_of_fame.asm b/engine/movie/hall_of_fame.asm
index ec457141..7e0a419a 100644
--- a/engine/movie/hall_of_fame.asm
+++ b/engine/movie/hall_of_fame.asm
@@ -58,8 +58,7 @@ AnimateHallOfFame:
ld c, 80
call DelayFrames
hlcoord 2, 13
- ld b, 3
- ld c, 14
+ lb bc, 3, 14
call TextBoxBorder
hlcoord 4, 15
ld de, HallOfFameText
@@ -77,7 +76,7 @@ AnimateHallOfFame:
ld bc, HOF_MON
call AddNTimes
ld [hl], $ff
- call SaveHallOfFameTeams
+ callfar SaveHallOfFameTeams ; useless since in same bank
xor a
ld [wHoFMonSpecies], a
inc a
@@ -122,6 +121,7 @@ HoFShowMonOrPlayer:
call RunPaletteCommand
ld a, %11100100
ldh [rBGP], a
+ call UpdateCGBPal_BGP
ld c, $31 ; back pic
call HoFLoadMonPlayerPicTileIDs
ld d, $a0
@@ -154,12 +154,27 @@ HoFDisplayAndRecordMonInfo:
ld hl, wPartyMonNicks
call GetPartyMonName
call HoFDisplayMonInfo
+ ld a, [wHoFPartyMonIndex]
+ ld [wWhichPokemon], a
+ callfar IsThisPartyMonStarterPikachu
+ jr nc, .asm_70336
+ ldpikacry e, PikachuCry35
+ callfar PlayPikachuSoundClip
+ jr .asm_7033c
+.asm_70336
+ ld a, [wHoFMonSpecies]
+ call PlayCry
+.asm_7033c
jp HoFRecordMonInfo
+Func_7033f:
+ call HoFDisplayMonInfo
+ ld a, [wHoFMonSpecies]
+ jp PlayCry
+
HoFDisplayMonInfo:
hlcoord 0, 2
- ld b, 9
- ld c, 10
+ lb bc, 9, 10
call TextBoxBorder
hlcoord 2, 6
ld de, HoFMonInfoText
@@ -174,8 +189,7 @@ HoFDisplayMonInfo:
ld [wCurSpecies], a
hlcoord 3, 9
predef PrintMonType
- ld a, [wHoFMonSpecies]
- jp PlayCry
+ ret
HoFMonInfoText:
db "LEVEL/"
@@ -186,10 +200,13 @@ HoFLoadPlayerPics:
ld de, RedPicFront
ld a, BANK(RedPicFront)
call UncompressSpriteFromDE
+ ld a, BANK("Sprite Buffers")
+ call OpenSRAM
ld hl, sSpriteBuffer1
ld de, sSpriteBuffer0
ld bc, 2 * SPRITEBUFFERSIZE
call CopyData
+ call CloseSRAM
ld de, vFrontPic
call InterlaceMergeSpriteBuffers
ld de, RedPicBack
@@ -210,12 +227,10 @@ HoFDisplayPlayerStats:
SetEvent EVENT_HALL_OF_FAME_DEX_RATING
predef DisplayDexRating
hlcoord 0, 4
- ld b, 6
- ld c, 10
+ lb bc, 6, 10
call TextBoxBorder
hlcoord 5, 0
- ld b, 2
- ld c, 9
+ lb bc, 2, 9
call TextBoxBorder
hlcoord 7, 2
ld de, wPlayerName
diff --git a/engine/movie/intro.asm b/engine/movie/intro.asm
index 2fa442f9..1381d396 100644
--- a/engine/movie/intro.asm
+++ b/engine/movie/intro.asm
@@ -11,8 +11,7 @@ PlayIntro:
inc a
ldh [hAutoBGTransferEnabled], a
call PlayShootingStar
- call PlayIntroScene
- call GBFadeOutToWhite
+ callfar PlayIntroScene
xor a
ldh [hSCX], a
ldh [hAutoBGTransferEnabled], a
@@ -20,162 +19,6 @@ PlayIntro:
call DelayFrame
ret
-PlayIntroScene:
- ld b, SET_PAL_NIDORINO_INTRO
- call RunPaletteCommand
- ldpal a, SHADE_BLACK, SHADE_DARK, SHADE_LIGHT, SHADE_WHITE
- ldh [rBGP], a
- ldh [rOBP0], a
- ldh [rOBP1], a
- xor a
- ldh [hSCX], a
- ld b, TILEMAP_GENGAR_INTRO_1
- call IntroCopyTiles
- ld a, 0
- ld [wBaseCoordX], a
- ld a, 80
- ld [wBaseCoordY], a
- lb bc, 6, 6
- call InitIntroNidorinoOAM
- lb de, 80 / 2, MOVE_NIDORINO_RIGHT
- call IntroMoveMon
- ret c
-
-; hip
- ld a, SFX_INTRO_HIP
- call PlaySound
- xor a
- ld [wIntroNidorinoBaseTile], a
- ld de, IntroNidorinoAnimation1
- call AnimateIntroNidorino
-; hop
- ld a, SFX_INTRO_HOP
- call PlaySound
- ld de, IntroNidorinoAnimation2
- call AnimateIntroNidorino
- ld c, 10
- call CheckForUserInterruption
- ret c
-
-; hip
- ld a, SFX_INTRO_HIP
- call PlaySound
- ld de, IntroNidorinoAnimation1
- call AnimateIntroNidorino
-; hop
- ld a, SFX_INTRO_HOP
- call PlaySound
- ld de, IntroNidorinoAnimation2
- call AnimateIntroNidorino
- ld c, 30
- call CheckForUserInterruption
- ret c
-
-; raise
- ld b, TILEMAP_GENGAR_INTRO_2
- call IntroCopyTiles
- ld a, SFX_INTRO_RAISE
- call PlaySound
- lb de, 8 / 2, MOVE_GENGAR_LEFT
- call IntroMoveMon
- ld c, 30
- call CheckForUserInterruption
- ret c
-
-; slash
- ld b, TILEMAP_GENGAR_INTRO_3
- call IntroCopyTiles
- ld a, SFX_INTRO_CRASH
- call PlaySound
- lb de, 16 / 2, MOVE_GENGAR_RIGHT
- call IntroMoveMon
-; hip
- ld a, SFX_INTRO_HIP
- call PlaySound
- ld a, (FightIntroFrontMon2 - FightIntroFrontMon) / TILE_SIZE
- ld [wIntroNidorinoBaseTile], a
- ld de, IntroNidorinoAnimation3
- call AnimateIntroNidorino
- ld c, 30
- call CheckForUserInterruption
- ret c
-
- lb de, 8 / 2, MOVE_GENGAR_LEFT
- call IntroMoveMon
- ld b, TILEMAP_GENGAR_INTRO_1
- call IntroCopyTiles
- ld c, 60
- call CheckForUserInterruption
- ret c
-
-; hip
- ld a, SFX_INTRO_HIP
- call PlaySound
- xor a
- ld [wIntroNidorinoBaseTile], a
- ld de, IntroNidorinoAnimation4
- call AnimateIntroNidorino
-; hop
- ld a, SFX_INTRO_HOP
- call PlaySound
- ld de, IntroNidorinoAnimation5
- call AnimateIntroNidorino
- ld c, 20
- call CheckForUserInterruption
- ret c
-
- ld a, (FightIntroFrontMon2 - FightIntroFrontMon) / TILE_SIZE
- ld [wIntroNidorinoBaseTile], a
- ld de, IntroNidorinoAnimation6
- call AnimateIntroNidorino
- ld c, 30
- call CheckForUserInterruption
- ret c
-
-; lunge
- ld a, SFX_INTRO_LUNGE
- call PlaySound
- ld a, (FightIntroFrontMon3 - FightIntroFrontMon) / TILE_SIZE
- ld [wIntroNidorinoBaseTile], a
- ld de, IntroNidorinoAnimation7
- jp AnimateIntroNidorino
-
-AnimateIntroNidorino:
- ld a, [de]
- cp ANIMATION_END
- ret z
- ld [wBaseCoordY], a
- inc de
- ld a, [de]
- ld [wBaseCoordX], a
- push de
- ld c, 6 * 6
- call UpdateIntroNidorinoOAM
- ld c, 5
- call DelayFrames
- pop de
- inc de
- jr AnimateIntroNidorino
-
-UpdateIntroNidorinoOAM:
- ld hl, wShadowOAM
- ld a, [wIntroNidorinoBaseTile]
- ld d, a
-.loop
- ld a, [wBaseCoordY]
- add [hl]
- ld [hli], a ; Y
- ld a, [wBaseCoordX]
- add [hl]
- ld [hli], a ; X
- ld a, d
- ld [hli], a ; tile
- inc hl
- inc d
- dec c
- jr nz, .loop
- ret
-
InitIntroNidorinoOAM:
ld hl, wShadowOAM
ld d, 0
@@ -232,82 +75,17 @@ IntroPlaceBlackTiles:
jr nz, .loop
ret
-IntroMoveMon:
-; d = number of times to move the mon (2 pixels each time)
- ld a, e
- cp MOVE_NIDORINO_RIGHT
- jr z, .moveNidorinoRight
- cp MOVE_GENGAR_LEFT
- jr z, .moveGengarLeft
-; move Gengar right
- ldh a, [hSCX]
- dec a
- dec a
- jr .next
-.moveNidorinoRight
- push de
- ld a, 2
- ld [wBaseCoordX], a
- xor a
- ld [wBaseCoordY], a
- ld c, 6 * 6
- call UpdateIntroNidorinoOAM
- pop de
-.moveGengarLeft
- ldh a, [hSCX]
- inc a
- inc a
-.next
- ldh [hSCX], a
- push de
- ld c, 2
- call CheckForUserInterruption
- pop de
- ret c
- dec d
- jr nz, IntroMoveMon
- ret
-
-IntroCopyTiles:
- hlcoord 13, 7
-
CopyTileIDsFromList_ZeroBaseTileID:
ld c, 0
predef_jump CopyTileIDsFromList
-PlayIntroMoveSound: ; unreferenced
- predef GetIntroMoveSound
- ld a, b
- jp PlaySound
-
-LoadIntroGraphics:
- ld hl, FightIntroBackMon
- ld de, vChars2
- ld bc, FightIntroBackMonEnd - FightIntroBackMon
- ld a, BANK(FightIntroBackMon)
- call FarCopyData2
- ld hl, GameFreakIntro
- ld de, vChars2 + (FightIntroBackMonEnd - FightIntroBackMon)
- ld bc, GameFreakIntroEnd - GameFreakIntro
- ld a, BANK(GameFreakIntro)
- call FarCopyData2
- ld hl, GameFreakIntro
- ld de, vChars1
- ld bc, GameFreakIntroEnd - GameFreakIntro
- ld a, BANK(GameFreakIntro)
- call FarCopyData2
- ld hl, FightIntroFrontMon
- ld de, vChars0
- ld bc, FightIntroFrontMonEnd - FightIntroFrontMon
- ld a, BANK(FightIntroFrontMon)
- jp FarCopyData2
-
PlayShootingStar:
ld b, SET_PAL_GAME_FREAK_INTRO
call RunPaletteCommand
farcall LoadCopyrightAndTextBoxTiles
ldpal a, SHADE_BLACK, SHADE_DARK, SHADE_LIGHT, SHADE_WHITE
ldh [rBGP], a
+ call UpdateCGBPal_BGP
ld c, 180
call DelayFrames
call ClearScreen
@@ -315,7 +93,27 @@ PlayShootingStar:
xor a
ld [wCurOpponent], a
call IntroDrawBlackBars
- call LoadIntroGraphics
+; write the black and white tiles
+ ld hl, vChars2
+ ld bc, $10
+ xor a
+ call FillMemory
+ ld hl, vChars2 + $10
+ ld bc, $10
+ ld a, $ff
+ call FillMemory
+; copy gamefreak logo and others
+ ld hl, GameFreakIntro
+ ld de, vChars2 + $600
+ ld bc, GameFreakIntroEnd - GameFreakIntro
+ ld a, BANK(GameFreakIntro)
+ call FarCopyData
+ ld hl, GameFreakIntro
+ ld de, vChars1
+ ld bc, GameFreakIntroEnd - GameFreakIntro
+ ld a, BANK(GameFreakIntro)
+ call FarCopyData
+
call EnableLCD
ld hl, rLCDC
res B_LCDC_WINDOW, [hl]
@@ -330,12 +128,6 @@ PlayShootingStar:
ld c, 40
call DelayFrames
.next
- ld a, BANK(Music_IntroBattle)
- ld [wAudioROMBank], a
- ld [wAudioSavedROMBank], a
- ld a, MUSIC_INTRO_BATTLE
- ld [wNewSoundID], a
- call PlaySound
call IntroClearMiddleOfScreen
call ClearSprites
jp Delay3
@@ -363,108 +155,8 @@ LoadPresentsGraphic: ; unreferenced
; It was dummied out in the English localization.
ret
-IntroNidorinoAnimation0:
- db 0, 0
- db ANIMATION_END
-
-IntroNidorinoAnimation1:
-; This is a sequence of pixel movements for part of the Nidorino animation. This
-; list describes how Nidorino should hop.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db -2, 2
- db -1, 2
- db 1, 2
- db 2, 2
- db ANIMATION_END
-
-IntroNidorinoAnimation2:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db -2, -2
- db -1, -2
- db 1, -2
- db 2, -2
- db ANIMATION_END
-
-IntroNidorinoAnimation3:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db -12, 6
- db -8, 6
- db 8, 6
- db 12, 6
- db ANIMATION_END
-
-IntroNidorinoAnimation4:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db -8, -4
- db -4, -4
- db 4, -4
- db 8, -4
- db ANIMATION_END
-
-IntroNidorinoAnimation5:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db -8, 4
- db -4, 4
- db 4, 4
- db 8, 4
- db ANIMATION_END
-
-IntroNidorinoAnimation6:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db 2, 0
- db 2, 0
- db 0, 0
- db ANIMATION_END
-
-IntroNidorinoAnimation7:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db -8, -16
- db -7, -14
- db -6, -12
- db -4, -10
- db ANIMATION_END
-
GameFreakIntro:
INCBIN "gfx/splash/gamefreak_presents.2bpp"
INCBIN "gfx/splash/gamefreak_logo.2bpp"
ds TILE_SIZE, $00 ; blank tile
GameFreakIntroEnd:
-
-FightIntroBackMon:
- INCBIN "gfx/intro/gengar.2bpp"
- ds TILE_SIZE, $00 ; blank tile
-FightIntroBackMonEnd:
-
-IF DEF(_RED)
-FightIntroFrontMon:
- INCBIN "gfx/intro/red_nidorino_1.2bpp"
-FightIntroFrontMon2:
- INCBIN "gfx/intro/red_nidorino_2.2bpp"
-FightIntroFrontMon3:
- INCBIN "gfx/intro/red_nidorino_3.2bpp"
-ENDC
-
-IF DEF(_BLUE)
-FightIntroFrontMon:
- INCBIN "gfx/intro/blue_jigglypuff_1.2bpp"
-FightIntroFrontMon2:
- INCBIN "gfx/intro/blue_jigglypuff_2.2bpp"
-FightIntroFrontMon3:
- INCBIN "gfx/intro/blue_jigglypuff_3.2bpp"
-ENDC
-
-FightIntroFrontMonEnd:
-
- ds 16, $00 ; blank tile
diff --git a/engine/movie/intro_yellow.asm b/engine/movie/intro_yellow.asm
new file mode 100644
index 00000000..cd411548
--- /dev/null
+++ b/engine/movie/intro_yellow.asm
@@ -0,0 +1,1090 @@
+PlayIntroScene:
+ ldh a, [rIE]
+ push af
+ xor a
+ ldh [rIF], a
+ ld a, $f
+ ldh [rIE], a
+ ld a, $8
+ ldh [rSTAT], a
+ call InitYellowIntroGFXAndMusic
+ call DelayFrame
+.loop
+ ld a, [wYellowIntroCurrentScene]
+ bit 7, a
+ jr nz, .go_to_title_screen
+ call JoypadLowSensitivity
+ ldh a, [hJoyPressed]
+ and PAD_A | PAD_B | PAD_START
+ jr nz, .go_to_title_screen
+ call Func_f98fc
+ ld a, $0
+ ld [wCurrentAnimatedObjectOAMBufferOffset], a
+ call RunObjectAnimations
+ ld a, [wYellowIntroCurrentScene]
+ cp $7
+ call z, Func_f98a2
+ cp $b
+ call z, Func_f98cb
+ call DelayFrame
+ jr .loop
+
+.go_to_title_screen
+ vc_hook Stop_Reducing_intro_scene_flashing
+ call YellowIntro_BlankPalettes
+ xor a
+ ldh [hLCDCPointer], a
+ call DelayFrame
+ xor a
+ ldh [rIF], a
+ pop af
+ ldh [rIE], a
+ ld a, $90
+ ldh [hWY], a
+ call ClearObjectAnimationBuffers
+ ld hl, wTileMap
+ ld bc, SCREEN_AREA
+ xor a
+ call Bank3E_FillMemory
+ call YellowIntro_BlankOAMBuffer
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ret
+
+Func_f98a2:
+ ld a, [wShadowOAMSprite08Attributes]
+ or $1
+ ld [wShadowOAMSprite08Attributes], a
+ ld a, [wShadowOAMSprite14Attributes]
+ or $1
+ ld [wShadowOAMSprite14Attributes], a
+ ld a, [wShadowOAMSprite16Attributes]
+ or $1
+ ld [wShadowOAMSprite16Attributes], a
+ ld a, [wShadowOAMSprite18Attributes]
+ or $1
+ ld [wShadowOAMSprite18Attributes], a
+ ld a, [wShadowOAMSprite19Attributes]
+ or $1
+ ld [wShadowOAMSprite19Attributes], a
+ ret
+
+Func_f98cb:
+ ld a, [wShadowOAMSprite18Attributes]
+ or $1
+ ld [wShadowOAMSprite18Attributes], a
+ ld a, [wShadowOAMSprite19Attributes]
+ or $1
+ ld [wShadowOAMSprite19Attributes], a
+ ld a, [wShadowOAMSprite20Attributes]
+ or $1
+ ld [wShadowOAMSprite20Attributes], a
+ ld a, [wShadowOAMSprite25Attributes]
+ or $1
+ ld [wShadowOAMSprite25Attributes], a
+ ld a, [wShadowOAMSprite26Attributes]
+ or $1
+ ld [wShadowOAMSprite26Attributes], a
+ ld a, [wShadowOAMSprite28Attributes]
+ or $1
+ ld [wShadowOAMSprite28Attributes], a
+ ret
+
+Func_f98fc:
+ ld a, [wYellowIntroCurrentScene]
+ ld hl, Jumptable_f9906
+ call Func_fa06e
+ jp hl
+
+Jumptable_f9906:
+ dw YellowIntroScene0 ; running pika 1
+ dw YellowIntroScene1 ; wait last
+ dw YellowIntroScene2 ; pikachu kick
+ dw YellowIntroScene3 ; wait last
+ dw YellowIntroScene4 ; running pika 2
+ dw YellowIntroScene5 ; wait last
+ dw YellowIntroScene6 ; surfing pika
+ dw YellowIntroScene7 ; wait last
+ dw YellowIntroScene8 ; running pika 3
+ dw YellowIntroScene9 ; wait last
+ dw YellowIntroScene10 ; flying pika
+ dw YellowIntroScene11 ; wait last
+ dw YellowIntroScene12 ; pika close up
+ dw YellowIntroScene13 ; wait last
+ dw YellowIntroScene14 ; pika thunderbolt
+ dw YellowIntroScene15 ; wait last
+ dw YellowIntroScene16 ; fade to white
+ dw YellowIntroScene17 ; wait and quit
+
+YellowIntro_NextScene:
+ ld hl, wYellowIntroCurrentScene
+ inc [hl]
+ vc_hook Reduce_intro_scene_flashing_0E
+ ret
+
+YellowIntroScene0:
+ xor a
+ ldh [hLCDCPointer], a
+ lb de, $58, $58
+ ld a, $1
+ call YellowIntro_SpawnAnimatedObjectAndSavePointer
+ xor a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ld a, $90
+ ldh [hWY], a
+ ld a, $e4
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ld a, $c4
+ ldh [rOBP1], a
+ call UpdateCGBPal_BGP
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
+ ld a, 130
+ ld [wYellowIntroSceneTimer], a
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene1:
+ call YellowIntro_CheckFrameTimerDecrement
+ ret nc
+ call YellowIntro_MaskCurrentAnimatedObjectStruct
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene2:
+ call YellowIntro_BlankPalsDelay2AndDisableLCD
+ ld c, $8
+ call UpdateMusicCTimes
+ xor a
+ ldh [hLCDCPointer], a
+ ld hl, vBGMap0
+ ld bc, $400
+ xor a
+ call Bank3E_FillMemory
+ call YellowIntroScene2_PlaceGraphic
+ lb de, $58, $b8 ; overloaded
+ ld a, $4 ; overloaded
+ call LoadYellowIntroFlyingSpeedBars
+ ld a, $1
+ call Func_f9e9a
+ call YellowIntro_SetTimerFor128Frames
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene2_PlaceGraphic:
+ ld hl, $98d4 ; (20, 6)
+ ld de, $20
+ ld b, $6
+ ld a, $90
+.row
+ ld c, $6
+ push af
+ push hl
+.col
+ ld [hli], a
+ inc a
+ dec c
+ jr nz, .col
+ pop hl
+ add hl, de
+ pop af
+ add $10
+ dec b
+ jr nz, .row
+ ldh a, [hOnCGB]
+ and a
+ jr z, .dmg_sgb
+ ; We can actually set palettes!
+ ld hl, $98d4 ; (20, 6)
+ ld de, $20
+ ld b, $6
+ ld a, $1
+ ldh [rVBK], a
+.attr_row
+ ld c, $6
+ push hl
+.attr_col
+ ld [hli], a
+ dec c
+ jr nz, .attr_col
+ pop hl
+ add hl, de
+ dec b
+ jr nz, .attr_row
+ xor a
+ ldh [rVBK], a
+.dmg_sgb
+ ret
+
+LoadYellowIntroFlyingSpeedBars:
+ ld hl, YellowIntroFlyingSpeedBarData
+ ld a, $8
+.loop
+; Spawn object $8 at indicated coordinates with indicated speeds
+ push af
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ ld a, [hli]
+ push hl
+ push af
+ ld a, $8
+ call SpawnAnimatedObject
+ pop af
+ ld hl, $b
+ add hl, bc
+ ld [hl], a
+ pop hl
+ pop af
+ dec a
+ jr nz, .loop
+ ret
+
+YellowIntroFlyingSpeedBarData:
+ ; y, x, speed
+ db $d0, $20, $02
+ db $f0, $30, $04
+ db $d0, $40, $06
+ db $c0, $50, $08
+ db $e0, $60, $08
+ db $c0, $70, $06
+ db $e0, $80, $04
+ db $f0, $90, $02
+
+YellowIntroScene3:
+ call YellowIntro_CheckFrameTimerDecrement
+ jr c, .expired
+ ldh a, [hSCX]
+ cp $68
+ ret z
+ add $4
+ ldh [hSCX], a
+ ret
+
+.expired
+ call MaskAllAnimatedObjectStructs
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene4:
+ call YellowIntro_BlankPalsDelay2AndDisableLCD
+ ld c, $5
+ call UpdateMusicCTimes
+ ldh a, [hOnCGB]
+ and a
+ jr z, .dmg_sgb
+ ; We can actually set palettes!
+ ld hl, $98d4
+ ld de, $20
+ ld b, $6
+ ld a, $1
+ ldh [rVBK], a
+ xor a
+.attr_row
+ ld c, $6
+ push hl
+.attr_col
+ ld [hli], a
+ dec c
+ jr nz, .attr_col
+ pop hl
+ add hl, de
+ dec b
+ jr nz, .attr_row
+ xor a
+ ldh [rVBK], a
+.dmg_sgb
+ xor a
+ ldh [hLCDCPointer], a
+ call Func_f9e5f
+ lb de, $58, $58
+ ld a, $2
+ call YellowIntro_SpawnAnimatedObjectAndSavePointer
+ xor a
+ call Func_f9e9a
+ call YellowIntro_SetTimerFor128Frames
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene5:
+ call YellowIntro_CheckFrameTimerDecrement
+ ret nc
+ call YellowIntro_MaskCurrentAnimatedObjectStruct
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene6:
+ call YellowIntro_BlankPalsDelay2AndDisableLCD
+ ld c, $5
+ call UpdateMusicCTimes
+ ld a, LOW(rSCY)
+ ldh [hLCDCPointer], a
+ call YellowIntro_Copy8BitSineWave
+ ld hl, vBGMap0
+ ld bc, $60
+ xor a
+ call Bank3E_FillMemory
+ ld hl, $9860
+ ld c, $10
+ ld a, $20
+.asm_f9a8b
+ ld [hli], a
+ inc a
+ ld [hli], a
+ dec a
+ dec c
+ jr nz, .asm_f9a8b
+ ld hl, $9880
+ ld bc, $300
+ ld a, $10
+ call Bank3E_FillMemory
+ lb de, $40, $f8
+ ld a, $5
+ call YellowIntro_SpawnAnimatedObjectAndSavePointer
+ ld a, $1
+ call Func_f9e9a
+ call YellowIntro_SetTimerFor88Frames
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene7:
+ call YellowIntro_CheckFrameTimerDecrement
+ jr c, .expired
+ ld hl, hSCX
+ inc [hl]
+ inc [hl]
+ ld hl, wLYOverridesBuffer
+ ld de, wLYOverridesBuffer + 1
+ ld a, [hl]
+ push af
+ ld c, $ff
+.shift_loop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .shift_loop
+ pop af
+ ld [hl], a
+ call Request7TileTransferFromC810ToC710
+ ret
+
+.expired
+ call YellowIntro_MaskCurrentAnimatedObjectStruct
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene8:
+ call YellowIntro_BlankPalsDelay2AndDisableLCD
+ ld c, $5
+ call UpdateMusicCTimes
+ xor a
+ ldh [hLCDCPointer], a
+ call Func_f9e5f
+ lb de, $58, $58
+ ld a, $3
+ call YellowIntro_SpawnAnimatedObjectAndSavePointer
+ xor a
+ call Func_f9e9a
+ call YellowIntro_SetTimerFor128Frames
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene9:
+ call YellowIntro_CheckFrameTimerDecrement
+ ret nc
+ call YellowIntro_MaskCurrentAnimatedObjectStruct
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene10:
+ call YellowIntro_BlankPalsDelay2AndDisableLCD
+ ld c, $5
+ call UpdateMusicCTimes
+ xor a
+ ldh [hLCDCPointer], a
+ ld hl, vBGMap0
+ ld bc, $400
+ xor a
+ call Bank3E_FillMemory
+ ld hl, vBGMap0
+ ld bc, $100
+ ld a, $2
+ call Bank3E_FillMemory
+ ld hl, $9900
+ ld de, Unkn_f9b6e
+ lb bc, 6, 20
+ call .FillBGMapBox
+ ld hl, $988c
+ ld de, Unkn_f9be6
+ lb bc, 3, 4
+ call .FillBGMapBox
+ ld hl, $98e3
+ ld de, Unkn_f9bf2
+ lb bc, 2, 2
+ call .FillBGMapBox
+ lb de, $98, $58
+ ld a, $6
+ call YellowIntro_SpawnAnimatedObjectAndSavePointer
+ ld a, $1
+ call Func_f9e9a
+ call YellowIntro_SetTimerFor128Frames
+ call YellowIntro_NextScene
+ ret
+
+.FillBGMapBox:
+.fill_row
+ push bc
+ push hl
+.fill_col
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .fill_col
+ pop hl
+ ld bc, $20
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .fill_row
+ ret
+
+Unkn_f9b6e: INCBIN "gfx/intro/unknown_f9b6e.tilemap"
+Unkn_f9be6: INCBIN "gfx/intro/unknown_f9be6.tilemap"
+Unkn_f9bf2: INCBIN "gfx/intro/unknown_f9bf2.tilemap"
+
+YellowIntroScene11:
+ call YellowIntro_CheckFrameTimerDecrement
+ jr c, .expired
+ ld a, [wYellowIntroSceneTimer]
+ and $7
+ ret nz
+ ld a, [wYellowIntroSceneTimer]
+ and $8
+ sla a
+ sla a
+ sla a
+ ld e, a
+ ld d, $0
+ ld hl, YellowIntroCloudGFX
+ add hl, de
+ ld a, l
+ ldh [hVBlankCopySource], a
+ ld a, h
+ ldh [hVBlankCopySource + 1], a
+ xor a
+ ldh [hVBlankCopyDest], a
+ ld a, $96
+ ldh [hVBlankCopyDest + 1], a
+ ld a, $4
+ ldh [hVBlankCopySize], a
+ ret
+
+.expired
+ call YellowIntro_MaskCurrentAnimatedObjectStruct
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroCloudGFX: INCBIN "gfx/intro/clouds.2bpp"
+
+YellowIntroScene12:
+ call YellowIntro_BlankPalsDelay2AndDisableLCD
+ ld c, $5
+ call UpdateMusicCTimes
+ xor a
+ ldh [hLCDCPointer], a
+ ld hl, vBGMap0
+ ld bc, $80
+ ld a, $1
+ call Bank3E_FillMemory
+ ld hl, $9880
+ ld bc, $140
+ xor a
+ call Bank3E_FillMemory
+ ld hl, $99c0
+ ld bc, $80
+ ld a, $1
+ call Bank3E_FillMemory
+
+ ; paste 8x12 graphic into vBGMap0 at (5, 6) starting at tile 4, skipping 4 vtiles at the end of each row
+ ld hl, $98c5
+ ld de, $20
+ ld a, $4
+ ld b, 8
+.row
+ ld c, 12
+ push hl
+.col
+ ld [hli], a
+ inc a
+ dec c
+ jr nz, .col
+ pop hl
+ add hl, de
+ add $4
+ dec b
+ jr nz, .row
+
+ ld hl, $98c4 ; (4, 6)
+ ld [hl], $3
+ ld hl, $98e4 ; (4, 7)
+ ld [hl], $74
+ ld hl, $99a5 ; (5, 5)
+ ld [hl], $0
+ lb de, $60, $58
+ ld a, $9
+ call YellowIntro_SpawnAnimatedObjectAndSavePointer
+ xor a
+ call Func_f9e9a
+ call YellowIntro_SetTimerFor128Frames
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene13:
+ call YellowIntro_CheckFrameTimerDecrement
+ ret nc
+ lb de, $68, $58
+ ld a, $a
+ call SpawnAnimatedObject
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene14:
+ ld de, YellowIntroPalSequence_f9dd6
+ call YellowIntro_LoadDMGPalAndIncrementCounter
+ jr c, .expired
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ and $f0
+ ldh [rOBP1], a
+ call UpdateCGBPal_BGP
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
+ ret
+
+.expired
+ call MaskAllAnimatedObjectStructs
+ call YellowIntro_BlankOAMBuffer
+ ld hl, wTileMap
+ ld bc, SCREEN_WIDTH * 4
+ ld a, $1
+ call Bank3E_FillMemory
+ hlcoord 0, 4
+ ld bc, SCREEN_WIDTH * 10
+ xor a
+ call Bank3E_FillMemory
+ hlcoord 0, 14
+ ld bc, SCREEN_WIDTH * 4
+ ld a, $1
+ call Bank3E_FillMemory
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ld a, $e4
+ ldh [rOBP0], a
+ ldh [rBGP], a
+ call UpdateCGBPal_BGP
+ call UpdateCGBPal_OBP0
+ lb de, $58, $58
+ ld a, $7
+ call YellowIntro_SpawnAnimatedObjectAndSavePointer
+ call YellowIntro_NextScene
+ ld a, $28
+ vc_hook Reduce_intro_scene_flashing_0F
+ ld [wYellowIntroSceneTimer], a
+ ret
+
+YellowIntroScene15:
+ call YellowIntro_CheckFrameTimerDecrement
+ jr c, .expired
+ ld a, [wYellowIntroSceneTimer]
+ and $3
+ ret nz
+ ldh a, [rOBP0]
+ xor $ff
+ ldh [rOBP0], a
+ ldh a, [rBGP]
+ xor $3
+ ldh [rBGP], a
+ call UpdateCGBPal_BGP
+ call UpdateCGBPal_OBP0
+ ret
+
+.expired
+ xor a
+ ldh [hLCDCPointer], a
+ ld a, $e4
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ call UpdateCGBPal_BGP
+ call UpdateCGBPal_OBP0
+ call YellowIntro_NextScene
+YellowIntroScene16:
+ ld de, YellowIntroPalSequence_f9e0a
+ call YellowIntro_LoadDMGPalAndIncrementCounter
+ jr c, .expired
+ ldh [rOBP0], a
+ ldh [rBGP], a
+ call UpdateCGBPal_BGP
+ call UpdateCGBPal_OBP0
+ ret
+
+.expired
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroPalSequence_f9dd6:
+ db $e4, $c0, $c0, $e4
+ db $e4, $c0, $c0, $e4
+ db $e4, $c0, $c0, $e4
+ db $e4, $c0, $c0, $e4
+ db $e4, $c0, $c0, $e4
+ db $e4, $c0, $c0, $e4
+ db $e4, $c0, $c0, $e4
+ db $e4, $c0, $c0, $e4
+ db $e4, $c0, $c0, $e4
+ db $e4, $c0, $c0, $e4
+ db $e4, $c0, $c0, $e4
+ db $e4, $c0, $c0, $e4
+ db $e4, $c0, $c0, $ff
+
+YellowIntroPalSequence_f9e0a:
+ db $e4, $90, $90, $40
+ db $40, $00, $00, $ff
+
+YellowIntroScene17:
+ ld c, 64
+ call DelayFrames
+ ld hl, wYellowIntroCurrentScene
+ set 7, [hl]
+ ret
+
+YellowIntro_SpawnAnimatedObjectAndSavePointer:
+ call SpawnAnimatedObject
+ ld a, c
+ ld [wYellowIntroAnimatedObjectStructPointer], a
+ ld a, b
+ ld [wYellowIntroAnimatedObjectStructPointer + 1], a
+ ret
+
+YellowIntro_MaskCurrentAnimatedObjectStruct:
+ ld a, [wYellowIntroAnimatedObjectStructPointer]
+ ld c, a
+ ld a, [wYellowIntroAnimatedObjectStructPointer + 1]
+ ld b, a
+ call MaskCurrentAnimatedObjectStruct
+ ret
+
+YellowIntro_SetTimerFor128Frames:
+ ld a, 128
+ ld [wYellowIntroSceneTimer], a
+ ret
+
+YellowIntro_SetTimerFor88Frames:
+ ld a, 88
+ ld [wYellowIntroSceneTimer], a
+ ret
+
+YellowIntro_CheckFrameTimerDecrement:
+ ld hl, wYellowIntroSceneTimer
+ ld a, [hl]
+ and a
+ jr z, .asm_f9e4b
+ dec [hl]
+ and a
+ ret
+
+.asm_f9e4b
+ vc_hook Stop_reducing_intro_scene_flashing_0F
+ scf
+ ret
+
+YellowIntro_LoadDMGPalAndIncrementCounter:
+ ld hl, wYellowIntroSceneTimer
+ ld a, [hl]
+ vc_hook Stop_reducing_intro_scene_flashing_0E
+ inc [hl]
+ ld l, a
+ ld h, $0
+ add hl, de
+ ld a, [hl]
+ cp $ff
+ jr z, .asm_f9e5d
+ and a
+ ret
+
+.asm_f9e5d
+ scf
+ ret
+
+Func_f9e5f:
+ ld hl, vBGMap0
+ ld bc, $80
+ ld a, $1
+ call Bank3E_FillMemory
+ ld hl, $9880
+ ld bc, $140
+ xor a
+ call Bank3E_FillMemory
+ ld hl, $99c0
+ ld bc, $80
+ ld a, $1
+ call Bank3E_FillMemory
+ ret
+
+YellowIntro_BlankPalsDelay2AndDisableLCD:
+ xor a
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ldh [rOBP1], a
+ call UpdateCGBPal_BGP
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
+ call DelayFrame
+ call DelayFrame
+ call DisableLCD
+ ret
+
+Func_f9e9a:
+ ld e, a
+ callfar YellowIntroPaletteAction
+ xor a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ld a, $90
+ ldh [hWY], a
+ ld a, $e3
+ ldh [rLCDC], a
+ ld a, $e4
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ld a, $e0
+ ldh [rOBP1], a
+ call UpdateCGBPal_BGP
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
+ ret
+
+YellowIntro_Copy8BitSineWave:
+ ; Copy this sine wave into wLYOverridesBuffer 8 times (end just before wc900)
+ ld de, wLYOverridesBuffer
+ ld a, $8
+.loop
+ push af
+ ld hl, .SineWave
+ ld bc, .SineWaveEnd - .SineWave
+ call Bank3E_CopyData
+ pop af
+ dec a
+ jr nz, .loop
+ ret
+
+.SineWave:
+; a sine wave with amplitude 4
+ db 0, 0, 1, 2, 2, 3, 3, 3
+ db 4, 3, 3, 3, 2, 2, 1, 0
+ db 0, 0, -1, -2, -2, -3, -3, -3
+ db -4, -3, -3, -3, -2, -2, -1, 0
+.SineWaveEnd:
+
+Request7TileTransferFromC810ToC710:
+ ld a, $10
+ ldh [hVBlankCopySource], a
+ ld a, HIGH(wLYOverridesBuffer)
+ ldh [hVBlankCopySource + 1], a
+ ld a, $10
+ ldh [hVBlankCopyDest], a
+ ld a, HIGH(wLYOverrides)
+ ldh [hVBlankCopyDest + 1], a
+ ld a, $7
+ ldh [hVBlankCopySize], a
+ ret
+
+InitYellowIntroGFXAndMusic:
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ldh [hAutoBGTransferDest], a
+ ld a, $98
+ ldh [hAutoBGTransferDest + 1], a
+ call YellowIntro_BlankTileMap
+ ld hl, wTileMap
+ ld bc, SCREEN_AREA
+ ld a, $1
+ call Bank3E_FillMemory
+ hlcoord 0, 4
+ ld bc, SCREEN_WIDTH * 10
+ xor a
+ call Bank3E_FillMemory
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ld de, YellowIntroGraphics2
+ ld hl, vChars0
+ lb bc, BANK(YellowIntroGraphics2), (YellowIntroGraphics2End - YellowIntroGraphics2 - $10) / $10
+ call CopyVideoData
+ ld de, YellowIntroGraphics1
+ ld hl, vChars2
+ lb bc, BANK(YellowIntroGraphics1), (YellowIntroGraphics1End - YellowIntroGraphics1) / $10
+ call CopyVideoData
+ call ClearObjectAnimationBuffers
+ call LoadYellowIntroObjectAnimationDataPointers
+ ld b, SET_PAL_GENERIC
+ call RunPaletteCommand
+ xor a
+ ld hl, wYellowIntroCurrentScene
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ld a, MUSIC_YELLOW_INTRO
+ ld c, BANK(Music_YellowIntro)
+ call PlayMusic
+ ret
+
+LoadYellowIntroObjectAnimationDataPointers:
+ ld a, LOW(YellowIntro_AnimatedObjectSpawnStateData)
+ ld [wAnimatedObjectSpawnStateDataPointer], a
+ ld a, HIGH(YellowIntro_AnimatedObjectSpawnStateData)
+ ld [wAnimatedObjectSpawnStateDataPointer + 1], a
+ ld a, LOW(YellowIntro_AnimatedObjectJumptable)
+ ld [wAnimatedObjectJumptablePointer], a
+ ld a, HIGH(YellowIntro_AnimatedObjectJumptable)
+ ld [wAnimatedObjectJumptablePointer + 1], a
+ ld a, LOW(YellowIntro_AnimatedObjectOAMData)
+ ld [wAnimatedObjectOAMDataPointer], a
+ ld a, HIGH(YellowIntro_AnimatedObjectOAMData)
+ ld [wAnimatedObjectOAMDataPointer + 1], a
+ ld a, LOW(YellowIntro_AnimatedObjectFramesData)
+ ld [wAnimatedObjectFramesDataPointer], a
+ ld a, HIGH(YellowIntro_AnimatedObjectFramesData)
+ ld [wAnimatedObjectFramesDataPointer + 1], a
+ ret
+
+YellowIntro_BlankTileMap:
+ ld hl, wTileMap
+ ld bc, SCREEN_AREA
+ ld a, $7f
+ call Bank3E_FillMemory
+ ret
+
+Bank3E_CopyData:
+.loop
+ ld a, [hli]
+ ld [de], a
+ inc de
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ ret
+
+Bank3E_FillMemory:
+ push de
+ ld e, a
+.loop
+ ld a, e
+ ld [hli], a
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ pop de
+ ret
+
+YellowIntro_BlankOAMBuffer:
+ ld hl, wShadowOAM
+ ld bc, wShadowOAMEnd - wShadowOAM
+ xor a
+ call Bank3E_FillMemory
+ ret
+
+YellowIntro_BlankPalettes:
+ xor a
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ldh [rOBP1], a
+ call UpdateCGBPal_BGP
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
+ ret
+
+YellowIntro_AnimatedObjectSpawnStateData:
+ db $00, $00, $00
+ db $01, $01, $00
+ db $02, $01, $00
+ db $03, $01, $00
+ db $04, $02, $00
+ db $05, $03, $00
+ db $06, $04, $00
+ db $07, $01, $00
+ db $08, $05, $00
+ db $09, $01, $00
+ db $0a, $01, $00
+
+YellowIntro_AnimatedObjectJumptable:
+ dw Func_fa007
+ dw Func_fa007
+ dw Func_fa008
+ dw Func_fa014
+ dw Func_fa02b
+ dw Func_fa062
+
+Func_fa007:
+ ret
+
+Func_fa008:
+ ld hl, $4
+ add hl, bc
+ ld a, [hl]
+ cp $58
+ ret z
+ sub $4
+ ld [hl], a
+ ret
+
+Func_fa014:
+ ld hl, $4
+ add hl, bc
+ ld a, [hl]
+ cp $58
+ jr z, .asm_fa020
+ add $4
+ ld [hl], a
+.asm_fa020
+ ld hl, $5
+ add hl, bc
+ cp $58
+ ret z
+ add $1
+ ld [hl], a
+ ret
+
+Func_fa02b:
+ ld hl, $b
+ add hl, bc
+ ld e, [hl]
+ ld d, $0
+ ld hl, Jumptable_fa03b
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+Jumptable_fa03b:
+ dw Func_fa03f
+ dw Func_fa051
+
+Func_fa03f:
+ ld hl, $5
+ add hl, bc
+ ld a, [hl]
+ cp $58
+ jr z, .asm_fa04c
+ sub $2
+ ld [hl], a
+ ret
+
+.asm_fa04c
+ ld hl, $b
+ add hl, bc
+ inc [hl]
+Func_fa051:
+ ld hl, $c
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ ld d, $8
+ call Func_fa079
+ ld hl, $7
+ add hl, bc
+ ld [hl], a
+ ret
+
+Func_fa062:
+ ld hl, $b
+ add hl, bc
+ ld a, [hl]
+ ld hl, $4
+ add hl, bc
+ add [hl]
+ ld [hl], a
+ ret
+
+Func_fa06e:
+ ld e, a
+ ld d, $0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ret
+
+Func_fa077: ; cosine
+ add $10
+Func_fa079:
+ and $3f
+ cp $20
+ jr nc, .asm_fa084
+ call Func_fa08e
+ ld a, h
+ ret
+
+.asm_fa084
+ and $1f
+ call Func_fa08e
+ ld a, h
+ xor $ff
+ inc a
+ ret
+
+Func_fa08e:
+ ld e, a
+ ld a, d
+ ld d, $0
+ ld hl, Unkn_fa0aa
+ add hl, de
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld hl, $0
+.asm_fa09d
+ srl a
+ jr nc, .asm_fa0a2
+ add hl, de
+.asm_fa0a2
+ sla e
+ rl d
+ and a
+ jr nz, .asm_fa09d
+ ret
+
+Unkn_fa0aa:
+ sine_table 32
+
+INCLUDE "data/sprite_anims/intro_frames.asm"
+INCLUDE "data/sprite_anims/intro_oam.asm"
+
+INCLUDE "gfx/yellow_intro.asm"
diff --git a/engine/movie/oak_speech/clear_save.asm b/engine/movie/oak_speech/clear_save.asm
index f4a278b3..f44a12b9 100644
--- a/engine/movie/oak_speech/clear_save.asm
+++ b/engine/movie/oak_speech/clear_save.asm
@@ -5,6 +5,8 @@ DoClearSaveDialogue:
call LoadTextBoxTilePatterns
ld hl, ClearSaveDataText
call PrintText
+ ld a, PAD_B
+ ld [wJoyIgnore], a
hlcoord 14, 7
lb bc, 8, 15
ld a, NO_YES_MENU
@@ -12,6 +14,8 @@ DoClearSaveDialogue:
ld a, TWO_OPTION_MENU
ld [wTextBoxID], a
call DisplayTextBoxID
+ ld a, 0
+ ld [wJoyIgnore], a
ld a, [wCurrentMenuItem]
and a
jp z, Init
diff --git a/engine/movie/oak_speech/init_player_data.asm b/engine/movie/oak_speech/init_player_data.asm
index bd4f86a4..90fb8f0e 100644
--- a/engine/movie/oak_speech/init_player_data.asm
+++ b/engine/movie/oak_speech/init_player_data.asm
@@ -12,6 +12,11 @@ InitPlayerData2:
ld a, $ff
ld [wUnusedPlayerDataByte], a
+ ld a, 90 ; initialize happiness to 90
+ ld [wPikachuHappiness], a
+ ld a, $80
+ ld [wPikachuMood], a ; initialize mood
+
ld hl, wPartyCount
call InitializeEmptyList
ld hl, wBoxCount
diff --git a/engine/movie/oak_speech/oak_speech.asm b/engine/movie/oak_speech/oak_speech.asm
index a5f13def..4d615126 100644
--- a/engine/movie/oak_speech/oak_speech.asm
+++ b/engine/movie/oak_speech/oak_speech.asm
@@ -10,6 +10,8 @@ PrepareOakSpeech:
; In non-debug builds, the instructions can be removed.
ld a, [wStatusFlags6]
push af
+ ld a, [wPrinterSettings]
+ push af
ld hl, wPlayerName
ld bc, wBoxDataEnd - wPlayerName
xor a
@@ -18,6 +20,12 @@ PrepareOakSpeech:
ld bc, wSpriteDataEnd - wSpriteDataStart
xor a
call FillMemory
+ xor a
+ ld [wSurfingMinigameHiScore], a
+ ld [wSurfingMinigameHiScore + 1], a
+ ld [wSurfingMinigameHiScore + 2], a
+ pop af
+ ld [wPrinterSettings], a
pop af
ld [wStatusFlags6], a
pop af
@@ -37,11 +45,11 @@ PrepareOakSpeech:
ld hl, DebugNewGameRivalName
ld de, wRivalName
ld bc, NAME_LENGTH
- jp CopyData
+ call CopyData ; rip optimizations
+ ret
OakSpeech:
- ld a, SFX_STOP_ALL_MUSIC
- call PlaySound
+ call StopAllMusic
ld a, BANK(Music_Routes2)
ld c, a
ld a, MUSIC_ROUTES2
@@ -72,7 +80,7 @@ OakSpeech:
call PrintText
call GBFadeOutToWhite
call ClearScreen
- ld a, NIDORINO
+ ld a, STARTER_PIKACHU
ld [wCurSpecies], a
ld [wCurPartySpecies], a
call GetMonHeader
@@ -120,13 +128,13 @@ OakSpeech:
; bug: switching ROM Bank should not happen outside of Home Bank
; This code does nothing, as PlaySound does all necessary Bank switch
; It looks like a leftover from an early development stage
- ldh [hLoadedROMBank], a
- ld [rROMB], a
+ call BankswitchCommon
ld c, 4
call DelayFrames
- ld de, RedSprite
ld hl, vSprites
- lb bc, BANK(RedSprite), $0C
+ ld de, RedSprite
+ ld b, BANK(RedSprite)
+ ld c, $0C
call CopyVideoData
ld de, ShrinkPic1
lb bc, BANK(ShrinkPic1), $00
@@ -144,18 +152,14 @@ OakSpeech:
ld [wAudioSavedROMBank], a
ld a, 10
ld [wAudioFadeOutControl], a
- ld a, SFX_STOP_ALL_MUSIC
- ld [wNewSoundID], a
- call PlaySound
+ call StopAllMusic
pop af
; bug: switching ROM Bank should not happen outside of Home Bank
- ldh [hLoadedROMBank], a
- ld [rROMB], a
+ call BankswitchCommon
ld c, 20
call DelayFrames
hlcoord 6, 5
- ld b, 7
- ld c, 7
+ lb bc, 7, 7
call ClearScreenArea
call LoadTextBoxTilePatterns
ld a, 1
@@ -163,7 +167,8 @@ OakSpeech:
ld c, 50
call DelayFrames
call GBFadeOutToWhite
- jp ClearScreen
+ call ClearScreen
+ ret
OakSpeechText1:
text_far _OakSpeechText1
@@ -171,8 +176,7 @@ OakSpeechText1:
OakSpeechText2:
text_far _OakSpeechText2A
- ; BUG: The cry played does not match the sprite displayed.
- sound_cry_nidorina
+ sound_cry_pikachu
text_far _OakSpeechText2B
text_end
@@ -194,6 +198,7 @@ FadeInIntroPic:
.next
ld a, [hli]
ldh [rBGP], a
+ call UpdateCGBPal_BGP
ld c, 10
call DelayFrames
dec b
@@ -215,6 +220,7 @@ MovePicLeft:
ld a, %11100100
ldh [rBGP], a
+ call UpdateCGBPal_BGP
.next
call DelayFrame
ldh a, [rWX]
@@ -233,10 +239,13 @@ IntroDisplayPicCenteredOrUpperRight:
push bc
ld a, b
call UncompressSpriteFromDE
+ ld a, BANK("Sprite Buffers")
+ call OpenSRAM
ld hl, sSpriteBuffer1
ld de, sSpriteBuffer0
ld bc, 2 * SPRITEBUFFERSIZE
call CopyData
+ call CloseSRAM
ld de, vFrontPic
call InterlaceMergeSpriteBuffers
pop bc
diff --git a/engine/movie/oak_speech/oak_speech2.asm b/engine/movie/oak_speech/oak_speech2.asm
index bff12f62..9beb4945 100644
--- a/engine/movie/oak_speech/oak_speech2.asm
+++ b/engine/movie/oak_speech/oak_speech2.asm
@@ -108,6 +108,7 @@ OakSpeechSlidePicCommon:
.loop
xor a
ldh [hAutoBGTransferEnabled], a
+ ldh [hAutoBGTransferPortion], a
ldh a, [hSlideDirection]
and a
jr nz, .slideLeft
@@ -129,8 +130,8 @@ OakSpeechSlidePicCommon:
; If sliding left, we need to zero the last tile in the pic (there is no need
; to take a corresponding action when sliding right because hl initially points
; to a 0 tile in that case).
- xor a
dec hl
+ xor a
ld [hl], a
.next3
ld a, 1
@@ -162,8 +163,7 @@ OakSpeechSlidePicCommon:
DisplayIntroNameTextBox:
push de
hlcoord 0, 0
- ld b, $a
- ld c, $9
+ lb bc, 10, 9
call TextBoxBorder
hlcoord 3, 0
ld de, .namestring
diff --git a/engine/movie/splash.asm b/engine/movie/splash.asm
index cc5526ae..8ac0c26e 100644
--- a/engine/movie/splash.asm
+++ b/engine/movie/splash.asm
@@ -3,6 +3,8 @@ LoadShootingStarGraphics:
ldh [rOBP0], a
ld a, $a4
ldh [rOBP1], a
+ call UpdateCGBPal_OBP0
+ call UpdateCGBPal_OBP1
ld de, MoveAnimationTiles1 tile 3 ; star tile (top left quadrant)
ld hl, vChars1 tile $20
lb bc, BANK(MoveAnimationTiles1), 1
@@ -75,6 +77,7 @@ AnimateShootingStar:
ld hl, rOBP0
rrc [hl]
rrc [hl]
+ call UpdateCGBPal_OBP0
ld c, 10
call CheckForUserInterruption
ret c
@@ -118,6 +121,15 @@ AnimateShootingStar:
ld [hli], a ; X
inc de
inc hl
+ push bc
+ ld a, [de]
+ ld b, a
+ ld a, [hl]
+ and $f0
+ or b
+ ld [hl], a
+ inc de
+ pop bc
inc hl
dec c
jr nz, .smallStarsInnerLoop
@@ -162,24 +174,32 @@ SmallStarsWaveCoordsPointerTable:
SmallStarsWave1Coords:
db $68, $30
- db $68, $40
+ db $05, $68
+ db $40, $05
db $68, $58
- db $68, $78
+ db $04, $68
+ db $78, $07
SmallStarsWave2Coords:
db $68, $38
- db $68, $48
+ db $05, $68
+ db $48, $06
db $68, $60
- db $68, $70
+ db $04, $68
+ db $70, $07
SmallStarsWave3Coords:
db $68, $34
- db $68, $4C
+ db $05, $68
+ db $4c, $06
db $68, $54
- db $68, $64
+ db $06, $68
+ db $64, $07
SmallStarsWave4Coords:
- db $68, $3C
- db $68, $5C
- db $68, $6C
- db $68, $74
+ db $68, $3c
+ db $05, $68
+ db $5c, $04
+ db $68, $6c
+ db $07, $68
+ db $74, $07
SmallStarsEmptyWave:
db -1 ; end
@@ -200,7 +220,7 @@ MoveDownSmallStars:
ldh a, [rOBP1]
xor %10100000
ldh [rOBP1], a
-
+ call UpdateCGBPal_OBP1
ld c, 3
call CheckForUserInterruption
ret c
@@ -228,10 +248,10 @@ GameFreakLogoOAMData:
GameFreakLogoOAMDataEnd:
GameFreakShootingStarOAMData:
- dbsprite 20, 0, 0, 0, $a0, OAM_PAL1
- dbsprite 21, 0, 0, 0, $a0, OAM_PAL1 | OAM_XFLIP
- dbsprite 20, 1, 0, 0, $a1, OAM_PAL1
- dbsprite 21, 1, 0, 0, $a1, OAM_PAL1 | OAM_XFLIP
+ dbsprite 20, 0, 0, 0, $a0, OAM_PAL1 | OAM_HIGH_PALS
+ dbsprite 21, 0, 0, 0, $a0, OAM_PAL1 | OAM_HIGH_PALS | OAM_XFLIP
+ dbsprite 20, 1, 0, 0, $a1, OAM_PAL1 | OAM_HIGH_PALS
+ dbsprite 21, 1, 0, 0, $a1, OAM_PAL1 | OAM_HIGH_PALS | OAM_XFLIP
GameFreakShootingStarOAMDataEnd:
FallingStar:
diff --git a/engine/movie/title.asm b/engine/movie/title.asm
index c9ea4b47..4ff22800 100644
--- a/engine/movie/title.asm
+++ b/engine/movie/title.asm
@@ -1,7 +1,3 @@
-CopyDebugName:
- ld bc, NAME_LENGTH
- jp CopyData
-
PrepareTitleScreen::
; These debug names are already copied later in PrepareOakSpeech.
; Removing the unused copies below has no apparent impact.
@@ -40,98 +36,32 @@ DisplayTitleScreen:
call DisableLCD
call LoadFontTilePatterns
ld hl, NintendoCopyrightLogoGraphics
- ld de, vTitleLogo2 tile 16
+ ld de, vTitleLogo tile $60
ld bc, 5 tiles
ld a, BANK(NintendoCopyrightLogoGraphics)
- call FarCopyData2
+ call FarCopyData
+ ld hl, NineTile
+ ld de, vTitleLogo tile $6e
+ ld bc, 1 tiles
+ ld a, BANK(NineTile)
+ call FarCopyData
ld hl, GameFreakLogoGraphics
- ld de, vTitleLogo2 tile (16 + 5)
+ ld de, vTitleLogo tile $65
ld bc, 9 tiles
ld a, BANK(GameFreakLogoGraphics)
- call FarCopyData2
- ld hl, PokemonLogoGraphics
- ld de, vTitleLogo
- ld bc, $60 tiles
- ld a, BANK(PokemonLogoGraphics)
- call FarCopyData2 ; first chunk
- ld hl, PokemonLogoGraphics tile $60
- ld de, vTitleLogo2
- ld bc, $10 tiles
- ld a, BANK(PokemonLogoGraphics)
- call FarCopyData2 ; second chunk
- ld hl, Version_GFX
- ld de, vChars2 tile $60 + (10 tiles - (Version_GFXEnd - Version_GFX) * 2) / 2
- ld bc, Version_GFXEnd - Version_GFX
- ld a, BANK(Version_GFX)
- call FarCopyDataDouble
- call ClearBothBGMaps
-
-; place tiles for pokemon logo (except for the last row)
- hlcoord 2, 1
- ld a, $80
- ld de, SCREEN_WIDTH
- ld c, 6
-.pokemonLogoTileLoop
- ld b, $10
- push hl
-.pokemonLogoTileRowLoop ; place tiles for one row
- ld [hli], a
- inc a
- dec b
- jr nz, .pokemonLogoTileRowLoop
- pop hl
- add hl, de
- dec c
- jr nz, .pokemonLogoTileLoop
-
-; place tiles for the last row of the pokemon logo
- hlcoord 2, 7
- ld a, $31
- ld b, $10
-.pokemonLogoLastTileRowLoop
- ld [hli], a
- inc a
- dec b
- jr nz, .pokemonLogoLastTileRowLoop
-
- call DrawPlayerCharacter
-
-; put a pokeball in the player's hand
- ld hl, wShadowOAMSprite10
- ld a, $74
- ld [hl], a
-
-; place tiles for title screen copyright
- hlcoord 2, 17
- ld de, .tileScreenCopyrightTiles
- ld b, .tileScreenCopyrightTilesEnd - .tileScreenCopyrightTiles
-.tileScreenCopyrightTilesLoop
- ld a, [de]
- ld [hli], a
- inc de
- dec b
- jr nz, .tileScreenCopyrightTilesLoop
-
- jr .next
-
-.tileScreenCopyrightTiles
- db $41,$42,$43,$42,$44,$42,$45,$46,$47,$48,$49,$4A,$4B,$4C,$4D,$4E ; ©'95.'96.'98 GAME FREAK inc.
-.tileScreenCopyrightTilesEnd
-
-.next
+ call FarCopyData
+ callfar LoadYellowTitleScreenGFX
+ ld hl, vBGMap0
+ ld bc, (vBGMap1 tile $40) - vBGMap0
+ ld a, ' '
+ call FillMemory
+ callfar TitleScreen_PlacePokemonLogo
+ call FillSpriteBuffer0WithAA
+ call .WriteCopyrightTiles
call SaveScreenTilesToBuffer2
call LoadScreenTilesFromBuffer2
call EnableLCD
-
-IF DEF(_RED)
- ld a, STARTER1 ; which Pokemon to show first on the title screen
-ENDC
-IF DEF(_BLUE)
- ld a, STARTER2 ; which Pokemon to show first on the title screen
-ENDC
- ld [wTitleMonSpecies], a
- call LoadTitleMonSprite
-
+ callfar TitleScreen_PlacePikachu
ld a, HIGH(vBGMap0 + $300)
call TitleScreenCopyTileMapToVRAM
call SaveScreenTilesToBuffer1
@@ -143,8 +73,9 @@ ENDC
ld b, SET_PAL_TITLE_SCREEN
call RunPaletteCommand
call GBPalNormal
- ld a, %11100100
+ ld a, %11100000
ldh [rOBP0], a
+ call UpdateCGBPal_OBP0
; make pokemon logo bounce up and down
ld bc, hSCY ; background scroll Y
@@ -186,6 +117,21 @@ ENDC
jr nz, .ScrollTitleScreenPokemonLogo
ret
+; place tiles for title screen copyright
+.WriteCopyrightTiles
+ hlcoord 2, 17
+ ld de, .tileScreenCopyrightTiles
+.titleScreenCopyrightTilesLoop
+ ld a, [de]
+ inc de
+ cp $ff
+ ret z
+ ld [hli], a
+ jr .titleScreenCopyrightTilesLoop
+
+.tileScreenCopyrightTiles
+ db $e0,$e1,$e2,$e3,$e1,$e2,$ee,$e5,$e6,$e7,$e8,$e9,$ea,$eb,$ec,$ed,$ff ; ©1995-1999 GAME FREAK inc.
+
.finishedBouncingPokemonLogo
call LoadScreenTilesFromBuffer1
ld c, 36
@@ -193,53 +139,46 @@ ENDC
ld a, SFX_INTRO_WHOOSH
call PlaySound
-; scroll game version in from the right
- call PrintGameVersionOnTitleScreen
+ callfar TitleScreen_PlacePikaSpeechBubble
ld a, SCREEN_HEIGHT_PX
ldh [hWY], a
- ld d, 144
-.scrollTitleScreenGameVersionLoop
- ld h, d
- ld l, 64
- call ScrollTitleScreenGameVersion
- ld h, 0
- ld l, 80
- call ScrollTitleScreenGameVersion
- ld a, d
- add 4
- ld d, a
- and a
- jr nz, .scrollTitleScreenGameVersionLoop
-
- ld a, HIGH(vBGMap1)
- call TitleScreenCopyTileMapToVRAM
- call LoadScreenTilesFromBuffer2
- call PrintGameVersionOnTitleScreen
call Delay3
+ ldpikacry e, PikachuCry1
+ call TitleScreen_PlayPikachuPCM
call WaitForSoundToFinish
+ call StopAllMusic
ld a, MUSIC_TITLE_SCREEN
ld [wNewSoundID], a
call PlaySound
+.loop
xor a
ld [wUnusedFlag], a
+ ld [wTitleScreenScene], a
+ ld [wTitleScreenScene + 1], a
+ ld [wTitleScreenScene + 2], a
+ ld [wTitleScreenScene + 3], a
+ ld a, $f
+ ld [wTitleScreenScene + 4], a
+.titleScreenLoop
+ call IncrementResetCounter
+ jp c, .doTitlescreenReset
+ call DelayFrame
+ call JoypadLowSensitivity
+ ldh a, [hJoyHeld]
+ cp PAD_UP | PAD_SELECT | PAD_B
+ jr z, .go_to_main_menu
+IF DEF(_DEBUG)
+ and PAD_A | PAD_SELECT | PAD_START
+ELSE
+ and PAD_A | PAD_START
+ENDC
+ jr nz, .go_to_main_menu
+ call DoTitleScreenFunction
+ jr .titleScreenLoop
-; Keep scrolling in new mons indefinitely until the user performs input.
-.awaitUserInterruptionLoop
- ld c, 200
- call CheckForUserInterruption
- jr c, .finishedWaiting
- call TitleScreenScrollInMon
- ld c, 1
- call CheckForUserInterruption
- jr c, .finishedWaiting
- farcall TitleScreenAnimateBallIfStarterOut
- call TitleScreenPickNewMon
- jr .awaitUserInterruptionLoop
-
-.finishedWaiting
- ld a, [wTitleMonSpecies]
- call PlayCry
- call WaitForSoundToFinish
+.go_to_main_menu
+ ldpikacry e, PikachuCry11
+ call TitleScreen_PlayPikachuPCM
call GBPalWhiteOutWithDelay3
call ClearSprites
xor a
@@ -261,112 +200,45 @@ ENDC
IF DEF(_DEBUG)
ld a, b
bit B_PAD_SELECT, a
- jp nz, DebugMenu
-ENDC
+ jp z, MainMenu
+ callfar DebugMenu
+ jp hl
+ELSE
jp MainMenu
+ENDC
-.doClearSaveDialogue
- farjp DoClearSaveDialogue
-
-TitleScreenPickNewMon:
- ld a, HIGH(vBGMap0)
- call TitleScreenCopyTileMapToVRAM
-
-.loop
-; Keep looping until a mon different from the current one is picked.
- call Random
- and $f
- ld c, a
- ld b, 0
- ld hl, TitleMons
- add hl, bc
- ld a, [hl]
- ld hl, wTitleMonSpecies
-
-; Can't be the same as before.
- cp [hl]
- jr z, .loop
-
- ld [hl], a
- call LoadTitleMonSprite
-
- ld a, $90
- ldh [hWY], a
- ld d, 1 ; scroll out
- farcall TitleScroll
- ret
-
-TitleScreenScrollInMon:
- ld d, 0 ; scroll in
- farcall TitleScroll
- xor a
- ldh [hWY], a
- ret
-
-ScrollTitleScreenGameVersion:
-.wait
- ldh a, [rLY]
- cp l
- jr nz, .wait
-
- ld a, h
- ldh [rSCX], a
-
-.wait2
- ldh a, [rLY]
- cp h
- jr z, .wait2
- ret
+.asm_42f0
+; unreferenced
+ callfar PrinterDebug
+ jp .loop
-DrawPlayerCharacter:
- ld hl, PlayerCharacterTitleGraphics
- ld de, vSprites
- ld bc, PlayerCharacterTitleGraphicsEnd - PlayerCharacterTitleGraphics
- ld a, BANK(PlayerCharacterTitleGraphics)
- call FarCopyData2
- call ClearSprites
- xor a
- ld [wPlayerCharacterOAMTile], a
- ld hl, wShadowOAM
- lb de, $60, $5a
- ld b, 7
-.loop
- push de
- ld c, 5
-.innerLoop
- ld a, d
- ld [hli], a ; Y
- ld a, e
- ld [hli], a ; X
- add 8
- ld e, a
- ld a, [wPlayerCharacterOAMTile]
- ld [hli], a ; tile
+.asm_42fb
+; unreferenced
+ ld a, [wTitleScreenScene + 4]
inc a
- ld [wPlayerCharacterOAMTile], a
- inc hl
- dec c
- jr nz, .innerLoop
- pop de
- ld a, 8
- add d
- ld d, a
- dec b
- jr nz, .loop
- ret
+ cp NUM_PIKA_CRIES
+ jr c, .asm_4305
+ ldpikacry a, PikachuCry16
+.asm_4305
+ ld [wTitleScreenScene + 4], a
+ ld e, a
+ callfar PlayPikachuSoundClip
+ xor a
+ ld [wTitleScreenScene + 2], a
+ ld [wTitleScreenScene + 3], a
+ jp .titleScreenLoop
-ClearBothBGMaps:
- ld hl, vBGMap0
- ld bc, 2 * TILEMAP_AREA
- ld a, ' '
- jp FillMemory
+.doTitlescreenReset
+ ld [wAudioFadeOutControl], a
+ call StopAllMusic
+.audioFadeLoop
+ ld a, [wAudioFadeOutControl]
+ and a
+ jr nz, .audioFadeLoop
+ jp Init
-LoadTitleMonSprite:
- ld [wCurPartySpecies], a
- ld [wCurSpecies], a
- hlcoord 5, 10
- call GetMonHeader
- jp LoadFrontSpriteByMonIndex
+.doClearSaveDialogue
+ farjp DoClearSaveDialogue
TitleScreenCopyTileMapToVRAM:
ldh [hAutoBGTransferDest + 1], a
@@ -381,37 +253,133 @@ LoadCopyrightAndTextBoxTiles:
LoadCopyrightTiles:
ld de, NintendoCopyrightLogoGraphics
ld hl, vChars2 tile $60
- lb bc, BANK(NintendoCopyrightLogoGraphics), (GameFreakLogoGraphicsEnd - NintendoCopyrightLogoGraphics) / TILE_SIZE
+ lb bc, BANK(NintendoCopyrightLogoGraphics), (TextBoxGraphics + $10 - NintendoCopyrightLogoGraphics) / TILE_SIZE ; bug: overflows into text box graphics and copies the "A" tile
call CopyVideoData
hlcoord 2, 7
ld de, CopyrightTextString
jp PlaceString
CopyrightTextString:
- db $60,$61,$62,$61,$63,$61,$64,$7F,$65,$66,$67,$68,$69,$6A ; ©'95.'96.'98 Nintendo
- next $60,$61,$62,$61,$63,$61,$64,$7F,$6B,$6C,$6D,$6E,$6F,$70,$71,$72 ; ©'95.'96.'98 Creatures inc.
- next $60,$61,$62,$61,$63,$61,$64,$7F,$73,$74,$75,$76,$77,$78,$79,$7A,$7B ; ©'95.'96.'98 GAME FREAK inc.
+ db $60,$61,$62,$63,$61,$62,$7c,$7f,$65,$66,$67,$68,$69,$6a ; ©1995-1999 Nintendo
+ next $60,$61,$62,$63,$61,$62,$7c,$7f,$6b,$6c,$6d,$6e,$6f,$70,$71,$72 ; ©1995-1999 Creatures inc.
+ next $60,$61,$62,$63,$61,$62,$7c,$7f,$73,$74,$75,$76,$77,$78,$79,$7a,$7b ; ©1995-1999 GAME FREAK inc.
db "@"
-INCLUDE "data/pokemon/title_mons.asm"
+TitleScreen_PlayPikachuPCM:
+ callfar PlayPikachuSoundClip
+ ret
-; prints version text (red, blue)
-PrintGameVersionOnTitleScreen:
- hlcoord 7, 8
- ld de, VersionOnTitleScreenText
- jp PlaceString
+DoTitleScreenFunction:
+ call .CheckTimer
+ ld a, [wTitleScreenScene]
+ 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
-; these point to special tiles specifically loaded for that purpose and are not usual text
-VersionOnTitleScreenText:
-IF DEF(_RED)
- db $60,$61,$7F,$65,$66,$67,$68,$69,"@" ; "Red Version"
-ENDC
-IF DEF(_BLUE)
- db $61,$62,$63,$64,$65,$66,$67,$68,"@" ; "Blue Version"
-ENDC
+.Jumptable:
+ dw .Nop
+ dw .BlinkHalf
+ dw .BlinkWait
+ dw .BlinkWait
+ dw .BlinkClosed
+ dw .BlinkWait
+ dw .BlinkWait
+ dw .BlinkHalf
+ dw .BlinkWait
+ dw .BlinkWait
+ dw .BlinkOpen
+ dw .GoBackToStart
+
+.GoBackToStart:
+ xor a
+ ld [wTitleScreenScene], a
+.Nop
+ ret
+
+.BlinkOpen:
+ ld e, 0
+ jr .LoadBlinkFrame
+
+.BlinkHalf:
+ ld e, 4
+ jr .LoadBlinkFrame
+
+.BlinkClosed:
+ ld e, 8
+.LoadBlinkFrame:
+ ld hl, wShadowOAMSprite00TileID
+ ld c, 8
+.loop
+ ld a, [hl]
+ and $f3
+ or e
+ ld [hli], a
+ inc hl
+ inc hl
+ inc hl
+ dec c
+ jr nz, .loop
+.BlinkWait:
+ ld hl, wTitleScreenScene
+ inc [hl]
+ ret
+
+.CheckTimer:
+ ld hl, wTitleScreenTimer
+ ld a, [hl]
+ inc [hl]
+ and a
+ jr z, .restart
+ cp $80
+ jr z, .restart
+ cp $90
+ ret nz
+.restart
+ ld a, $1
+ ld [wTitleScreenScene], a
+ ret
+
+CopyDebugName:
+ ld bc, NAME_LENGTH
+ jp CopyData
DebugNewGamePlayerName:
db "NINTEN@"
DebugNewGameRivalName:
db "SONY@"
+
+IncrementResetCounter:
+ ld hl, wTitleScreenScene + 2
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc de
+ ld a, d
+ cp $c
+ jr z, .doReset
+ ld [hl], d
+ dec hl
+ ld [hl], e
+ and a
+ ret
+
+.doReset
+ scf
+ ret
+
+FillSpriteBuffer0WithAA:
+ xor a
+ call OpenSRAM
+ ld hl, sSpriteBuffer0
+ ld bc, $20
+ ld a, $aa
+ call FillMemory
+ call CloseSRAM
+ ret
diff --git a/engine/movie/title2.asm b/engine/movie/title_rb.asm
index bc75015f..0c0c121e 100644
--- a/engine/movie/title2.asm
+++ b/engine/movie/title_rb.asm
@@ -1,3 +1,5 @@
+; Leftover of Red/Blue. Seemingly unused
+
TitleScroll_WaitBall:
; Wait around for the TitleBall animation to play out.
; hi: speed
@@ -89,12 +91,12 @@ TitleBallYTable:
TitleScreenAnimateBallIfStarterOut:
; Animate the TitleBall if a starter just got scrolled out.
- ld a, [wTitleMonSpecies]
- cp STARTER1
+ ld a, [wTitleScreenScene]
+ cp CHARMANDER ; starter 1
jr z, .ok
- cp STARTER2
+ cp SQUIRTLE ; starter 2
jr z, .ok
- cp STARTER3
+ cp BULBASAUR ; starter 3
ret nz
.ok
ld e, 1 ; animate titleball
diff --git a/engine/movie/title_yellow.asm b/engine/movie/title_yellow.asm
new file mode 100644
index 00000000..1e5b7929
--- /dev/null
+++ b/engine/movie/title_yellow.asm
@@ -0,0 +1,109 @@
+LoadYellowTitleScreenGFX:
+ ld hl, PokemonLogoGraphics
+ ld de, vChars2
+ ld bc, PokemonLogoGraphicsEnd - PokemonLogoGraphics
+ ld a, BANK(PokemonLogoGraphics)
+ call FarCopyData
+ ld hl, PokemonLogoCornerGraphics
+ ld de, vChars1 tile $7d
+ ld bc, PokemonLogoCornerGraphicsEnd - PokemonLogoCornerGraphics
+ ld a, BANK(PokemonLogoCornerGraphics)
+ call FarCopyData
+ ld hl, TitlePikachuBGGraphics
+ ld de, vChars1
+ ld bc, TitlePikachuBGGraphicsEnd - TitlePikachuBGGraphics
+ ld a, BANK(TitlePikachuBGGraphics)
+ call FarCopyData
+ ld hl, TitlePikachuOBGraphics
+ ld de, vChars1 tile $70
+ ld bc, TitlePikachuOBGraphicsEnd - TitlePikachuOBGraphics
+ ld a, BANK(TitlePikachuOBGraphics)
+ call FarCopyData
+ ret
+
+TitleScreen_PlacePokemonLogo:
+ hlcoord 2, 1
+ ld de, TitleScreenPokemonLogoTilemap
+ lb bc, 7, 16
+ call Bank3D_CopyBox
+ ret
+
+TitleScreen_PlacePikaSpeechBubble:
+ hlcoord 6, 4
+ ld de, TitleScreenPikaBubbleTilemap
+ lb bc, 4, 7
+ call Bank3D_CopyBox
+ hlcoord 9, 8
+ ld [hl], $64
+ inc hl
+ ld [hl], $65
+ ret
+
+TitleScreen_PlacePikachu:
+ hlcoord 4, 8
+ ld de, TitleScreenPikachuTilemap
+ lb bc, 9, 12
+ call Bank3D_CopyBox
+ hlcoord 16, 10
+ ld [hl], $96
+ hlcoord 16, 11
+ ld [hl], $9d
+ hlcoord 16, 12
+ ld [hl], $a7
+ hlcoord 16, 13
+ ld [hl], $b1
+ ld hl, TitleScreenPikachuEyesOAMData
+ ld de, wShadowOAM
+ ld bc, $20
+ call CopyData
+ ret
+
+TitleScreenPikachuEyesOAMData:
+ db $60, $40, $f1, $22
+ db $60, $48, $f0, $22
+ db $68, $40, $f3, $22
+ db $68, $48, $f2, $22
+ db $60, $60, $f0, $02
+ db $60, $68, $f1, $02
+ db $68, $60, $f2, $02
+ db $68, $68, $f3, $02
+
+Bank3D_CopyBox:
+; copy cxb (xy) screen area from de to hl
+.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
+
+TitleScreenPokemonLogoTilemap: ; 16x7
+ INCBIN "gfx/title/pokemon_logo.tilemap"
+
+Pointer_f4669: ; unreferenced
+ db $47, $48, $49, $4a, $4b, $4c, $4d, $4e, $4f, $5f
+
+TitleScreenPikaBubbleTilemap: ; 7x4
+ INCBIN "gfx/title/pika_bubble.tilemap"
+
+TitleScreenPikachuTilemap: ; 12x9
+ INCBIN "gfx/title/pikachu.tilemap"
+
+PokemonLogoGraphics: INCBIN "gfx/title/pokemon_logo.2bpp"
+PokemonLogoGraphicsEnd:
+PokemonLogoCornerGraphics: INCBIN "gfx/title/pokemon_logo_corner.2bpp"
+PokemonLogoCornerGraphicsEnd:
+TitlePikachuBGGraphics: INCBIN "gfx/title/pikachu_bg.2bpp"
+TitlePikachuBGGraphicsEnd:
+TitlePikachuOBGraphics: INCBIN "gfx/title/pikachu_ob.2bpp"
+TitlePikachuOBGraphicsEnd:
diff --git a/engine/movie/trade.asm b/engine/movie/trade.asm
index 292f47cd..f0c813bc 100644
--- a/engine/movie/trade.asm
+++ b/engine/movie/trade.asm
@@ -20,12 +20,13 @@ ExternalClockTradeAnim:
TradeAnimCommon:
ld a, [wOptions]
push af
+ and %110000 ; preserve speaker options
+ ld [wOptions], a
ldh a, [hSCY]
push af
ldh a, [hSCX]
push af
xor a
- ld [wOptions], a
ldh [hSCY], a
ldh [hSCX], a
push de
@@ -160,12 +161,12 @@ LoadTradingGFXAndMonNames:
ld de, vChars2 tile $31
ld bc, TradingAnimationGraphicsEnd - TradingAnimationGraphics
ld a, BANK(TradingAnimationGraphics)
- call FarCopyData2
+ call FarCopyData
ld hl, TradingAnimationGraphics2
ld de, vSprites tile $7c
ld bc, TradingAnimationGraphics2End - TradingAnimationGraphics2
ld a, BANK(TradingAnimationGraphics2)
- call FarCopyData2
+ call FarCopyData
ld hl, vBGMap0
ld bc, 2 * TILEMAP_AREA
ld a, ' '
@@ -182,6 +183,7 @@ LoadTradingGFXAndMonNames:
ld a, $f0 ; SGB OBP0
.next
ldh [rOBP0], a
+ call UpdateCGBPal_OBP0
call EnableLCD
xor a
ldh [hAutoBGTransferEnabled], a
@@ -199,6 +201,7 @@ LoadTradingGFXAndMonNames:
Trade_LoadMonPartySpriteGfx:
ld a, %11010000
ldh [rOBP1], a
+ call UpdateCGBPal_OBP1
farjp LoadMonPartySpriteGfx
Trade_SwapNames:
@@ -233,8 +236,7 @@ Trade_ShowPlayerMon:
xor a
ldh [hAutoBGTransferEnabled], a
hlcoord 4, 0
- ld b, 6
- ld c, 10
+ lb bc, 6, 10
call TextBoxBorder
call Trade_PrintPlayerMonInfoText
ld b, HIGH(vBGMap0)
@@ -303,6 +305,7 @@ Trade_AnimateBallEnteringLinkCable:
call DelayFrames
ld a, %11100100
ldh [rOBP0], a
+ call UpdateCGBPal_OBP0
xor a
ld [wLinkCableAnimBulgeToggle], a
lb bc, $20, $60
@@ -356,8 +359,7 @@ Trade_ShowEnemyMon:
call Trade_ShowAnimation
call Trade_ShowClearedWindow
hlcoord 4, 10
- ld b, 6
- ld c, 10
+ lb bc, 6, 10
call TextBoxBorder
call Trade_PrintEnemyMonInfoText
call Trade_CopyTileMapToVRAM
@@ -384,6 +386,7 @@ Trade_AnimLeftToRight:
ld [wTradedMonMovingRight], a
ld a, %11100100
ldh [rOBP0], a
+ call UpdateCGBPal_OBP0
ld a, $54
ld [wBaseCoordX], a
ld a, $1c
@@ -448,6 +451,8 @@ Trade_InitGameboyTransferGfx:
ld a, $1
ldh [hAutoBGTransferEnabled], a
call ClearScreen
+ ld b, SET_PAL_GENERIC
+ call RunPaletteCommand
xor a
ldh [hAutoBGTransferEnabled], a
call Trade_LoadMonPartySpriteGfx
@@ -481,8 +486,7 @@ Trade_DrawLeftGameboy:
; draw text box with player name below gameboy pic
hlcoord 4, 12
- ld b, 2
- ld c, 7
+ lb bc, 2, 7
call TextBoxBorder
hlcoord 5, 14
ld de, wPlayerName
@@ -528,8 +532,7 @@ Trade_DrawRightGameboy:
; draw text box with enemy name above link cable
hlcoord 6, 0
- ld b, 2
- ld c, 7
+ lb bc, 2, 7
call TextBoxBorder
hlcoord 7, 2
ld de, wLinkEnemyTrainerName
@@ -601,6 +604,7 @@ Trade_AnimCircledMon:
ldh a, [rBGP]
xor $3c ; make link cable flash
ldh [rBGP], a
+ call UpdateCGBPal_BGP
ld hl, wShadowOAMSprite00TileID
ld de, OBJ_SIZE
ld c, $14
diff --git a/engine/overworld/advance_player_sprite.asm b/engine/overworld/advance_player_sprite.asm
new file mode 100644
index 00000000..314883dd
--- /dev/null
+++ b/engine/overworld/advance_player_sprite.asm
@@ -0,0 +1,244 @@
+_AdvancePlayerSprite::
+ ld a, [wSpritePlayerStateData1YStepVector]
+ ld b, a
+ ld a, [wSpritePlayerStateData1XStepVector]
+ ld c, a
+ ld hl, wWalkCounter
+ dec [hl]
+ jr nz, .afterUpdateMapCoords
+; if it's the end of the animation, update the player's map coordinates
+ ld hl, wPikachuOverworldStateFlags
+ res 5, [hl]
+ ld a, [wYCoord]
+ add b
+ ld [wYCoord], a
+ ld a, [wXCoord]
+ add c
+ ld [wXCoord], a
+.afterUpdateMapCoords
+ ld a, [wWalkCounter]
+ cp $07
+ jp nz, .scrollBackgroundAndSprites
+; if this is the first iteration of the animation
+ ld a, c
+ cp $01
+ jr nz, .checkIfMovingWest
+; moving east
+ ld a, [wMapViewVRAMPointer]
+ ld e, a
+ and $e0
+ ld d, a
+ ld a, e
+ add $02
+ and $1f
+ or d
+ ld [wMapViewVRAMPointer], a
+ jr .adjustXCoordWithinBlock
+.checkIfMovingWest
+ cp $ff
+ jr nz, .checkIfMovingSouth
+; moving west
+ ld a, [wMapViewVRAMPointer]
+ ld e, a
+ and $e0
+ ld d, a
+ ld a, e
+ sub $02
+ and $1f
+ or d
+ ld [wMapViewVRAMPointer], a
+ jr .adjustXCoordWithinBlock
+.checkIfMovingSouth
+ ld a, b
+ cp $01
+ jr nz, .checkIfMovingNorth
+; moving south
+ ld a, [wMapViewVRAMPointer]
+ add $40
+ ld [wMapViewVRAMPointer], a
+ jr nc, .adjustXCoordWithinBlock
+ ld a, [wMapViewVRAMPointer + 1]
+ inc a
+ and $03
+ or $98
+ ld [wMapViewVRAMPointer + 1], a
+ jr .adjustXCoordWithinBlock
+.checkIfMovingNorth
+ cp $ff
+ jr nz, .adjustXCoordWithinBlock
+; moving north
+ ld a, [wMapViewVRAMPointer]
+ sub $40
+ ld [wMapViewVRAMPointer], a
+ jr nc, .adjustXCoordWithinBlock
+ ld a, [wMapViewVRAMPointer + 1]
+ dec a
+ and $03
+ or $98
+ ld [wMapViewVRAMPointer + 1], a
+.adjustXCoordWithinBlock
+ ld a, c
+ and a
+ jr z, .pointlessJump ; mistake?
+.pointlessJump
+ ld hl, wXBlockCoord
+ ld a, [hl]
+ add c
+ ld [hl], a
+ cp $02
+ jr nz, .checkForMoveToWestBlock
+; moved into the tile block to the east
+ xor a
+ ld [hl], a
+ ld hl, wXOffsetSinceLastSpecialWarp
+ inc [hl]
+ ld de, wCurrentTileBlockMapViewPointer
+ call MoveTileBlockMapPointerEast
+ jr .updateMapView
+.checkForMoveToWestBlock
+ cp $ff
+ jr nz, .adjustYCoordWithinBlock
+; moved into the tile block to the west
+ ld a, $01
+ ld [hl], a
+ ld hl, wXOffsetSinceLastSpecialWarp
+ dec [hl]
+ ld de, wCurrentTileBlockMapViewPointer
+ call MoveTileBlockMapPointerWest
+ jr .updateMapView
+.adjustYCoordWithinBlock
+ ld hl, wYBlockCoord
+ ld a, [hl]
+ add b
+ ld [hl], a
+ cp $02
+ jr nz, .checkForMoveToNorthBlock
+; moved into the tile block to the south
+ xor a
+ ld [hl], a
+ ld hl, wYOffsetSinceLastSpecialWarp
+ inc [hl]
+ ld de, wCurrentTileBlockMapViewPointer
+ ld a, [wCurMapWidth]
+ call MoveTileBlockMapPointerSouth
+ jr .updateMapView
+.checkForMoveToNorthBlock
+ cp $ff
+ jr nz, .updateMapView
+; moved into the tile block to the north
+ ld a, $01
+ ld [hl], a
+ ld hl, wYOffsetSinceLastSpecialWarp
+ dec [hl]
+ ld de, wCurrentTileBlockMapViewPointer
+ ld a, [wCurMapWidth]
+ call MoveTileBlockMapPointerNorth
+.updateMapView
+ call LoadCurrentMapView
+ ld a, [wSpritePlayerStateData1YStepVector]
+ cp $01
+ jr nz, .checkIfMovingNorth2
+; if moving south
+ call ScheduleSouthRowRedraw
+ jr .scrollBackgroundAndSprites
+.checkIfMovingNorth2
+ cp $ff
+ jr nz, .checkIfMovingEast2
+; if moving north
+ call ScheduleNorthRowRedraw
+ jr .scrollBackgroundAndSprites
+.checkIfMovingEast2
+ ld a, [wSpritePlayerStateData1XStepVector]
+ cp $01
+ jr nz, .checkIfMovingWest2
+; if moving east
+ call ScheduleEastColumnRedraw
+ jr .scrollBackgroundAndSprites
+.checkIfMovingWest2
+ cp $ff
+ jr nz, .scrollBackgroundAndSprites
+; if moving west
+ call ScheduleWestColumnRedraw
+.scrollBackgroundAndSprites
+ ld a, [wSpritePlayerStateData1YStepVector]
+ add a
+ ld b, a
+ ld a, [wSpritePlayerStateData1XStepVector]
+ add a
+ ld c, a
+; shift all the sprites in the direction opposite of the player's motion
+; so that the player appears to move relative to them
+ ld hl, wSprite01StateData1YPixels
+ ld e, 15
+.spriteShiftLoop
+ ld a, [hl]
+ sub b
+ ld [hli], a
+ inc l
+ ld a, [hl]
+ sub c
+ ld [hl], a
+ ld a, $0e
+ add l
+ ld l, a
+ dec e
+ jr nz, .spriteShiftLoop
+.done
+ ldh a, [hSCY]
+ add b
+ ldh [hSCY], a ; update background scroll Y
+ ldh a, [hSCX]
+ add c
+ ldh [hSCX], a ; update background scroll X
+ ret
+
+; the following four functions are used to move the pointer to the upper left
+; corner of the tile block map in the direction of motion
+
+MoveTileBlockMapPointerEast::
+ ld a, [de]
+ add $01
+ ld [de], a
+ ret nc
+ inc de
+ ld a, [de]
+ inc a
+ ld [de], a
+ ret
+
+MoveTileBlockMapPointerWest::
+ ld a, [de]
+ sub $01
+ ld [de], a
+ ret nc
+ inc de
+ ld a, [de]
+ dec a
+ ld [de], a
+ ret
+
+MoveTileBlockMapPointerSouth::
+ add MAP_BORDER * 2
+ ld b, a
+ ld a, [de]
+ add b
+ ld [de], a
+ ret nc
+ inc de
+ ld a, [de]
+ inc a
+ ld [de], a
+ ret
+
+MoveTileBlockMapPointerNorth::
+ add MAP_BORDER * 2
+ ld b, a
+ ld a, [de]
+ sub b
+ ld [de], a
+ ret nc
+ inc de
+ ld a, [de]
+ dec a
+ ld [de], a
+ ret
diff --git a/engine/overworld/auto_movement.asm b/engine/overworld/auto_movement.asm
index dc5fc385..2266e866 100644
--- a/engine/overworld/auto_movement.asm
+++ b/engine/overworld/auto_movement.asm
@@ -37,8 +37,8 @@ _EndNPCMovementScript::
res BIT_EXITING_DOOR, [hl]
xor a
ld [wNPCMovementScriptSpriteOffset], a
- ld [wNPCMovementScriptPointerTableNum], a
ld [wNPCMovementScriptFunctionNum], a
+ ld [wNPCMovementScriptPointerTableNum], a
ld [wUnusedOverrideSimulatedJoypadStatesIndex], a
ld [wSimulatedJoypadStatesIndex], a
ld [wSimulatedJoypadStatesEnd], a
@@ -79,6 +79,10 @@ PalletMovementScript_OakMoveLeft:
ld a, $3
ld [wNPCMovementScriptFunctionNum], a
.done
+ ld a, BANK(Music_MuseumGuy)
+ ld c, a
+ ld a, MUSIC_MUSEUM_GUY
+ call PlayMusic
ld hl, wStatusFlags7
set BIT_NO_MAP_MUSIC, [hl]
ld a, PAD_SELECT | PAD_START | PAD_CTRL_PAD
@@ -127,8 +131,9 @@ PalletMovementScript_WalkToLab:
ld [wNPCMovementScriptFunctionNum], a
ret
+
RLEList_ProfOakWalkToLab:
- db NPC_MOVEMENT_DOWN, 5
+ db NPC_MOVEMENT_DOWN, 6 ; differs from red
db NPC_MOVEMENT_LEFT, 1
db NPC_MOVEMENT_DOWN, 5
db NPC_MOVEMENT_RIGHT, 3
@@ -141,7 +146,7 @@ RLEList_PlayerWalkToLab:
db PAD_RIGHT, 3
db PAD_DOWN, 5
db PAD_LEFT, 1
- db PAD_DOWN, 6
+ db PAD_DOWN, 7 ; differs from red
db -1 ; end
PalletMovementScript_Done:
@@ -163,11 +168,9 @@ PewterMuseumGuyMovementScriptPointerTable::
PewterMovementScript_WalkToMuseum:
ld a, BANK(Music_MuseumGuy)
- ld [wAudioROMBank], a
- ld [wAudioSavedROMBank], a
+ ld c, a
ld a, MUSIC_MUSEUM_GUY
- ld [wNewSoundID], a
- call PlaySound
+ call PlayMusic
ld a, [wSpriteIndex]
swap a
ld [wNPCMovementScriptSpriteOffset], a
@@ -179,7 +182,7 @@ PewterMovementScript_WalkToMuseum:
ld [wSimulatedJoypadStatesIndex], a
xor a
ld [wWhichPewterGuy], a
- predef PewterGuys
+ call PewterGuys
ld hl, wNPCMovementDirections2
ld de, RLEList_PewterMuseumGuy
call DecodeRLEList
@@ -219,11 +222,9 @@ PewterGymGuyMovementScriptPointerTable::
PewterMovementScript_WalkToGym:
ld a, BANK(Music_MuseumGuy)
- ld [wAudioROMBank], a
- ld [wAudioSavedROMBank], a
+ ld c, a
ld a, MUSIC_MUSEUM_GUY
- ld [wNewSoundID], a
- call PlaySound
+ call PlayMusic
ld a, [wSpriteIndex]
swap a
ld [wNPCMovementScriptSpriteOffset], a
@@ -236,7 +237,7 @@ PewterMovementScript_WalkToGym:
ld [wSimulatedJoypadStatesIndex], a
ld a, 1
ld [wWhichPewterGuy], a
- predef PewterGuys
+ call PewterGuys
ld hl, wNPCMovementDirections2
ld de, RLEList_PewterGymGuy
call DecodeRLEList
@@ -266,27 +267,4 @@ RLEList_PewterGymGuy:
db NPC_MOVEMENT_RIGHT, 3
db -1 ; end
-SetEnemyTrainerToStayAndFaceAnyDirection::
- ld a, [wCurMap]
- cp POKEMON_TOWER_7F
- ret z ; the Rockets on Pokemon Tower 7F leave after battling, so don't set them
- ld hl, RivalIDs
- ld a, [wEngagedTrainerClass]
- ld b, a
-.loop
- ld a, [hli]
- cp -1
- jr z, .notRival
- cp b
- ret z ; the rival leaves after battling, so don't set him
- jr .loop
-.notRival
- ld a, [wSpriteIndex]
- ldh [hSpriteIndex], a
- jp SetSpriteMovementBytesToFF
-
-RivalIDs:
- db OPP_RIVAL1
- db OPP_RIVAL2
- db OPP_RIVAL3
- db -1 ; end
+INCLUDE "engine/events/pewter_guys.asm"
diff --git a/engine/overworld/cut.asm b/engine/overworld/cut.asm
index 368941d5..dea23cc5 100644
--- a/engine/overworld/cut.asm
+++ b/engine/overworld/cut.asm
@@ -76,6 +76,7 @@ InitCutAnimOAM:
ld [wWhichAnimationOffsets], a
ld a, %11100100
ldh [rOBP1], a
+ call UpdateCGBPal_OBP1
ld a, [wCutTile]
cp $52
jr z, .grass
@@ -124,10 +125,10 @@ WriteCutOrBoulderDustAnimationOAMBlock:
.OAMBlock:
; tile ID, attributes
- db $fc, OAM_PAL1
- db $fd, OAM_PAL1
- db $fe, OAM_PAL1
- db $ff, OAM_PAL1
+ db $fc, OAM_PAL1 | OAM_HIGH_PALS
+ db $fd, OAM_PAL1 | OAM_HIGH_PALS
+ db $fe, OAM_PAL1 | OAM_HIGH_PALS
+ db $ff, OAM_PAL1 | OAM_HIGH_PALS
GetCutOrBoulderDustAnimationOffsets:
ld hl, wSpritePlayerStateData1YPixels
diff --git a/engine/overworld/cut2.asm b/engine/overworld/cut2.asm
index 7697d430..9d6124e4 100644
--- a/engine/overworld/cut2.asm
+++ b/engine/overworld/cut2.asm
@@ -18,6 +18,7 @@ AnimCut:
ldh a, [rOBP1]
xor $64
ldh [rOBP1], a
+ call UpdateCGBPal_OBP1
call DelayFrame
pop bc
dec c
@@ -68,6 +69,7 @@ AnimCutGrass_UpdateOAMEntries:
ldh a, [rOBP1]
xor $64
ldh [rOBP1], a
+ call UpdateCGBPal_OBP1
call DelayFrame
pop bc
dec c
diff --git a/engine/overworld/dungeon_warps.asm b/engine/overworld/dungeon_warps.asm
new file mode 100644
index 00000000..943c379d
--- /dev/null
+++ b/engine/overworld/dungeon_warps.asm
@@ -0,0 +1,15 @@
+IsPlayerOnDungeonWarp::
+ xor a
+ ld [wWhichDungeonWarp], a
+ ld a, [wStatusFlags3]
+ bit BIT_ON_DUNGEON_WARP, a
+ ret nz
+ call ArePlayerCoordsInArray
+ ret nc
+ ld a, [wCoordIndex]
+ ld [wWhichDungeonWarp], a
+ ld hl, wStatusFlags3
+ set BIT_ON_DUNGEON_WARP, [hl]
+ ld hl, wStatusFlags6
+ set BIT_DUNGEON_WARP, [hl]
+ ret
diff --git a/engine/overworld/dust_smoke.asm b/engine/overworld/dust_smoke.asm
index 85b89cdc..2e6576a8 100644
--- a/engine/overworld/dust_smoke.asm
+++ b/engine/overworld/dust_smoke.asm
@@ -7,6 +7,7 @@ AnimateBoulderDust:
ld [wUpdateSpritesEnabled], a
ld a, %11100100
ldh [rOBP1], a
+ call UpdateCGBPal_OBP1
call LoadSmokeTileFourTimes
farcall WriteCutOrBoulderDustAnimationOAMBlock
ld c, 8 ; number of steps in animation
@@ -21,6 +22,7 @@ AnimateBoulderDust:
ldh a, [rOBP1]
xor %01100100
ldh [rOBP1], a
+ call UpdateCGBPal_OBP1
call Delay3
pop bc
dec c
diff --git a/engine/overworld/elevator.asm b/engine/overworld/elevator.asm
index 0d19c127..3c425caa 100644
--- a/engine/overworld/elevator.asm
+++ b/engine/overworld/elevator.asm
@@ -4,8 +4,7 @@ ShakeElevator::
ld de, SCREEN_HEIGHT * $20
call ShakeElevatorRedrawRow
call Delay3
- ld a, SFX_STOP_ALL_MUSIC
- call PlaySound
+ call StopAllMusic
ldh a, [hSCY]
ld d, a
ld e, $1
@@ -27,8 +26,7 @@ ShakeElevator::
jr nz, .shakeLoop
ld a, d
ldh [hSCY], a
- ld a, SFX_STOP_ALL_MUSIC
- call PlaySound
+ call StopAllMusic
ld c, BANK(SFX_Safari_Zone_PA)
ld a, SFX_SAFARI_ZONE_PA
call PlayMusic
diff --git a/engine/overworld/emotion_bubbles.asm b/engine/overworld/emotion_bubbles.asm
index d44a12ce..da9502b0 100644
--- a/engine/overworld/emotion_bubbles.asm
+++ b/engine/overworld/emotion_bubbles.asm
@@ -1,13 +1,16 @@
EmotionBubble:
ld a, [wWhichEmotionBubble]
+ and $f
+ swap a
ld c, a
ld b, 0
- ld hl, EmotionBubblesPointerTable
+ ld hl, EmotionBubbles
+ add hl, bc ; each emotion bubble is 16 bytes, so calculate the offset directly instead of with a pointer table
add hl, bc
add hl, bc
- ld e, [hl]
- inc hl
- ld d, [hl]
+ add hl, bc
+ ld e, l
+ ld d, h
ld hl, vChars1 tile $78
lb bc, BANK(EmotionBubbles), 4
call CopyVideoData
@@ -59,13 +62,9 @@ EmotionBubble:
pop af
ld [wUpdateSpritesEnabled], a
call DelayFrame
- jp UpdateSprites
+ call UpdateSprites
+ ret
-EmotionBubblesPointerTable:
-; entries correspond to *_BUBBLE constants
- dw ShockEmote
- dw QuestionEmote
- dw HappyEmote
EmotionBubblesOAMBlock:
; tile ID, attributes
@@ -78,3 +77,8 @@ EmotionBubbles:
ShockEmote: INCBIN "gfx/emotes/shock.2bpp"
QuestionEmote: INCBIN "gfx/emotes/question.2bpp"
HappyEmote: INCBIN "gfx/emotes/happy.2bpp"
+SkullEmote: INCBIN "gfx/emotes/skull.2bpp"
+HeartEmote: INCBIN "gfx/emotes/heart.2bpp"
+BoltEmote: INCBIN "gfx/emotes/bolt.2bpp"
+ZzzEmote: INCBIN "gfx/emotes/zzz.2bpp"
+FishEmote: INCBIN "gfx/emotes/fish.2bpp"
diff --git a/engine/overworld/healing_machine.asm b/engine/overworld/healing_machine.asm
index 273b9bb0..5cf312ac 100644
--- a/engine/overworld/healing_machine.asm
+++ b/engine/overworld/healing_machine.asm
@@ -12,14 +12,13 @@ AnimateHealingMachine:
push af
ld a, $e0
ldh [rOBP1], a
+ call UpdateCGBPal_OBP1
ld hl, wShadowOAMSprite33
ld de, PokeCenterOAMData
call CopyHealingMachineOAM
ld a, 4
ld [wAudioFadeOutControl], a
- ld a, SFX_STOP_ALL_MUSIC
- ld [wNewSoundID], a
- call PlaySound
+ call StopAllMusic
.waitLoop
ld a, [wAudioFadeOutControl]
and a ; is fade-out finished?
@@ -38,9 +37,7 @@ AnimateHealingMachine:
cp BANK("Audio Engine 3")
ld [wAudioSavedROMBank], a
jr nz, .next
- ld a, SFX_STOP_ALL_MUSIC
- ld [wNewSoundID], a
- call PlaySound
+ call StopAllMusic
ld a, BANK(Music_PkmnHealed)
ld [wAudioROMBank], a
.next
@@ -57,6 +54,7 @@ AnimateHealingMachine:
call DelayFrames
pop af
ldh [rOBP1], a
+ call UpdateCGBPal_OBP1
pop hl
pop af
ld [hl], a
@@ -67,14 +65,14 @@ PokeCenterFlashingMonitorAndHealBall:
PokeCenterOAMData:
; heal machine monitor
- dbsprite 6, 4, 4, 4, $7c, OAM_PAL1
+ dbsprite 6, 4, 4, 4, $7c, OAM_PAL1 | OAM_HIGH_PALS
; poke balls 1-6
- dbsprite 6, 5, 0, 3, $7d, OAM_PAL1
- dbsprite 7, 5, 0, 3, $7d, OAM_PAL1 | OAM_XFLIP
- dbsprite 6, 6, 0, 0, $7d, OAM_PAL1
- dbsprite 7, 6, 0, 0, $7d, OAM_PAL1 | OAM_XFLIP
- dbsprite 6, 6, 0, 5, $7d, OAM_PAL1
- dbsprite 7, 6, 0, 5, $7d, OAM_PAL1 | OAM_XFLIP
+ dbsprite 6, 5, 0, 3, $7d, OAM_PAL1 | OAM_HIGH_PALS
+ dbsprite 7, 5, 0, 3, $7d, OAM_PAL1 | OAM_HIGH_PALS | OAM_XFLIP
+ dbsprite 6, 6, 0, 0, $7d, OAM_PAL1 | OAM_HIGH_PALS
+ dbsprite 7, 6, 0, 0, $7d, OAM_PAL1 | OAM_HIGH_PALS | OAM_XFLIP
+ dbsprite 6, 6, 0, 5, $7d, OAM_PAL1 | OAM_HIGH_PALS
+ dbsprite 7, 6, 0, 5, $7d, OAM_PAL1 | OAM_HIGH_PALS | OAM_XFLIP
; d = value to xor with palette
FlashSprite8Times:
@@ -83,6 +81,7 @@ FlashSprite8Times:
ldh a, [rOBP1]
xor d
ldh [rOBP1], a
+ call UpdateCGBPal_OBP1
ld c, 10
call DelayFrames
dec b
diff --git a/engine/overworld/hidden_events.asm b/engine/overworld/hidden_events.asm
index 8369e533..b7c803e5 100644
--- a/engine/overworld/hidden_events.asm
+++ b/engine/overworld/hidden_events.asm
@@ -1,19 +1,3 @@
-IsPlayerOnDungeonWarp::
- xor a
- ld [wWhichDungeonWarp], a
- ld a, [wStatusFlags3]
- bit BIT_ON_DUNGEON_WARP, a
- ret nz
- call ArePlayerCoordsInArray
- ret nc
- ld a, [wCoordIndex]
- ld [wWhichDungeonWarp], a
- ld hl, wStatusFlags3
- set BIT_ON_DUNGEON_WARP, [hl]
- ld hl, wStatusFlags6
- set BIT_DUNGEON_WARP, [hl]
- ret
-
; if a hidden event was found, stores $00 in [hDidntFindAnyHiddenEvent], else stores $ff
CheckForHiddenEvent::
ld hl, hItemAlreadyFound
@@ -22,22 +6,12 @@ CheckForHiddenEvent::
ld [hli], a ; [hSavedMapTextPtr]
ld [hli], a ; [hSavedMapTextPtr + 1]
ld [hl], a ; [hDidntFindAnyHiddenEvent]
- ld de, $0
ld hl, HiddenEventMaps
-.hiddenMapLoop
- ld a, [hli]
- ld b, a
- cp $ff
- jr z, .noMatch
+ ld de, 3
ld a, [wCurMap]
- cp b
- jr z, .foundMatchingMap
- inc de
- inc de
- jr .hiddenMapLoop
-.foundMatchingMap
- ld hl, HiddenEventPointers
- add hl, de
+ call IsInArray
+ jr nc, .noMatch
+ inc hl
ld a, [hli]
ld h, [hl]
ld l, a
diff --git a/engine/overworld/ledges.asm b/engine/overworld/ledges.asm
index 69403042..5cb2d5fc 100644
--- a/engine/overworld/ledges.asm
+++ b/engine/overworld/ledges.asm
@@ -61,19 +61,20 @@ LoadHoppingShadowOAM:
ld de, LedgeHoppingShadow
lb bc, BANK(LedgeHoppingShadow), (LedgeHoppingShadowEnd - LedgeHoppingShadow) / TILE_1BPP_SIZE
call CopyVideoDataDouble
- ld a, $9
- lb bc, $54, $48 ; b, c = y, x coordinates of shadow
- ld de, LedgeHoppingShadowOAMBlock
- call WriteOAMBlock
+ ld hl, LedgeHoppingShadowOAM
+ ld de, wShadowOAMSprite36
+ ld bc, LedgeHoppingShadowOAMEnd - LedgeHoppingShadowOAM
+ call CopyData
+ ld a, $a0
+ ld [wShadowOAMSprite38YCoord], a
+ ld [wShadowOAMSprite39YCoord], a
ret
LedgeHoppingShadow:
INCBIN "gfx/overworld/shadow.1bpp"
LedgeHoppingShadowEnd:
-LedgeHoppingShadowOAMBlock:
-; tile ID, attributes
- db $ff, OAM_PAL1
- db $ff, OAM_XFLIP
- db $ff, OAM_YFLIP
- db $ff, OAM_XFLIP | OAM_YFLIP
+LedgeHoppingShadowOAM:
+ dbsprite 9, 11, 0, 0, $ff, 0
+ dbsprite 10, 11, 0, 0, $ff, OAM_XFLIP
+LedgeHoppingShadowOAMEnd:
diff --git a/engine/overworld/map_sprites.asm b/engine/overworld/map_sprites.asm
index 57c2d4db..7e807c65 100644
--- a/engine/overworld/map_sprites.asm
+++ b/engine/overworld/map_sprites.asm
@@ -8,247 +8,13 @@
; wSpriteStateData2 sprite slot, respectively, within loops. The X is the loop index.
; If there is an inner loop, Y is the inner loop index, i.e. y#SPRITESTATEDATA1_* and
; y#SPRITESTATEDATA2_* denote fields of the sprite slots iterated over in the inner loop.
-InitMapSprites::
+_InitMapSprites::
call InitOutsideMapSprites
ret c ; return if the map is an outside map (already handled by above call)
; if the map is an inside map (i.e. mapID >= FIRST_INDOOR_MAP)
- ld hl, wSpritePlayerStateData1PictureID
- ld de, wSpritePlayerStateData2PictureID
-; Loop to copy picture IDs from [x#SPRITESTATEDATA1_PICTUREID]
-; to [x#SPRITESTATEDATA2_PICTUREID] for LoadMapSpriteTilePatterns.
-.copyPictureIDLoop
- ld a, [hl] ; a = [x#SPRITESTATEDATA1_PICTUREID]
- ld [de], a ; [x#SPRITESTATEDATA2_PICTUREID] = a
- ld a, SPRITESTATEDATA1_LENGTH
- add e
- ld e, a
- ld a, SPRITESTATEDATA1_LENGTH
- add l
- ld l, a
- jr nz, .copyPictureIDLoop
-
-; This is used for both inside and outside maps, since it is called by
-; InitOutsideMapSprites.
-; Loads tile pattern data for sprites into VRAM.
-LoadMapSpriteTilePatterns:
- ld a, [wNumSprites]
- and a ; are there any sprites?
- jr nz, .spritesExist
- ret
-.spritesExist
- ld c, a ; c = [wNumSprites]
- ld b, NUM_SPRITESTATEDATA_STRUCTS
- ld hl, wSpritePlayerStateData2PictureID
- xor a
- ldh [hFourTileSpriteCount], a
-; Loop to copy picture IDs from [x#SPRITESTATEDATA2_PICTUREID]
-; to [x#SPRITESTATEDATA2_IMAGEBASEOFFSET].
-.copyPictureIDLoop
- ld a, [hli] ; a = [x#SPRITESTATEDATA2_PICTUREID]
- ld [hld], a ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET] = a
- ld a, l
- add SPRITESTATEDATA1_LENGTH
- ld l, a
- dec b
- jr nz, .copyPictureIDLoop
- ld hl, wSprite01StateData2ImageBaseOffset
-.loadTilePatternLoop
- ld de, wSprite01StateData2PictureID
-; Check if the current picture ID has already had its tile patterns loaded.
-; This done by looping through the previous sprite slots and seeing if any of
-; their picture ID's match that of the current sprite slot.
-.checkIfAlreadyLoadedLoop
- ld a, e
- and $f0
- ld b, a ; b = offset of the wSpriteStateData2 sprite slot being checked against
- ld a, l
- and $f0 ; a = offset of current wSpriteStateData2 sprite slot
- cp b ; done checking all previous sprite slots?
- jr z, .notAlreadyLoaded
- ld a, [de] ; picture ID of the wSpriteStateData2 sprite slot being checked against
- cp [hl] ; do the picture ID's match?
- jp z, .alreadyLoaded
- ld a, e
- add SPRITESTATEDATA1_LENGTH
- ld e, a
- jr .checkIfAlreadyLoadedLoop
-.notAlreadyLoaded
- ld de, wSpritePlayerStateData2ImageBaseOffset
- ld b, 1
-; loop to find the highest tile pattern VRAM slot (among the first 10 slots) used by a previous sprite slot
-; this is done in order to find the first free VRAM slot available
-.findNextVRAMSlotLoop
- ld a, e
- add SPRITESTATEDATA1_LENGTH
- ld e, a
- ld a, l
- cp e ; reached current slot?
- jr z, .foundNextVRAMSlot
- ld a, [de] ; y#SPRITESTATEDATA2_IMAGEBASEOFFSET
- cp 11 ; is it one of the first 10 slots?
- jr nc, .findNextVRAMSlotLoop
- cp b ; compare the slot being checked to the current max
- jr c, .findNextVRAMSlotLoop ; if the slot being checked is less than the current max
-; if the slot being checked is greater than or equal to the current max
- ld b, a ; store new max VRAM slot
- jr .findNextVRAMSlotLoop
-.foundNextVRAMSlot
- inc b ; increment previous max value to get next VRAM tile pattern slot
- ld a, b ; a = next VRAM tile pattern slot
- push af
- ld a, [hl] ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET]
- ld b, a ; b = current sprite picture ID
- cp FIRST_STILL_SPRITE ; is it a 4-tile sprite?
- jr c, .notFourTileSprite
- pop af
- ldh a, [hFourTileSpriteCount]
- add 11
- jr .storeVRAMSlot
-.notFourTileSprite
- pop af
-.storeVRAMSlot
- ld [hl], a ; store VRAM slot at [x#SPRITESTATEDATA2_IMAGEBASEOFFSET]
- ldh [hVRAMSlot], a ; used to determine if it's 4-tile sprite later
- ld a, b ; a = current sprite picture ID
- dec a
- add a
- add a
- push bc
- push hl
- ld hl, SpriteSheetPointerTable
- jr nc, .noCarry
- inc h
-.noCarry
- add l
- ld l, a
- jr nc, .noCarry2
- inc h
-.noCarry2
- push hl
- call ReadSpriteSheetData
- push af
- push de
- push bc
- ld hl, vNPCSprites ; VRAM base address
- ld bc, 12 tiles ; number of bytes per VRAM slot
- ldh a, [hVRAMSlot]
- cp 11 ; is it a 4-tile sprite?
- jr nc, .fourTileSpriteVRAMAddr
- ld d, a
- dec d
-; hl = vSprites + [hVRAMSlot] * 12 tiles
-.calculateVRAMAddrLoop
- add hl, bc
- dec d
- jr nz, .calculateVRAMAddrLoop
- jr .loadStillTilePattern
-.fourTileSpriteVRAMAddr
- ld hl, vSprites tile $7c ; address for second 4-tile sprite
- ldh a, [hFourTileSpriteCount]
- and a
- jr nz, .loadStillTilePattern
-; if it's the first 4-tile sprite
- ld hl, vSprites tile $78 ; address for first 4-tile sprite
- inc a
- ldh [hFourTileSpriteCount], a
-.loadStillTilePattern
- pop bc
- pop de
- pop af
- push hl
- push hl
- ld h, d
- ld l, e
- pop de
- ld b, a
- ld a, [wFontLoaded]
- bit BIT_FONT_LOADED, a ; reloading upper half of tile patterns after displaying text?
- jr nz, .skipFirstLoad ; if so, skip loading data into the lower half
- ld a, b
- ld b, 0
- call FarCopyData2 ; load tile pattern data for sprite when standing still
-.skipFirstLoad
- pop de
- pop hl
- ldh a, [hVRAMSlot]
- cp 11 ; is it a 4-tile sprite?
- jr nc, .skipSecondLoad ; if so, there is no second block
- push de
- call ReadSpriteSheetData
- push af
- ld a, $c0
- add e
- ld e, a
- jr nc, .noCarry3
- inc d
-.noCarry3
- ld a, [wFontLoaded]
- bit BIT_FONT_LOADED, a ; reloading upper half of tile patterns after displaying text?
- jr nz, .loadWhileLCDOn
- pop af
- pop hl
- set 3, h ; add $800 ($80 tiles) to hl (1 << 3 == $8)
- push hl
- ld h, d
- ld l, e
- pop de
- call FarCopyData2 ; load tile pattern data for sprite when walking
- jr .skipSecondLoad
-; When reloading the upper half of tile patterns after displaying text, the LCD
-; will be on, so CopyVideoData (which writes to VRAM only during V-blank) must
-; be used instead of FarCopyData2.
-.loadWhileLCDOn
- pop af
- pop hl
- set 3, h ; add $800 ($80 tiles) to hl (1 << 3 == $8)
- ld b, a
- swap c
- call CopyVideoData ; load tile pattern data for sprite when walking
-.skipSecondLoad
- pop hl
- pop bc
- jr .nextSpriteSlot
-.alreadyLoaded ; if the current picture ID has already had its tile patterns loaded
- inc de
- ld a, [de] ; a = [y#SPRITESTATEDATA2_IMAGEBASEOFFSET]
- ld [hl], a ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET] = a
-.nextSpriteSlot
- ld a, l
- add SPRITESTATEDATA2_LENGTH
- ld l, a
- dec c
- jp nz, .loadTilePatternLoop
- ld hl, wSpritePlayerStateData2PictureID
- ld b, NUM_SPRITESTATEDATA_STRUCTS
-; the pictures IDs stored at [x#SPRITESTATEDATA2_PICTUREID] are no longer needed,
-; so zero them
-.zeroStoredPictureIDLoop
- xor a
- ld [hl], a ; [x#SPRITESTATEDATA2_PICTUREID]
- ld a, SPRITESTATEDATA2_LENGTH
- add l
- ld l, a
- dec b
- jr nz, .zeroStoredPictureIDLoop
- ret
-
-; reads data from SpriteSheetPointerTable
-; INPUT:
-; hl = address of sprite sheet entry
-; OUTPUT:
-; de = pointer to sprite sheet
-; bc = length in bytes
-; a = ROM bank
-ReadSpriteSheetData:
- ld a, [hli]
- ld e, a
- ld a, [hli]
- ld d, a
- ld a, [hli]
- ld c, a
- xor a
- ld b, a
- ld a, [hli]
+ call LoadSpriteSetFromMapHeader
+ call LoadMapSpriteTilePatterns
+ call LoadMapSpritesImageBaseOffset
ret
; Loads sprite set for outside maps (cities and routes) and sets VRAM slots.
@@ -257,15 +23,8 @@ InitOutsideMapSprites:
ld a, [wCurMap]
cp FIRST_INDOOR_MAP ; is the map a city or a route?
ret nc ; if not, return
- ld hl, MapSpriteSets
- add l
- ld l, a
- jr nc, .noCarry
- inc h
-.noCarry
- ld a, [hl] ; a = spriteSetID
- cp FIRST_SPLIT_SET - 1 ; does the map have 2 sprite sets?
- call nc, GetSplitMapSpriteSetID ; if so, choose the appropriate one
+ call GetSplitMapSpriteSetID
+; if so, choose the appropriate one
ld b, a ; b = spriteSetID
ld a, [wFontLoaded]
bit BIT_FONT_LOADED, a ; reloading upper half of tile patterns after displaying text?
@@ -277,120 +36,283 @@ InitOutsideMapSprites:
ld a, b
ld [wSpriteSetID], a
dec a
- ld b, a
- sla a
ld c, a
- sla a
- sla a
- add c
- add b ; a = (spriteSetID - 1) * SPRITE_SET_LENGTH
- ld de, SpriteSets
-; add a to de to get offset of sprite set
- add e
- ld e, a
- jr nc, .noCarry2
- inc d
-.noCarry2
- ld hl, wSpritePlayerStateData2PictureID
- ld a, SPRITE_RED
- ld [hl], a
- ld bc, wSpriteSet
-; Load the sprite set into RAM.
-; This loop also fills [x#SPRITESTATEDATA2_PICTUREID] where X is from $0 to $A
-; with picture IDs. This is done so that LoadMapSpriteTilePatterns will
-; load tile patterns for all sprite pictures in the sprite set.
-.loadSpriteSetLoop
- ld a, SPRITESTATEDATA2_LENGTH
- add l
- ld l, a
- ld a, [de] ; sprite picture ID from sprite set
- ld [hl], a ; [x#SPRITESTATEDATA2_PICTUREID]
- ld [bc], a
- inc de
- inc bc
- ld a, l
- cp 11 * SPRITESTATEDATA2_LENGTH + SPRITESTATEDATA2_PICTUREID ; reached 11th sprite slot?
- jr nz, .loadSpriteSetLoop
- ld b, 4 ; 4 remaining sprite slots
-.zeroRemainingSlotsLoop ; loop to zero the picture ID's of the remaining sprite slots
- ld a, SPRITESTATEDATA2_LENGTH
- add l
- ld l, a
- xor a
- ld [hl], a ; [x#SPRITESTATEDATA2_PICTUREID]
- dec b
- jr nz, .zeroRemainingSlotsLoop
- ld a, [wNumSprites]
- push af ; save number of sprites
- ld a, SPRITE_SET_LENGTH ; 11 sprites in sprite set
- ld [wNumSprites], a
+ ld b, 0
+ ld a, wSpriteSetID - wSpriteSet
+ ld hl, SpriteSets
+ call AddNTimes ; get sprite set offset
+ ld de, wSpriteSet
+ ld bc, wSpriteSetID - wSpriteSet
+ call CopyData ; copy it to wSpriteSet
call LoadMapSpriteTilePatterns
- pop af
- ld [wNumSprites], a ; restore number of sprites
- ld hl, wSprite01StateData2ImageBaseOffset
- ld b, NUM_SPRITESTATEDATA_STRUCTS - 1
-; The VRAM tile pattern slots that LoadMapSpriteTilePatterns set are in the
-; order of the map's sprite set, not the order of the actual sprites loaded
-; for the current map. So, they are not needed and are zeroed by this loop.
-.zeroVRAMSlotsLoop
- xor a
- ld [hl], a ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET]
- ld a, SPRITESTATEDATA2_LENGTH
- add l
- ld l, a
- dec b
- jr nz, .zeroVRAMSlotsLoop
.skipLoadingSpriteSet
- ld hl, wSprite01StateData1
+ call LoadMapSpritesImageBaseOffset
+ scf
+ ret
+
+LoadSpriteSetFromMapHeader:
; This loop stores the correct VRAM tile pattern slots according the sprite
; data from the map's header. Since the VRAM tile pattern slots are filled in
; the order of the sprite set, in order to find the VRAM tile pattern slot
; for a sprite slot, the picture ID for the sprite is looked up within the
-; sprite set. The index of the picture ID within the sprite set plus one
-; (since the Red sprite always has the first VRAM tile pattern slot) is the
-; VRAM tile pattern slot.
+; sprite set. The index of the picture ID within the sprite set plus two
+; (since the Red sprite always has the first VRAM tile pattern slot and the
+; Pikachu sprite reserves the second slot) is the VRAM tile pattern slot.
+ ld hl, wSpriteSet
+ ld bc, wSpriteSetID - wSpriteSet
+ xor a
+ call FillMemory
+ ld a, SPRITE_PIKACHU ; load Pikachu separately
+ ld [wSpriteSet], a
+ ld hl, wSprite01StateData1
+ ld a, 14
.storeVRAMSlotsLoop
- ld c, 0
+ push af
ld a, [hl] ; [x#SPRITESTATEDATA1_PICTUREID] (zero if sprite slot is not used)
and a ; is the sprite slot used?
- jr z, .skipGettingPictureIndex ; if the sprite slot is not used
- ld b, a ; b = picture ID
+ jr z, .continue ; if the sprite slot is not used
+ ld c, a
+ call CheckForFourTileSprite ; is this a four tile sprite?
+ jr nc, .isNotFourTileSprite
+; loop through the space reserved for four tile picture IDs
+ ld de, wSpriteSet + 9
+ ld b, 2
+ call CheckIfPictureIDAlreadyLoaded
+ jr .continue
+
+.isNotFourTileSprite
+; loop through the space reserved for regular picture IDs
ld de, wSpriteSet
-; Loop to find the index of the sprite's picture ID within the sprite set.
-.getPictureIndexLoop
- inc c
+ ld b, 9
+ call CheckIfPictureIDAlreadyLoaded
+.continue
+ ld de, wSprite02StateData1 - wSprite01StateData1
+ add hl, de
+ pop af
+ dec a
+ jr nz, .storeVRAMSlotsLoop
+ ret
+
+CheckIfPictureIDAlreadyLoaded:
+; Check if the current picture ID has already had its tile patterns loaded.
+; This done by looping through the previous sprite slots and seeing if any of
+; their picture ID's match that of the current sprite slot.
+.loop
ld a, [de]
+ and a ; is sprite set slot not taken up yet?
+ jr z, .spriteSlotNotTaken ; if so, load it as it signifies we've reached
+ ; the end of data for the last sprite set
+
+ cp c ; is the tile pattern already loaded?
+ ret z ; don't redundantly load
+ dec b ; have we reached the end of the sprite set?
+ jr z, .spriteNotAlreadyLoaded ; if so, we're done here
inc de
- cp b ; does the picture ID match?
- jr nz, .getPictureIndexLoop
- inc c
-.skipGettingPictureIndex
- push hl
- inc h ; HIGH(wSpriteStateData2)
- ld a, SPRITESTATEDATA2_IMAGEBASEOFFSET - SPRITESTATEDATA1_PICTUREID
- add l
- ld l, a
- ld a, c ; a = VRAM slot (zero if sprite slot is not used)
- ld [hl], a ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET]
- pop hl
- ld a, SPRITESTATEDATA1_LENGTH
- add l
+ jr .loop
+
+.spriteSlotNotTaken
+ ld a, c
+ ld [de], a
+ ret
+.spriteNotAlreadyLoaded
+ scf
+ ret
+
+CheckForFourTileSprite:
+; Checks for a sprite added in yellow
+; Returns no carry if the sprite is Pikachu, as its sprite is handled separately
+; Else, returns carry if the sprite uses 4 tiles
+ cp SPRITE_PIKACHU ; is this the Pikachu Sprite?
+ ret z ; return if yes
+
+ cp FIRST_STILL_SPRITE ; is this a four tile sprite?
+ jr nc, .notYellowSprite ; set carry if yes
+; regular sprite
+ and a
+ ret
+
+.notYellowSprite
+ scf
+ ret
+
+LoadMapSpriteTilePatterns:
+ ld a, 0
+.loop
+ ldh [hVRAMSlot], a
+ cp 9
+ jr nc, .fourTileSprite
+ call LoadStillTilePattern
+ call LoadWalkingTilePattern
+ jr .continue
+
+.fourTileSprite
+ call LoadStillTilePattern
+.continue
+ ldh a, [hVRAMSlot]
+ inc a
+ cp 11
+ jr nz, .loop
+ ret
+
+ReloadWalkingTilePatterns:
+ xor a
+.loop
+ ldh [hVRAMSlot], a
+ cp 9
+ jr nc, .fourTileSprite
+ call LoadWalkingTilePattern
+.fourTileSprite
+ ldh a, [hVRAMSlot]
+ inc a
+ cp 11
+ jr nz, .loop
+ ret
+
+LoadStillTilePattern:
+ ld a, [wFontLoaded]
+ bit BIT_FONT_LOADED, a ; reloading upper half of tile patterns after displaying text?
+ ret nz ; if so, skip loading data into the lower half
+ call ReadSpriteSheetData
+ ret nc
+ call GetSpriteVRAMAddress
+ call CopyVideoDataAlternate ; new yellow function
+ ret
+
+LoadWalkingTilePattern:
+ call ReadSpriteSheetData
+ ret nc
+ ld hl, $c0
+ add hl, de
+ ld d, h
+ ld e, l
+ call GetSpriteVRAMAddress
+ set 3, h ; add $800 ($80 tiles) to hl (1 << 3 == $8)
+ call CopyVideoDataAlternate
+ ret
+
+GetSpriteVRAMAddress:
+ push bc
+ ldh a, [hVRAMSlot]
+ ld c, a
+ ld b, 0
+ ld hl, SpriteVRAMAddresses
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
ld l, a
+ pop bc
+ ret
+
+SpriteVRAMAddresses:
+ dw vChars0 + (1 * 12) tiles
+ dw vChars0 + (2 * 12) tiles
+ dw vChars0 + (3 * 12) tiles
+ dw vChars0 + (4 * 12) tiles
+ dw vChars0 + (5 * 12) tiles
+ dw vChars0 + (6 * 12) tiles
+ dw vChars0 + (7 * 12) tiles
+ dw vChars0 + (8 * 12) tiles
+ dw vChars0 + (9 * 12) tiles
+ dw vChars0 + (10 * 12) tiles ; 4-tile sprites
+ dw vChars0 + (10 * 12 + 4) tiles ; 4-tile sprites
+
+ReadSpriteSheetData:
+ ldh a, [hVRAMSlot]
+ ld e, a
+ ld d, 0
+ ld hl, wSpriteSet
+ add hl, de
+ ld a, [hl]
and a
- jr nz, .storeVRAMSlotsLoop
+ ret z
+
+ dec a
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ ld de, SpriteSheetPointerTable
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ ld c, [hl]
+ swap c ; get the number of tiles, not the raw byte length
+ ; this is because of the use of CopyVideoDataAlternate
+ inc hl
+ ld b, [hl]
+ inc hl
scf
ret
+LoadMapSpritesImageBaseOffset:
+ ld a, $1
+ ld [wSpritePlayerStateData2ImageBaseOffset], a ; vram slot for player
+ ld a, $2
+ ld [wSpritePikachuStateData2ImageBaseOffset], a ; vram slot for Pikachu
+ ld a, $e
+ ld hl, wSprite01StateData1
+.loop
+ ldh [hVRAMSlot], a ; store current sprite set slot as a counter
+ ld a, [hl] ; [x#SPRITESTATEDATA1_PICTUREID]
+ and a ; is the sprite unused?
+ jr z, .spriteUnused
+ call GetSpriteImageBaseOffset
+ push hl
+ ld de, wSpritePlayerStateData2ImageBaseOffset - wSpriteStateData1
+ add hl, de ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET]
+ ld [hl], a ; write offset
+ pop hl
+.spriteUnused
+ ld de, wSprite02StateData1 - wSprite01StateData1
+ add hl, de
+ ldh a, [hVRAMSlot]
+ dec a
+ jr nz, .loop
+ ret
+
+GetSpriteImageBaseOffset:
+ push de
+ push bc
+ ld c, a ; c = picture ID
+ ld b, 11
+ ld de, wSpriteSet
+.findSpriteImageBaseOffsetLoop
+ ld a, [de] ; a = sprite set picture ID
+ cp c ; have we found a match?
+ jr z, .foundSpritePictureID ; if so, get the sprite image base offset and return
+ inc de
+ dec b ; have we looped through all entries in wSpriteSet?
+ jr nz, .findSpriteImageBaseOffsetLoop ; continue looping if not
+ ld a, $1 ; assume slot one if this ever happens
+ jr .done
+.foundSpritePictureID
+ ld a, 13
+ sub b ; get sprite image base offset
+.done
+ pop bc
+ pop de
+ ret
+
+GetSplitMapSpriteSetID:
+ ld e, a
+ ld d, 0
+ ld hl, MapSpriteSets
+ add hl, de
+ ld a, [hl] ; a = spriteSetID
+ cp FIRST_SPLIT_SET - 1 ; does the map have 2 sprite sets?
+ ret c
; Chooses the correct sprite set ID depending on the player's position within
; the map for maps with two sprite sets.
-GetSplitMapSpriteSetID:
cp SPLITSET_ROUTE_20
jr z, .route20
ld hl, SplitMapSpriteSets
and $0f
dec a
- sla a
- sla a
+ add a
+ add a
add l
ld l, a
jr nc, .noCarry
diff --git a/engine/overworld/movement.asm b/engine/overworld/movement.asm
index be8d6f62..165208eb 100644
--- a/engine/overworld/movement.asm
+++ b/engine/overworld/movement.asm
@@ -22,7 +22,13 @@ UpdatePlayerSprite:
ld [wSpritePlayerStateData1ImageIndex], a
ret
.lowerLeftTileIsMapTile
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
call DetectCollisionBetweenSprites
+ pop af
+ ld [wUpdateSpritesEnabled], a
ld h, HIGH(wSpriteStateData1)
ld a, [wWalkCounter]
and a
@@ -48,42 +54,24 @@ UpdatePlayerSprite:
jr z, .notMoving
ld a, SPRITE_FACING_RIGHT
jr .next
+.next
+ ld [wSpritePlayerStateData1FacingDirection], a ; facing direction
+ ld a, [wFontLoaded]
+ bit BIT_FONT_LOADED, a
+ jr z, .moving
.notMoving
; zero the animation counters
xor a
ld [wSpritePlayerStateData1IntraAnimFrameCounter], a
ld [wSpritePlayerStateData1AnimFrameCounter], a
- jr .calcImageIndex
-.next
- ld [wSpritePlayerStateData1FacingDirection], a
- ld a, [wFontLoaded]
- bit BIT_FONT_LOADED, a
- jr nz, .notMoving
+ call Func_4e32
+ jr .skipSpriteAnim
.moving
ld a, [wMovementFlags]
bit BIT_SPINNING, a
jr nz, .skipSpriteAnim
- ldh a, [hCurrentSpriteOffset]
- add $7
- ld l, a
- ld a, [hl]
- inc a
- ld [hl], a
- cp 4
- jr nz, .calcImageIndex
- xor a
- ld [hl], a
- inc hl
- ld a, [hl]
- inc a
- and $3
- ld [hl], a
-.calcImageIndex
- ld a, [wSpritePlayerStateData1AnimFrameCounter]
- ld b, a
- ld a, [wSpritePlayerStateData1FacingDirection]
- add b
- ld [wSpritePlayerStateData1ImageIndex], a
+ call Func_5274
+ call Func_4e32
.skipSpriteAnim
; If the player is standing on a grass tile, make the player's sprite have
; lower priority than the background so that it's partially obscured by the
@@ -100,15 +88,12 @@ UpdatePlayerSprite:
ld [wSpritePlayerStateData2GrassPriority], a
ret
-UnusedReadSpriteDataFunction:
- push bc
- push af
- ldh a, [hCurrentSpriteOffset]
- ld c, a
- pop af
- add c
- ld l, a
- pop bc
+Func_4e32:
+ ld a, [wSpritePlayerStateData1AnimFrameCounter]
+ ld b, a
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ add b
+ ld [wSpritePlayerStateData1ImageIndex], a
ret
UpdateNPCSprite:
@@ -146,6 +131,8 @@ UpdateNPCSprite:
jp z, UpdateSpriteMovementDelay ; [x#SPRITESTATEDATA1_MOVEMENTSTATUS] == 2
cp $3
jp z, UpdateSpriteInWalkingAnimation ; [x#SPRITESTATEDATA1_MOVEMENTSTATUS] == 3
+ cp $4
+ jp z, Func_5357
ld a, [wWalkCounter]
and a
ret nz ; don't do anything yet if player is currently moving
@@ -156,9 +143,9 @@ UpdateNPCSprite:
ld l, a
ld a, [hl] ; x#SPRITESTATEDATA2_MOVEMENTBYTE1
inc a
- jr z, .randomMovement ; value STAY
+ jp z, .randomMovement ; value STAY
inc a
- jr z, .randomMovement ; value WALK
+ jp z, .randomMovement ; value WALK
; scripted movement
dec a
ld [hl], a ; increment movement byte 1 (movement data index)
@@ -183,12 +170,18 @@ UpdateNPCSprite:
ret
.next
cp WALK
- jr nz, .determineDirection
+ jr nz, .asm_4ecb
; current NPC movement data is WALK ($fe). this seems buggy
ld [hl], $1 ; set movement byte 1 to $1
ld de, wNPCMovementDirections
call LoadDEPlusA ; a = [wNPCMovementDirections + $fe] (?)
- jr .determineDirection
+.asm_4ecb
+ push af
+ call Func_5288
+ pop bc
+ ld a, b
+ jr nc, .determineDirection
+ ret
.randomMovement
call GetTileSpriteStandsOn
call Random
@@ -263,34 +256,14 @@ ChangeFacingDirection:
; set carry on failure, clears carry on success
TryWalking:
push hl
- ld h, HIGH(wSpriteStateData1)
- ldh a, [hCurrentSpriteOffset]
- add $9
- ld l, a
- ld [hl], c ; x#SPRITESTATEDATA1_FACINGDIRECTION
- ldh a, [hCurrentSpriteOffset]
- add $3
- ld l, a
- ld [hl], d ; x#SPRITESTATEDATA1_YSTEPVECTOR
- inc l
- inc l
- ld [hl], e ; x#SPRITESTATEDATA1_XSTEPVECTOR
+ call Func_5337
pop hl
push de
- ld c, [hl] ; read tile to walk onto
+ ld c, [hl]
call CanWalkOntoTile
pop de
ret c ; cannot walk there (reinitialization of delay values already done)
- ld h, HIGH(wSpriteStateData2)
- ldh a, [hCurrentSpriteOffset]
- add $4
- ld l, a
- ld a, [hl] ; x#SPRITESTATEDATA2_MAPY
- add d
- ld [hli], a ; update Y position
- ld a, [hl] ; x#SPRITESTATEDATA2_MAPX
- add e
- ld [hl], a ; update X position
+ call Func_5349
ldh a, [hCurrentSpriteOffset]
ld l, a
ld [hl], $10 ; [x#SPRITESTATEDATA2_WALKANIMATIONCOUNTER] = 16
@@ -301,22 +274,7 @@ TryWalking:
; update the walking animation parameters for a sprite that is currently walking
UpdateSpriteInWalkingAnimation:
- ldh a, [hCurrentSpriteOffset]
- add $7
- ld l, a
- ld a, [hl] ; x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER
- inc a
- ld [hl], a ; [x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER]++
- cp $4
- jr nz, .noNextAnimationFrame
- xor a
- ld [hl], a ; [x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER] = 0
- inc l
- ld a, [hl] ; x#SPRITESTATEDATA1_ANIMFRAMECOUNTER
- inc a
- and $3
- ld [hl], a ; advance to next animation frame every 4 ticks (16 ticks total for one step)
-.noNextAnimationFrame
+ call Func_5274
ldh a, [hCurrentSpriteOffset]
add $3
ld l, a
@@ -449,6 +407,7 @@ InitializeSpriteStatus:
ld a, $8
ld [hli], a ; [x#SPRITESTATEDATA2_YDISPLACEMENT] = 8
ld [hl], a ; [x#SPRITESTATEDATA2_XDISPLACEMENT] = 8
+ call InitializeSpriteScreenPosition ; could have done fallthrough here
ret
; calculates the sprite's screen position from its map position and the player position
@@ -461,7 +420,7 @@ InitializeSpriteScreenPosition:
ld b, a
ld a, [hl] ; x#SPRITESTATEDATA2_MAPY
sub b ; relative to player position
- swap a ; * 16
+ call Func_5033
sub $4 ; - 4
dec h
ld [hli], a ; [x#SPRITESTATEDATA1_YPIXELS]
@@ -470,11 +429,23 @@ InitializeSpriteScreenPosition:
ld b, a
ld a, [hli] ; x#SPRITESTATEDATA2_MAPX
sub b ; relative to player position
- swap a ; * 16
+ call Func_5033
dec h
ld [hl], a ; [x#SPRITESTATEDATA1_XPIXELS]
ret
+Func_5033:
+ jr nc, .asm_503c
+ cpl
+ inc a
+ swap a
+ cpl
+ inc a
+ ret
+.asm_503c
+ swap a
+ ret
+
; tests if sprite is off screen or otherwise unable to do anything
CheckSpriteAvailability:
predef IsObjectHidden
@@ -594,16 +565,8 @@ CanWalkOntoTile:
and a
ret
.notScripted
- ld a, [wTilesetCollisionPtr]
- ld l, a
- ld a, [wTilesetCollisionPtr+1]
- ld h, a
-.tilePassableLoop
- ld a, [hli]
- cp $ff
- jr z, .impassable
- cp c
- jr nz, .tilePassableLoop
+ call _IsTilePassable
+ jr c, .impassable
ld h, HIGH(wSpriteStateData2)
ldh a, [hCurrentSpriteOffset]
add $6
@@ -627,7 +590,13 @@ CanWalkOntoTile:
jr nc, .impassable ; don't walk off screen
push de
push bc
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
call DetectCollisionBetweenSprites
+ pop af
+ ld [wUpdateSpritesEnabled], a
pop bc
pop de
ld h, HIGH(wSpriteStateData1)
@@ -650,8 +619,9 @@ CanWalkOntoTile:
; stuck whenever they walked upwards 5 steps
; on the other hand, the amount a sprite can walk out to the
; right of bottom is not limited (until the counter overflows)
+ ; this was fixed in Yellow
cp $5
- jr c, .impassable ; if [x#SPRITESTATEDATA2_YDISPLACEMENT]+d < 5, don't go
+ ;jr c, .impassable ; if [x#SPRITESTATEDATA2_YDISPLACEMENT]+d < 5, don't go
jr .checkHorizontal
.upwards
sub $1
@@ -705,7 +675,7 @@ GetTileSpriteStandsOn:
ld l, a
ld a, [hli] ; x#SPRITESTATEDATA1_YPIXELS
add $4 ; align to 2*2 tile blocks (Y position is always off 4 pixels to the top)
- and $f0 ; in case object is currently moving
+ and $f8 ; in case object is currently moving (XXX why changed to $f8?)
srl a ; screen Y tile * 4
ld c, a
ld b, $0
@@ -871,20 +841,235 @@ AnimScriptedNPCMovement:
ret
AdvanceScriptedNPCAnimFrameCounter:
+ call Func_5274
+ ld h, HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
- add $7
+ add $8
ld l, a
ld a, [hl] ; intra-animation frame counter
+ and $3
+ ldh [hSpriteAnimFrameCounter], a
+ ret
+
+Func_5274:
+ ldh a, [hCurrentSpriteOffset]
+ add $7
+ ld l, a
+ ld h, HIGH(wSpriteStateData1)
+ ld a, [hl] ; x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER
inc a
- ld [hl], a
- cp 4
+ and $3
+ ld [hl], a ; [x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER]++
ret nz
- xor a
- ld [hl], a ; reset intra-animation frame counter
inc l
- ld a, [hl] ; animation frame counter
+ ld a, [hl] ; x#SPRITESTATEDATA1_ANIMFRAMECOUNTER
inc a
and $3
+ ld [hl], a ; advance to next animation frame every 4 ticks (16 ticks total for one step)
+ ret
+
+Func_5288:
+; nice lookup table
+; a is supposedly [wNPCMovementDirections + $fe]
+ cp $5
+ jr z, .asm_52af
+ cp $4
+ jr z, .asm_52aa
+ cp $6
+ jr z, .asm_52b4
+ cp $7
+ jr z, .asm_52b9
+ cp $11
+ jr z, .asm_52c3
+ cp $12
+ jr z, .asm_52be
+ cp $13
+ jr z, .asm_52c8
+ cp $14
+ jr z, .asm_52cd
+ xor a
+ ret
+; set 1?
+.asm_52aa
+ call Func_531f
+ jr .asm_52e6
+.asm_52af
+ call Func_5325
+ jr .asm_52e6
+.asm_52b4
+ call Func_5331
+ jr .asm_52e6
+.asm_52b9
+ call Func_532b
+ jr .asm_52e6
+; set 2?
+.asm_52be
+ call Func_531f
+ jr .asm_52fa
+.asm_52c3
+ call Func_5325
+ jr .asm_52fa
+.asm_52c8
+ call Func_5331
+ jr .asm_52fa
+.asm_52cd
+ call Func_532b
+ jr .asm_52fa
+; set 3? (unused)
+.asm_52d2
+ call Func_531f
+ jr .asm_530b
+.asm_52d7
+ call Func_5325
+ jr .asm_530b
+.asm_52dc
+ call Func_5331
+ jr .asm_530b
+.asm_52e1
+ call Func_532b
+ jr .asm_530b
+
+.asm_52e6
+ call Func_5337
+ call Func_5349
+ ldh a, [hCurrentSpriteOffset]
+ ld l, a
+ ld [hl], $8
+ dec h
+ inc l
+ ld [hl], $4
+ call UpdateSpriteImage
+ scf
+ ret
+
+.asm_52fa
+ call Func_5337
+ ldh a, [hCurrentSpriteOffset]
+ ld l, a
+ ld [hl], $8
+ dec h
+ inc l
+ ld [hl], $3
+ call UpdateSpriteImage
+ scf
+ ret
+
+.asm_530b
+ call Func_5337
+ call Func_5349
+ ldh a, [hCurrentSpriteOffset]
+ ld l, a
+ ld [hl], $8
+ dec h
+ inc l
+ ld [hl], $3
+ call UpdateSpriteImage
+ scf
+ ret
+
+Func_531f:
+ lb de, 1, 0
+ ld c, SPRITE_FACING_DOWN
+ ret
+
+Func_5325:
+ lb de, -1, 0
+ ld c, SPRITE_FACING_UP
+ ret
+
+Func_532b:
+ lb de, 0, 1
+ ld c, SPRITE_FACING_RIGHT
+ ret
+
+Func_5331:
+ lb de, 0, -1
+ ld c, SPRITE_FACING_LEFT
+ ret
+
+Func_5337:
+ ldh a, [hCurrentSpriteOffset]
+ add $9
+ ld l, a
+ ld h, HIGH(wSpriteStateData1)
+ ld [hl], c ; x#SPRITESTATEDATA1_FACINGDIRECTION
+ ldh a, [hCurrentSpriteOffset]
+ add $3
+ ld l, a
+ ld [hl], d ; x#SPRITESTATEDATA1_YSTEPVECTOR
+ inc l
+ inc l
+ ld [hl], e ; x#SPRITESTATEDATA1_XSTEPVECTOR
+ ret
+
+Func_5349:
+ ld h, HIGH(wSpriteStateData2)
+ ldh a, [hCurrentSpriteOffset]
+ add $4
+ ld l, a
+ ld a, [hl] ; x#SPRITESTATEDATA2_MAPY
+ add d
+ ld [hli], a ; update Y position
+ ld a, [hl] ; x#SPRITESTATEDATA2_MAPX
+ add e
+ ld [hl], a ; update X position
+ ret
+
+Func_5357:
+ call Func_5274
+ ldh a, [hCurrentSpriteOffset]
+ add $3
+ ld l, a
+ ld h, HIGH(wSpriteStateData1)
+ ld a, [hli]
+ add a
+ ld b, a
+ ld a, [hl]
+ add b
+ ld [hli], a
+ ld a, [hli]
+ add a
+ ld b, a
+ ld a, [hl]
+ add b
+ ld [hl], a
+ ldh a, [hCurrentSpriteOffset]
+ ld l, a
+ ld h, HIGH(wSpriteStateData2)
+ dec [hl]
+ ret nz
+ ld a, $6
+ add l
+ ld l, a
+ ld a, [hl]
+ cp $fe
+ jr nc, .asm_5386
+ ldh a, [hCurrentSpriteOffset]
+ inc a
+ ld l, a
+ ld h, HIGH(wSpriteStateData1)
+ ld [hl], $1
+ ret
+.asm_5386
+ call Random
+ ldh a, [hCurrentSpriteOffset]
+ add $8
+ ld l, a
+ ld h, HIGH(wSpriteStateData2)
+ ldh a, [hRandomAdd]
+ and $7f
+ ld [hl], a
+ dec h
+ ldh a, [hCurrentSpriteOffset]
+ inc a
+ ld l, a
+ ld [hl], $2
+ inc l
+ inc l
+ xor a
+ ld b, [hl]
+ ld [hli], a
+ inc l
+ ld c, [hl]
ld [hl], a
- ldh [hSpriteAnimFrameCounter], a
ret
diff --git a/engine/overworld/npc_movement_2.asm b/engine/overworld/npc_movement_2.asm
new file mode 100644
index 00000000..bca9bf52
--- /dev/null
+++ b/engine/overworld/npc_movement_2.asm
@@ -0,0 +1,24 @@
+SetEnemyTrainerToStayAndFaceAnyDirection::
+ ld a, [wCurMap]
+ cp POKEMON_TOWER_7F
+ ret z ; the Rockets on Pokemon Tower 7F leave after battling, so don't set them
+ ld hl, RivalIDs
+ ld a, [wEngagedTrainerClass]
+ ld b, a
+.loop
+ ld a, [hli]
+ cp -1
+ jr z, .notRival
+ cp b
+ ret z ; the rival leaves after battling, so don't set him
+ jr .loop
+.notRival
+ ld a, [wSpriteIndex]
+ ldh [hSpriteIndex], a
+ jp SetSpriteMovementBytesToFF
+
+RivalIDs:
+ db OPP_RIVAL1
+ db OPP_RIVAL2
+ db OPP_RIVAL3
+ db -1 ; end
diff --git a/engine/overworld/player_animations.asm b/engine/overworld/player_animations.asm
index 657c001e..1948f68d 100644
--- a/engine/overworld/player_animations.asm
+++ b/engine/overworld/player_animations.asm
@@ -13,7 +13,6 @@ EnterMapAnim::
call PlaySound
ld hl, wStatusFlags6
bit BIT_DUNGEON_WARP, [hl]
- res BIT_DUNGEON_WARP, [hl]
pop hl
jr nz, .dungeonWarpAnimation
call PlayerSpinWhileMovingDown
@@ -34,21 +33,22 @@ EnterMapAnim::
ld [hl], $ff ; wPlayerSpinInPlaceAnimSoundID
ld hl, wFacingDirectionList
call PlayerSpinInPlace
+ ld a, $1
+ ld [wPikachuSpawnState], a
.restoreDefaultMusic
call PlayDefaultMusic
.done
+ call Func_151d
jp RestoreFacingDirectionAndYScreenPos
.dungeonWarpAnimation
ld c, 50
call DelayFrames
call PlayerSpinWhileMovingDown
+ ld a, $0
+ ld [wPikachuSpawnState], a
jr .done
.flyAnimation
pop hl
- ld de, BirdSprite
- ld hl, vNPCSprites
- lb bc, BANK(BirdSprite), $0c
- call CopyVideoData
call LoadBirdSpriteGraphics
ld a, SFX_FLY
call PlaySound
@@ -61,6 +61,8 @@ EnterMapAnim::
ld de, FlyAnimationEnterScreenCoords
call DoFlyAnimation
call LoadPlayerSpriteGraphics
+ ld a, $1
+ ld [wPikachuSpawnState], a
jr .restoreDefaultMusic
FlyAnimationEnterScreenCoords:
@@ -90,7 +92,9 @@ PlayerSpinWhileMovingDown:
ld [hl], a ; wPlayerSpinWhileMovingUpOrDownAnimFrameDelay
jp PlayerSpinWhileMovingUpOrDown
+
_LeaveMapAnim::
+ call Func_1510
call InitFacingDirectionList
call IsPlayerStandingOnWarpPadOrHole
ld a, b
@@ -249,12 +253,14 @@ DoFlyAnimation:
LoadBirdSpriteGraphics:
ld de, BirdSprite
+ ld b, BANK(BirdSprite)
+ ld c, $c
ld hl, vNPCSprites
- lb bc, BANK(BirdSprite), 12
call CopyVideoData
ld de, BirdSprite tile 12 ; moving animation sprite
+ ld b, BANK(BirdSprite)
+ ld c, 12
ld hl, vNPCSprites2
- lb bc, BANK(BirdSprite), 12
jp CopyVideoData
InitFacingDirectionList:
@@ -380,9 +386,10 @@ FishingAnim:
call DelayFrames
ld hl, wMovementFlags
set BIT_LEDGE_OR_FISHING, [hl]
+ ld hl, vNPCSprites
ld de, RedSprite
- ld hl, vNPCSprites tile $00
- lb bc, BANK(RedSprite), 12
+ ld b, BANK(RedSprite)
+ ld c, 12
call CopyVideoData
ld a, $4
ld hl, RedFishingTiles
diff --git a/engine/overworld/player_state.asm b/engine/overworld/player_state.asm
index 263ab634..3f642dc0 100644
--- a/engine/overworld/player_state.asm
+++ b/engine/overworld/player_state.asm
@@ -69,7 +69,8 @@ CheckForceBikeOrSurf::
ld a, $1
ld [wWalkBikeSurfState], a
ld [wWalkBikeSurfStateCopy], a
- jp ForceBikeOrSurf
+ call ForceBikeOrSurf
+ ret
.incorrectMap
inc hl
.incorrectY
@@ -79,7 +80,8 @@ CheckForceBikeOrSurf::
ld a, $2
ld [wWalkBikeSurfState], a
ld [wWalkBikeSurfStateCopy], a
- jp ForceBikeOrSurf
+ call ForceBikeOrSurf
+ ret
INCLUDE "data/maps/force_bike_surf.asm"
@@ -223,8 +225,7 @@ PrintSafariZoneSteps::
cp CERULEAN_CAVE_2F
ret nc
hlcoord 0, 0
- ld b, 3
- ld c, 7
+ lb bc, 3, 7
call TextBoxBorder
hlcoord 1, 1
ld de, wSafariSteps
@@ -351,16 +352,8 @@ GetTileTwoStepsInFrontOfPlayer:
CheckForCollisionWhenPushingBoulder:
call GetTileTwoStepsInFrontOfPlayer
- ld hl, wTilesetCollisionPtr
- ld a, [hli]
- ld h, [hl]
- ld l, a
-.loop
- ld a, [hli]
- cp $ff
- jr z, .done ; if the tile two steps ahead is not passable
- cp c
- jr nz, .loop
+ call IsTilePassable
+ jr c, .done
ld hl, TilePairCollisionsLand
call CheckForTilePairCollisions2
ld a, $ff
diff --git a/engine/overworld/specific_script_flags.asm b/engine/overworld/specific_script_flags.asm
new file mode 100644
index 00000000..bd045145
--- /dev/null
+++ b/engine/overworld/specific_script_flags.asm
@@ -0,0 +1,25 @@
+SetMapSpecificScriptFlagsOnMapReload::
+ ld a, [wCurMap]
+ cp VERMILION_GYM
+ jr z, .vermilion_gym
+ ld c, a
+ ld hl, Bit5Maps
+.search_loop
+ ld a, [hli]
+ cp c
+ jr z, .in_list
+ cp $ff
+ jr nz, .search_loop
+ ret
+
+.vermilion_gym
+ ld hl, wCurrentMapScriptFlags
+ set BIT_CUR_MAP_LOADED_2, [hl]
+ ret
+
+.in_list
+ ld hl, wCurrentMapScriptFlags
+ set BIT_CUR_MAP_LOADED_1, [hl]
+ ret
+
+INCLUDE "data/maps/bit_5_maps.asm"
diff --git a/engine/overworld/sprite_collisions.asm b/engine/overworld/sprite_collisions.asm
index e6d89480..2a514a0a 100644
--- a/engine/overworld/sprite_collisions.asm
+++ b/engine/overworld/sprite_collisions.asm
@@ -24,9 +24,12 @@ _UpdateSprites::
jr nz, .spriteLoop
ret
.updateCurrentSprite
- cp $1
- jp nz, UpdateNonPlayerSprite
- jp UpdatePlayerSprite
+ ldh a, [hCurrentSpriteOffset]
+ and a
+ jp z, UpdatePlayerSprite
+ cp $f0 ; pikachu
+ jp z, SpawnPikachu
+ ld a, [hl]
UpdateNonPlayerSprite:
dec a
@@ -52,11 +55,10 @@ UpdateNonPlayerSprite:
; The reason that 4 is added below to the coordinate is to make it align with a
; multiple of $10 to make comparisons easier.
DetectCollisionBetweenSprites:
- nop
+ ; nop
ld h, HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
- add LOW(wSpriteStateData1)
ld l, a
ld a, [hl] ; a = [i#SPRITESTATEDATA1_PICTUREID] (0 if slot is unused)
@@ -271,6 +273,17 @@ DetectCollisionBetweenSprites:
jr nc, .next ; go to next sprite if distance is still positive after both adjustments
.collision
+ ld a, l
+ and $f0 ; collision with pikachu?
+ jr nz, .asm_4cd9
+ xor a
+ ld [wd433], a
+ ldh a, [hCollidingSpriteOffset]
+ cp $f
+ jr nz, .asm_4cd9
+ call Func_4d0a
+ jr .asm_4cef
+.asm_4cd9
ldh a, [hCollidingSpriteTempXValue] ; a = 7 or 9 depending on sprite i's delta X
ld b, a
ldh a, [hCollidingSpriteTempYValue] ; a = 7 or 9 depending on sprite i's delta Y
@@ -296,6 +309,7 @@ DetectCollisionBetweenSprites:
; to indicate which sprite the collision occurred with
inc l
inc l
+.asm_4cef
ldh a, [hCollidingSpriteOffset]
ld de, SpriteCollisionBitTable
add a
@@ -324,6 +338,26 @@ DetectCollisionBetweenSprites:
; c = 0 if delta X/Y is 0
; c = 7 if delta X/Y is 1
; c = 9 if delta X/Y is -1
+Func_4d0a:
+ ldh a, [hCollidingSpriteTempXValue]
+ ld b, a
+ ldh a, [hCollidingSpriteTempYValue]
+ inc l
+ cp b
+ jr c, .asm_4d17
+ ld b, %1100
+ jr .asm_4d19
+.asm_4d17
+ ld b, %11
+.asm_4d19
+ ld a, c
+ and b
+ ld [wd433], a
+ ld a, c
+ inc l
+ inc l
+ ret
+
SetSpriteCollisionValues:
and a
ld b, 0
diff --git a/engine/overworld/tilesets.asm b/engine/overworld/tilesets.asm
index d36e1169..11c2bef6 100644
--- a/engine/overworld/tilesets.asm
+++ b/engine/overworld/tilesets.asm
@@ -5,23 +5,14 @@ LoadTilesetHeader:
ld a, [wCurMapTileset]
add a
add a
- ld b, a
- add a
- add b ; a = tileset * 12
- jr nc, .noCarry
- inc d
-.noCarry
ld e, a
ld hl, Tilesets
add hl, de
+ add hl, de
+ add hl, de
ld de, wTilesetBank
- ld c, $b
-.copyTilesetHeaderLoop
- ld a, [hli]
- ld [de], a
- inc de
- dec c
- jr nz, .copyTilesetHeaderLoop
+ ld bc, $b
+ call CopyData
ld a, [hl]
ldh [hTileAnimations], a
xor a
diff --git a/engine/overworld/toggleable_objects.asm b/engine/overworld/toggleable_objects.asm
index bfb3576c..a97f2bd2 100644
--- a/engine/overworld/toggleable_objects.asm
+++ b/engine/overworld/toggleable_objects.asm
@@ -17,15 +17,11 @@ MarkTownVisitedAndLoadToggleableObjects::
ld h, [hl]
ld l, a
push hl
- ld de, ToggleableObjectStates ; calculate difference between out pointer and the base pointer
ld a, l
- sub e
- jr nc, .noCarry
- dec h
-.noCarry
+ sub LOW(ToggleableObjectStates) ; calculate difference between out pointer and the base pointer
ld l, a
ld a, h
- sub d
+ sbc HIGH(ToggleableObjectStates)
ld h, a
; divide difference by 3, resulting in the global offset (number of toggleable items before ours)
ld a, h
diff --git a/engine/overworld/turn_sprite.asm b/engine/overworld/turn_sprite.asm
deleted file mode 100644
index 17fbaaa2..00000000
--- a/engine/overworld/turn_sprite.asm
+++ /dev/null
@@ -1,25 +0,0 @@
-UpdateSpriteFacingOffsetAndDelayMovement::
- ld h, HIGH(wSpriteStateData2)
- ldh a, [hCurrentSpriteOffset]
- add $8
- ld l, a
- ld a, $7f ; maximum movement delay
- ld [hl], a ; x#SPRITESTATEDATA2_MOVEMENTDELAY
- dec h ; HIGH(wSpriteStateData1)
- ldh a, [hCurrentSpriteOffset]
- add $9
- ld l, a
- ld a, [hld] ; x#SPRITESTATEDATA1_FACINGDIRECTION
- ld b, a
- xor a
- ld [hld], a ; x#SPRITESTATEDATA1_ANIMFRAMECOUNTER
- ld [hl], a ; x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER
- ldh a, [hCurrentSpriteOffset]
- add SPRITESTATEDATA1_IMAGEINDEX
- ld l, a
- ld a, [hl] ; x#SPRITESTATEDATA1_IMAGEINDEX
- or b ; or in the facing direction
- ld [hld], a
- ld a, $2 ; delayed movement status
- ld [hl], a ; x#SPRITESTATEDATA1_MOVEMENTSTATUS
- ret
diff --git a/engine/overworld/unused_load_toggleable_object_data.asm b/engine/overworld/unused_load_toggleable_object_data.asm
new file mode 100644
index 00000000..cf53f80a
--- /dev/null
+++ b/engine/overworld/unused_load_toggleable_object_data.asm
@@ -0,0 +1,46 @@
+Func_f0a54: ; unreferenced
+ ret
+
+LoadToggleableObjectData::
+; farcalled by an unreferenced function
+ ld hl, .ToggleableObjectsMaps
+.loop
+ ld a, [hli]
+ cp -1
+ ret z
+ ld b, a
+ ld a, [wCurMap]
+ cp b
+ jr z, .found
+ inc hl
+ inc hl
+ inc hl
+ jr .loop
+
+.found
+ ld a, [hli]
+ ld c, a
+ ld b, 0
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wToggleableObjectList
+ call CopyData
+ ret
+
+MACRO toggleable_object_map
+ db \1
+ db \3 - \2
+ dw \2
+ENDM
+
+.ToggleableObjectsMaps:
+ toggleable_object_map BLUES_HOUSE, .BluesHouse, .BluesHouseEnd
+ db -1 ; end
+
+.BluesHouse:
+ db 1, TOGGLE_DAISY_SITTING_COPY
+ db 2, TOGGLE_DAISY_WALKING_COPY
+ db 3, TOGGLE_TOWN_MAP_COPY
+ db -1 ; end
+.BluesHouseEnd:
diff --git a/engine/pikachu/pikachu_emotions.asm b/engine/pikachu/pikachu_emotions.asm
new file mode 100644
index 00000000..3fc08363
--- /dev/null
+++ b/engine/pikachu/pikachu_emotions.asm
@@ -0,0 +1,477 @@
+IsPlayerTalkingToPikachu::
+ ld a, [wd435]
+ and a
+ ret z
+ ldh a, [hSpriteIndex]
+ cp PIKACHU_SPRITE_INDEX
+ ret nz
+ call InitializePikachuTextID
+ xor a
+ ldh [hSpriteIndex], a
+ ld [wd435], a
+ ret
+
+InitializePikachuTextID::
+ ld a, TEXT_PIKACHU_ANIM ; display
+ ldh [hTextID], a
+ xor a
+ ld [wPlayerMovingDirection], a
+ ld a, $1
+ ld [wAutoTextBoxDrawingControl], a
+ call DisplayTextID
+ xor a
+ ld [wAutoTextBoxDrawingControl], a
+ ret
+
+DoStarterPikachuEmotions:
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+.loop
+ ld a, [de]
+ inc de
+ cp $ff
+ jr z, .done
+ ld c, a
+ ld b, 0
+ ld hl, StarterPikachuEmotionsJumptable
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call JumpToAddress
+ jr .loop
+
+.done
+ ret
+
+StarterPikachuEmotionsJumptable:
+ dw StarterPikachuEmotionCommand_nop ; 0
+ dw StarterPikachuEmotionCommand_text ; 1
+ dw StarterPikachuEmotionCommand_pcm ; 2
+ dw StarterPikachuEmotionCommand_emote ; 3
+ dw StarterPikachuEmotionCommand_movement ; 4
+ dw StarterPikachuEmotionCommand_pikapic ; 5
+ dw StarterPikachuEmotionCommand_subcmd ; 6
+ dw StarterPikachuEmotionCommand_delay ; 7
+ dw StarterPikachuEmotionCommand_nop2 ; 8
+ dw StarterPikachuEmotionCommand_9 ; 9
+ dw StarterPikachuEmotionCommand_nop3 ; a
+
+StarterPikachuEmotionCommand_nop:
+StarterPikachuEmotionCommand_nop3:
+ ret
+
+StarterPikachuEmotionCommand_text:
+ ld a, [de]
+ ld l, a
+ inc de
+ ld a, [de]
+ ld h, a
+ inc de
+ push de
+ call PrintText
+ pop de
+ ret
+
+StarterPikachuEmotionCommand_pcm:
+ ld a, [de]
+ inc de
+ push de
+ ld e, a
+ nop
+ call PlayPikachuSoundClip_
+ pop de
+ ret
+
+PlayPikachuSoundClip_:
+ cp $ff
+ ret z
+ callfar PlayPikachuSoundClip
+ ret
+
+StarterPikachuEmotionCommand_emote:
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ ld a, [de]
+ inc de
+ push de
+ call ShowPikachuEmoteBubble
+ pop de
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ ret
+
+ShowPikachuEmoteBubble:
+ ld [wWhichEmotionBubble], a
+ ld a, PIKACHU_SPRITE_INDEX
+ ld [wEmotionBubbleSpriteIndex], a
+ predef EmotionBubble
+ ret
+
+StarterPikachuEmotionCommand_movement:
+ ld a, [de]
+ inc de
+ ld l, a
+ ld a, [de]
+ inc de
+ ld h, a
+ push de
+ ld b, BANK(DoStarterPikachuEmotions)
+ call ApplyPikachuMovementData_
+ pop de
+ ret
+
+StarterPikachuEmotionCommand_delay:
+ ld a, [de]
+ inc de
+ push de
+ ld c, a
+ call DelayFrames
+ pop de
+ ret
+
+StarterPikachuEmotionCommand_subcmd:
+ ld a, [de]
+ inc de
+ push de
+ ld e, a
+ ld d, 0
+ ld hl, .Subcommands
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call JumpToAddress
+ pop de
+ ret
+
+.Subcommands:
+ dw LoadPikachuSpriteIntoVRAM
+ dw LoadFontTilePatterns
+ dw Pikachu_LoadCurrentMapViewUpdateSpritesAndDelay3
+ dw WaitForTextScrollButtonPress
+ dw PikachuPewterPokecenterCheck
+ dw PikachuFanClubCheck
+ dw PikachuBillsHouseCheck
+
+StarterPikachuEmotionCommand_nop2:
+IF DEF(_DEBUG)
+ push hl
+ ld hl, wStatusFlags6
+ bit BIT_DEBUG_MODE, [hl]
+ pop hl
+ ret z
+ push de
+ ld d, a
+ ld a, [wCurMap]
+ cp REDS_HOUSE_2F
+ ld a, d
+ pop de
+ ret nz
+ push de
+ call Pikachu_LoadCurrentMapViewUpdateSpritesAndDelay3
+ call LoadFontTilePatterns
+ ld hl, ExpressionText
+ call PrintText
+ call Pikachu_LoadCurrentMapViewUpdateSpritesAndDelay3
+ pop de
+ ret
+
+ExpressionText:
+ text_far _ExpressionText
+ text_end
+ELSE
+ ret
+ENDC
+
+StarterPikachuEmotionCommand_9:
+ push de
+ call StarterPikachuEmotionCommand_turnawayfromplayer
+ call UpdateSprites
+ pop de
+ ret
+
+StarterPikachuEmotionCommand_turnawayfromplayer:
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ xor $4
+ ld [wSpritePikachuStateData1FacingDirection], a
+ ret
+
+DeletedFunction_fcffb:
+; Inexplicably empty.
+REPT 5
+ nop
+ENDR
+IF DEF(_DEBUG)
+ push hl
+ ld hl, wStatusFlags6
+ bit BIT_DEBUG_MODE, [hl]
+ pop hl
+ ret z
+ push de
+ ld d, a
+ ld a, [wCurMap]
+ cp REDS_HOUSE_2F
+ ld a, d
+ pop de
+ ret nz
+ ld a, [wExpressionNumber]
+ inc a
+ cp (PikachuEmotion33_id - PikachuEmotionTable) / 2
+ jr c, .valid
+ ldpikaemotion a, PikachuEmotion1
+.valid
+ ld [wExpressionNumber], a
+ ret
+
+HallOfFamePCForever:
+ callfar HallOfFamePC
+ call WaitForTextScrollButtonPress
+ jr HallOfFamePCForever
+ELSE
+ ret
+ENDC
+
+PlaySpecificPikachuEmotion:
+ ld a, e
+ jr load_expression
+
+TalkToPikachu::
+ call MapSpecificPikachuExpression
+ jr c, load_expression
+ call GetPikaPicAnimationScriptIndex
+ call DeletedFunction_fcffb
+load_expression:
+ ld [wExpressionNumber], a
+ ld hl, PikachuEmotionTable
+ call DoStarterPikachuEmotions
+ ret
+
+MACRO pikaemotion_def
+\1_id::
+ dw \1
+ENDM
+
+PikachuEmotionTable::
+ pikaemotion_def PikachuEmotion0
+ pikaemotion_def PikachuEmotion1
+ pikaemotion_def PikachuEmotion2
+ pikaemotion_def PikachuEmotion3
+ pikaemotion_def PikachuEmotion4
+ pikaemotion_def PikachuEmotion5
+ pikaemotion_def PikachuEmotion6
+ pikaemotion_def PikachuEmotion7
+ pikaemotion_def PikachuEmotion8
+ pikaemotion_def PikachuEmotion9
+ pikaemotion_def PikachuEmotion10
+ pikaemotion_def PikachuEmotion11
+ pikaemotion_def PikachuEmotion12
+ pikaemotion_def PikachuEmotion13
+ pikaemotion_def PikachuEmotion14
+ pikaemotion_def PikachuEmotion15
+ pikaemotion_def PikachuEmotion16
+ pikaemotion_def PikachuEmotion17
+ pikaemotion_def PikachuEmotion18
+ pikaemotion_def PikachuEmotion19
+ pikaemotion_def PikachuEmotion20
+ pikaemotion_def PikachuEmotion21 ; used a fishing rod
+ pikaemotion_def PikachuEmotion22
+ pikaemotion_def PikachuEmotion23
+ pikaemotion_def PikachuEmotion24
+ pikaemotion_def PikachuEmotion25
+ pikaemotion_def PikachuEmotion26 ; wake up pikachu in pewter pokemon center
+ pikaemotion_def PikachuEmotion27
+ pikaemotion_def PikachuEmotion28
+ pikaemotion_def PikachuEmotion29
+ pikaemotion_def PikachuEmotion30
+ pikaemotion_def PikachuEmotion31
+ pikaemotion_def PikachuEmotion32
+ pikaemotion_def PikachuEmotion33
+
+PikachuEmotion33:
+ db $ff
+
+MapSpecificPikachuExpression:
+ ld a, [wCurMap]
+ cp POKEMON_FAN_CLUB
+ jr nz, .notFanClub
+ ld hl, wd492
+ bit 7, [hl]
+ ldpikaemotion a, PikachuEmotion29
+ jr z, .play_emotion
+ call CheckPikachuFollowingPlayer
+ ldpikaemotion a, PikachuEmotion30
+ jr nz, .play_emotion
+ jr .check_pikachu_status
+
+.notFanClub
+ ld a, [wCurMap]
+ cp PEWTER_POKECENTER
+ jr nz, .notPewterPokecenter
+ call CheckPikachuFollowingPlayer
+ ldpikaemotion a, PikachuEmotion26
+ jr nz, .play_emotion
+ jr .check_pikachu_status
+
+.notPewterPokecenter
+ callfar Func_f24ae
+ ld a, e
+ cp $ff
+ jr nz, .play_emotion
+ jr .check_pikachu_status ; useless
+
+.check_pikachu_status
+ call IsPlayerPikachuAsleepInParty
+ ldpikaemotion a, PikachuEmotion11
+ jr c, .play_emotion
+ callfar CheckPikachuStatusCondition ; same bank
+ ldpikaemotion a, PikachuEmotion28
+ jr c, .play_emotion
+ ld a, [wCurMap]
+ cp POKEMON_TOWER_1F
+ jr c, .notInLavenderTower
+ cp POKEMON_TOWER_7F + 1
+ ldpikaemotion a, PikachuEmotion22
+ jr c, .play_emotion
+.notInLavenderTower
+ ld a, [wd49b]
+ and a
+ jr z, .mood_based_emotion
+ dec a
+ ld c, a
+ ld b, $0
+ ld hl, .Emotions
+ add hl, bc
+ ld a, [hl]
+ jr .play_emotion
+
+.mood_based_emotion
+ and a
+ ret
+
+.play_emotion
+ scf
+ ret
+
+.Emotions:
+ dpikaemotion PikachuEmotion18
+ dpikaemotion PikachuEmotion21
+ dpikaemotion PikachuEmotion23
+ dpikaemotion PikachuEmotion24
+ dpikaemotion PikachuEmotion25
+
+IsPlayerPikachuAsleepInParty:
+ xor a
+ ld [wWhichPokemon], a
+.loop
+ ld a, [wWhichPokemon]
+ ld c, a
+ ld b, 0
+ ld hl, wPartySpecies
+ add hl, bc
+ ld a, [hl]
+ cp $ff
+ jr z, .done
+ cp STARTER_PIKACHU
+ jr nz, .curMonNotStarterPikachu
+ callfar IsThisPartyMonStarterPikachu
+ jr nc, .curMonNotStarterPikachu
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMon1Status
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+ ld a, [hl]
+ and SLP_MASK
+ jr z, .done
+ jr .curMonSleepingPikachu
+
+.curMonNotStarterPikachu
+ ld a, [wWhichPokemon]
+ cp PARTY_LENGTH - 1
+ jr z, .done
+ inc a
+ ld [wWhichPokemon], a
+ jr .loop
+
+.curMonSleepingPikachu
+ scf
+ ret
+
+.done
+ and a
+ ret
+
+INCLUDE "data/pikachu/pikachu_emotions.asm"
+
+PikachuWalksToNurseJoy:
+ ld a, $40
+ ldh [hPikachuSpriteVRAMOffset], a
+ call LoadPikachuSpriteIntoVRAM
+ call .GetMovementData
+ and a
+ jr z, .skip
+ call ApplyPikachuMovementData
+.skip
+ xor a
+ ldh [hPikachuSpriteVRAMOffset], a
+ ret
+
+.GetMovementData:
+ ld a, [wSpritePikachuStateData2MapY]
+ ld e, a
+ ld a, [wSpritePikachuStateData2MapX]
+ ld d, a
+ ld a, [wYCoord]
+ add 4
+ cp e
+ jr z, .pikachu_at_same_y_as_player
+ jr nc, .pikachu_above_player
+ ld hl, .PikaMovementData1
+ ld a, 1
+ ret
+
+.pikachu_above_player
+ xor a
+ ret
+
+.pikachu_at_same_y_as_player
+ ld a, [wXCoord]
+ add 4
+ cp d
+ jr c, .pikachu_to_right_of_player
+ ld hl, .PikaMovementData2
+ ld a, 2
+ ret
+
+.pikachu_to_right_of_player
+ ld hl, .PikaMovementData3
+ ld a, 3
+ ret
+
+.PikaMovementData1:
+ db $00 ; init
+ db $36 ; look up
+ db $2b ; walk up left
+ db $34 ; hop up right
+ db $3f ; ret
+
+.PikaMovementData2:
+ db $00 ; init
+ db $36 ; look up
+ db $34 ; hop up right
+ db $3f ; ret
+
+.PikaMovementData3:
+ db $00 ; init
+ db $36 ; look up
+ db $33 ; hop up left
+ db $3f ; ret
diff --git a/engine/pikachu/pikachu_follow.asm b/engine/pikachu/pikachu_follow.asm
new file mode 100644
index 00000000..11093c29
--- /dev/null
+++ b/engine/pikachu/pikachu_follow.asm
@@ -0,0 +1,1578 @@
+ShouldPikachuSpawn::
+; possibly to test if pika should be out?
+ ld a, [wPikachuOverworldStateFlags]
+ bit 5, a
+ jr nz, .hide
+ ld a, [wPikachuOverworldStateFlags]
+ bit 7, a
+ jr nz, .hide
+ call IsStarterPikachuAliveInOurParty
+ jr nc, .hide
+ ld a, [wWalkBikeSurfState]
+ and a
+ jr nz, .hide
+ scf
+ ret
+
+.hide
+ and a
+ ret
+
+SchedulePikachuSpawnForAfterText::
+ ld hl, wPikachuOverworldStateFlags
+ bit 4, [hl]
+ res 4, [hl]
+ jr nz, .normal_spawn_state
+ call EnablePikachuFollowingPlayer
+ call ClearPikachuSpriteStateData
+ ld a, $ff
+ ld [wSpritePikachuStateData1ImageIndex], a
+ call ClearPikachuFollowCommandBuffer
+ call CalculatePikachuFacingDirection
+ ret
+
+.normal_spawn_state
+ call CalculatePikachuPlacementCoords
+ xor a
+ ld [wPikachuSpawnState], a
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ ld [wSpritePikachuStateData1FacingDirection], a
+ ret
+
+ClearPikachuSpriteStateData::
+ ld hl, wSpritePikachuStateData1PictureID
+ call .clear
+ ld hl, wSpritePikachuStateData2
+.clear
+ ld bc, $10
+ xor a
+ call FillMemory
+ ret
+
+CalculatePikachuSpawnCoordsAndFacing::
+ call CalculatePikachuPlacementCoords
+ call CalculatePikachuFacingDirection
+ xor a
+ ld [wPikachuSpawnState], a
+ ret
+
+CalculatePikachuPlacementCoords::
+ ld bc, wSpritePikachuStateData1PictureID
+ ld a, [wYCoord]
+ add $4
+ ld e, a
+ ld a, [wXCoord]
+ add $4
+ ld d, a
+ ld a, [wPikachuSpawnState]
+ and a
+ jr z, .load_coords
+ cp $1
+ jr z, .right_of_player
+ cp $2
+ jr z, .check_player_facing2
+ cp $3
+ jr z, .load_coords
+ cp $4
+ jr z, .below_player
+ cp $5
+ jr z, .above_player
+ cp $6
+ jr z, .left_of_player
+ cp $7
+ jr z, .check_player_facing
+ jr .right_of_player
+
+.check_player_facing
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ and a ; SPRITE_FACING_DOWN
+ jr z, .below_player
+ cp SPRITE_FACING_UP
+ jr z, .above_player
+ cp SPRITE_FACING_LEFT
+ jr z, .left_of_player
+ cp SPRITE_FACING_RIGHT
+ jr z, .right_of_player
+.check_player_facing2
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ and a
+ jr nz, .check_up
+ dec e
+ jr .load_coords
+
+.check_up
+ cp SPRITE_FACING_UP
+ jr nz, .check_left
+ inc e
+ jr .load_coords
+
+.check_left
+ cp SPRITE_FACING_LEFT
+ jr nz, .left_of_player_2
+ inc d
+ jr .load_coords
+
+.left_of_player_2
+ dec d
+ jr .load_coords
+
+.right_of_player
+ inc d
+ jr .load_coords
+
+.left_of_player
+ dec d
+ jr .load_coords
+
+.below_player
+ inc e
+ jr .load_coords
+
+.above_player
+ dec e
+ jr .load_coords ; useless jr
+.load_coords
+ ld hl, wSpritePlayerStateData2MapY - wSpritePlayerStateData1
+ add hl, bc
+ ld [hl], e
+ inc hl
+ ld [hl], d
+ inc hl
+ ld [hl], $fe
+ push hl
+ ld hl, wd471
+ set 5, [hl]
+ pop hl
+ ret
+
+CalculatePikachuFacingDirection::
+ ld a, $49
+ ld [wSpritePikachuStateData1PictureID], a
+ ld a, $ff
+ ld [wSpritePikachuStateData1ImageIndex], a
+ ld a, [wPikachuSpawnState]
+ and a
+ jr z, .copy_player_facing
+ cp $1
+ jr z, .copy_player_facing
+ cp $3
+ jr z, .force_facing_down
+ cp $4
+ jr z, .copy_player_facing
+ cp $6
+ jr z, .copy_player_facing
+ cp $7
+ jr z, .face_the_other_way
+ call ComputePikachuFacingDirection
+ ret
+
+.copy_player_facing
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ ld [wSpritePikachuStateData1FacingDirection], a
+ ret
+
+.force_facing_down
+ ld a, SPRITE_FACING_DOWN
+ ld [wSpritePikachuStateData1FacingDirection], a
+ ret
+
+.face_the_other_way
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ xor $4
+ ld [wSpritePikachuStateData1FacingDirection], a
+ ret
+
+SetPikachuSpawnOutside::
+ ld a, [wCurMap]
+ cp OAKS_LAB
+ jr z, .oaks_lab
+ cp ROUTE_22_GATE
+ jr z, .route_22_gate
+ cp MT_MOON_B1F
+ jr z, .mt_moon_2
+ cp ROCK_TUNNEL_1F
+ jr z, .rock_tunnel_1
+ ld a, [wCurMap]
+ ld hl, Pointer_fc64b
+ call Pikachu_IsInArray ; similar to IsInArray, but not the same
+ jr c, .map_list_1
+ ld a, [wCurMap]
+ ld hl, Pointer_fc653
+ call Pikachu_IsInArray
+ jr nc, .not_map_list_2
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ and a
+ jr nz, .not_map_list_2
+ ld a, $3
+ jr .load
+
+.route_22_gate
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ and a
+ jr z, .rock_tunnel_1
+ jr .not_map_list_2
+
+.mt_moon_2
+ ld a, $3
+ jr .load
+
+.map_list_1
+ ld a, $4
+ jr .load
+
+.oaks_lab
+ ld a, $6
+ jr .load
+
+.not_map_list_2
+ ld a, $1
+ jr .load
+
+.rock_tunnel_1
+ ld a, $3
+.load
+ ld [wPikachuSpawnState], a
+ ret
+
+Pointer_fc64b::
+ db VICTORY_ROAD_2F
+ db ROUTE_7_GATE
+ db ROUTE_8_GATE
+ db ROUTE_16_GATE_1F
+ db ROUTE_18_GATE_1F
+ db ROUTE_15_GATE_1F
+ db ROUTE_11_GATE_1F
+ db $ff
+
+Pointer_fc653::
+ db VIRIDIAN_FOREST_NORTH_GATE
+ db CERULEAN_BADGE_HOUSE
+ db CERULEAN_TRASHED_HOUSE
+ db VERMILION_DOCK
+ db CELADON_MANSION_1F
+ db ROUTE_2_GATE
+ db FUCHSIA_GOOD_ROD_HOUSE
+ db $ff
+
+SetPikachuSpawnWarpPad::
+ ld a, [wCurMap]
+ cp VIRIDIAN_FOREST_NORTH_GATE
+ jr z, .viridian_forest_exit
+ cp VIRIDIAN_FOREST_SOUTH_GATE
+ jr z, .viridian_forest_entrance
+ ld a, [wCurMap]
+ ld hl, Pointer_fc68e
+ call Pikachu_IsInArray
+ jr c, .in_array
+ jr .not_in_array
+
+.viridian_forest_exit
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ cp SPRITE_FACING_UP
+ jr z, .in_array
+ jr .not_in_array
+
+.viridian_forest_entrance
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ and a ; SPRITE_FACING_DOWN
+ jr z, .not_in_array
+ jr .in_array
+
+.not_in_array
+ ld a, $0
+ jr .load_spawn_state
+
+.in_array
+ ld a, $1
+.load_spawn_state
+ ld [wPikachuSpawnState], a
+ ret
+
+Pointer_fc68e::
+ db VIRIDIAN_FOREST
+ db SAFARI_ZONE_CENTER_REST_HOUSE
+ db SAFARI_ZONE_WEST_REST_HOUSE
+ db SAFARI_ZONE_EAST_REST_HOUSE
+ db SAFARI_ZONE_NORTH_REST_HOUSE
+ db SAFARI_ZONE_SECRET_HOUSE
+ db SILPH_CO_ELEVATOR
+ db CELADON_MART_ELEVATOR
+ db CINNABAR_LAB_TRADE_ROOM
+ db CINNABAR_LAB_METRONOME_ROOM
+ db CINNABAR_LAB_FOSSIL_ROOM
+ db $ff
+
+SetPikachuSpawnBackOutside::
+ ld a, [wCurMap]
+ cp ROUTE_22_GATE
+ jr z, .asm_fc6a7
+ cp ROUTE_2_GATE
+ jr z, .asm_fc6b0
+ jr .asm_fc6bd
+
+.asm_fc6a7
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ cp SPRITE_FACING_UP
+ jr z, .asm_fc6b9
+ jr .asm_fc6bd
+
+.asm_fc6b0
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ cp SPRITE_FACING_UP
+ jr z, .asm_fc6b9
+ jr .asm_fc6bd
+
+.asm_fc6b9
+ ld a, $1
+ jr .asm_fc6c1
+
+.asm_fc6bd
+ ld a, $3
+ jr .asm_fc6c1
+
+.asm_fc6c1
+ ld [wPikachuSpawnState], a
+ ret
+
+SetPikachuOverworldStateFlag2::
+ push hl
+ ld hl, wPikachuOverworldStateFlags
+ set 2, [hl]
+ pop hl
+ ret
+
+ResetPikachuOverworldStateFlag2::
+ push hl
+ ld hl, wPikachuOverworldStateFlags
+ res 2, [hl]
+ pop hl
+ ret
+
+SpawnPikachu_::
+ call ResetPikachuOverworldStateFlag2
+ call TrySpawnPikachu
+ ret nc
+
+ push bc
+ call WillPikachuSpawnOnTheScreen
+ pop bc
+ ret c
+
+ ld bc, wSpritePikachuStateData1
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ bit 7, [hl]
+ jp nz, Func_fc745
+ ld a, [wFontLoaded]
+ bit BIT_FONT_LOADED, a
+ jp nz, Func_fc76a
+ call CheckPikachuFollowingPlayer
+ jp nz, Func_fc76a
+ ld a, [hl]
+ and $7f
+ cp $a
+ jr c, .valid
+ xor a
+.valid
+ add a
+ ld e, a
+ ld d, 0
+ ld hl, PointerTable_fc710
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+PointerTable_fc710:
+ dw Func_fc793
+ dw Func_fc7aa
+ dw Func_fc803
+ dw asm_fc9c3
+ dw asm_fca1c
+ dw asm_fc9ee
+ dw asm_fc87f
+ dw asm_fc904
+ dw asm_fc937
+ dw asm_fc969
+ dw .nop
+
+.nop:
+ ret
+
+TrySpawnPikachu:
+ call ShouldPikachuSpawn
+ jr nc, .dont_spawn
+ ld a, [wSpritePikachuStateData1MovementStatus]
+ and a
+ jr nz, .already_spawned
+ push bc
+ push hl
+ call CalculatePikachuSpawnCoordsAndFacing
+ pop hl
+ pop bc
+.already_spawned
+ scf
+ ret
+
+.dont_spawn
+ ld hl, wSpritePikachuStateData1ImageIndex
+ ld [hl], $ff
+ dec hl
+ ld [hl], $0
+ xor a
+ ret
+
+Func_fc745:
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ res 7, [hl]
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], a
+ call CheckPikachuFollowingPlayer
+ jr nz, .okay
+ ; Have Pikachu face in the opposite direction of you
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ xor $4
+ ld hl, wSpritePikachuStateData1FacingDirection - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], a
+.okay
+ xor a
+ ld hl, wSpritePikachuStateData1IntraAnimFrameCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hli], a
+ ld [hl], a
+ call UpdatePikachuWalkingSprite
+ ret
+
+Func_fc76a:
+ xor a
+ ld hl, wSpritePikachuStateData1IntraAnimFrameCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hli], a
+ ld [hl], a
+ call UpdatePikachuWalkingSprite
+ call Func_fc82e
+ jr c, .skip
+ push bc
+ callfar InitializeSpriteScreenPosition
+ pop bc
+.skip
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $1
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $0
+ call RefreshPikachuFollow
+ ret
+
+Func_fc793:
+ call RefreshPikachuFollow
+ push bc
+ callfar InitializeSpriteScreenPosition
+ pop bc
+ ld hl, wSpritePikachuStateData1ImageIndex - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $ff
+ dec hl
+ ld [hl], $1
+ ret
+
+Func_fc7aa:
+ call Func_fcc92
+ jp c, Func_fc803
+ dec a
+ ld l, a
+ ld h, $0
+ add hl, hl
+ add hl, hl
+ ld de, Pointer_fc7e3
+ add hl, de
+ ld d, h
+ ld e, l
+ ld a, [de]
+ inc de
+ ld hl, wSpritePikachuStateData1FacingDirection - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], a
+ ld a, [de]
+ inc de
+ ld hl, wSpritePikachuStateData1XStepVector - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], a
+ dec hl
+ dec hl
+ ld a, [de]
+ ld [hl], a
+ inc de
+ ld a, [de]
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], a
+ cp $4
+ jp z, Func_fca0a
+ call AreThereAtLeastTwoStepsInPikachuFollowCommandBuffer
+ jp c, FastPikachuFollow
+ jp NormalPikachuFollow
+
+Pointer_fc7e3:
+ db 0, 0
+ db 1, 3
+ db 4, 0
+ db -1, 3
+ db 8, -1
+ db 0, 3
+ db 12, 1
+ db 0, 3
+ db 0, 0
+ db 1, 4
+ db 4, 0
+ db -1, 4
+ db 8, -1
+ db 0, 4
+ db 12, 1
+ db 0, 4
+
+Func_fc803:
+ call Func_fcae2
+ ret c
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ dec [hl]
+ jr nz, .asm_fc823
+ push hl
+ call GetPikachuFollowCommand
+ pop hl
+ cp $5
+ jr nc, Func_fc842
+ ld [hl], $20
+ call Random
+ and $c
+ ld hl, wSpritePikachuStateData1FacingDirection - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], a
+.asm_fc823
+ xor a
+ ld hl, wSpritePikachuStateData1IntraAnimFrameCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hli], a
+ ld [hl], a
+ call UpdatePikachuWalkingSprite
+ ret
+
+Func_fc82e:
+ ld a, [wWalkCounter]
+ and a
+ ret z
+ scf
+ ret
+
+Func_fc835:
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $10
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $1
+ ret
+
+Func_fc842:
+ ld hl, $0
+ push af
+ call Random
+ ldh a, [hRandomAdd]
+ and %11
+ ld e, a
+ ld d, $0
+ ld hl, PointerTable_fc85a
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ pop af
+ jp hl
+
+PointerTable_fc85a:
+ dw Func_fc862
+ dw Func_fc8f8
+ dw Func_fc92b
+ dw Func_fc95d
+
+Func_fc862:
+ dec a
+ add a
+ add a
+ and $c
+ ld hl, wSpritePikachuStateData1FacingDirection - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], a
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $6
+ xor a
+ ld [wd431], a
+ ld [wd432], a
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $11
+asm_fc87f:
+ ld a, [wd431]
+ ld e, a
+ ld a, [wd432]
+ ld d, a
+ call Func_fc82e
+ jr c, Func_fc8c7
+ call SetPikachuOverworldStateFlag2
+ ld hl, wSpritePikachuStateData1YPixels - wSpritePikachuStateData1
+ add hl, bc
+ ld a, [hl]
+ sub e
+ ld e, a
+ inc hl
+ inc hl
+ ld a, [hl]
+ sub d
+ ld d, a
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld a, [hl]
+ dec a
+ add a
+ add LOW(Pointer_fc8d6)
+ ld l, a
+ ld a, HIGH(Pointer_fc8d6)
+ adc 0
+ ld h, a
+ ld a, [hli]
+ ld [wd431], a
+ add e
+ ld e, a
+ ld a, [hl]
+ ld [wd432], a
+ add d
+ ld d, a
+ ld hl, wSpritePikachuStateData1YPixels - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], e
+ inc hl
+ inc hl
+ ld [hl], d
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ dec [hl]
+ ret nz
+ jp Func_fc835
+
+Func_fc8c7:
+ ld hl, wSpritePikachuStateData1YPixels - wSpritePikachuStateData1
+ add hl, bc
+ ld a, [hl]
+ sub e
+ ld [hl], a
+ inc hl
+ inc hl
+ ld a, [hl]
+ sub d
+ ld [hl], a
+ jp Func_fc835
+
+Pointer_fc8d6:
+ db 0, 0
+ db -2, 1
+ db -4, 2
+ db -2, 3
+ db 0, 4
+ db -2, 3
+ db -4, 2
+ db -2, 1
+ db 0, 0
+ db -2, -1
+ db -4, -2
+ db -2, -3
+ db 0, -4
+ db -2, -3
+ db -4, -2
+ db -2, -1
+ db 0, 0
+
+Func_fc8f8:
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $7
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $30
+asm_fc904:
+ call Func_fc82e
+ jp c, Func_fc835
+ call SetPikachuOverworldStateFlag2
+ ld hl, wSpritePikachuStateData1IntraAnimFrameCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld a, [hl]
+ inc a
+ cp $8
+ ld [hl], a
+ jr nz, .asm_fc91f
+ xor a
+ ld [hli], a
+ ld a, [hl]
+ inc a
+ and %11
+ ld [hl], a
+.asm_fc91f
+ call UpdatePikachuWalkingSprite
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ dec [hl]
+ ret nz
+ jp Func_fc835
+
+Func_fc92b:
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $20
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $8
+asm_fc937:
+ call Func_fc82e
+ jp c, Func_fc835
+ call SetPikachuOverworldStateFlag2
+ ld hl, wSpritePikachuStateData1IntraAnimFrameCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld a, [hl]
+ inc a
+ cp $8
+ ld [hl], a
+ jr nz, .asm_fc951
+ xor a
+ ld [hli], a
+ ld a, [hl]
+ xor $1
+ ld [hl], a
+.asm_fc951
+ call UpdatePikachuWalkingSprite
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ dec [hl]
+ ret nz
+ jp Func_fc835
+
+Func_fc95d:
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $20
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $9
+asm_fc969:
+ call Func_fc82e
+ jp c, Func_fc835
+ call SetPikachuOverworldStateFlag2
+ ld hl, wSpritePikachuStateData1IntraAnimFrameCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld a, [hl]
+ inc a
+ cp $8
+ ld [hl], a
+ jr nz, .skip
+ xor a
+ ld [hl], a
+ ld hl, wSpritePikachuStateData1FacingDirection - wSpritePikachuStateData1
+ add hl, bc
+ ld a, [hl]
+ call .TurnClockwise
+ ld [hl], a
+.skip
+ call UpdatePikachuWalkingSprite
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ dec [hl]
+ ret nz
+ jp Func_fc835
+
+.TurnClockwise:
+ push hl
+ ld hl, .Facings
+ ld d, a
+.loop
+ ld a, [hli]
+ cp d
+ jr nz, .loop
+ ld a, [hl]
+ pop hl
+ ret
+
+.TurnCounterclockwise:
+ push hl
+ ld hl, .Facings_End
+ ld d, a
+.loop_
+ ld a, [hld]
+ cp d
+ jr nz, .loop_
+ ld a, [hl]
+ pop hl
+ ret
+
+.Facings:
+ db SPRITE_FACING_DOWN, SPRITE_FACING_LEFT, SPRITE_FACING_UP, SPRITE_FACING_RIGHT
+ db SPRITE_FACING_DOWN, SPRITE_FACING_LEFT, SPRITE_FACING_UP, SPRITE_FACING_RIGHT
+.Facings_End:
+
+NormalPikachuFollow:
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $8
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $3
+ call AddPikachuStepVector
+asm_fc9c3:
+ call TryDoubleAddPikachuStepVectorToScreenPixelCoords
+ call GetPikachuWalkingAnimationSpeed
+ call UpdatePikachuWalkingSprite
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ dec [hl]
+ ret nz
+ call ResetPikachuStepVector
+ call ComputePikachuFacingDirection
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $1
+ ret
+
+FastPikachuFollow:
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $4
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $5
+ call AddPikachuStepVector
+asm_fc9ee:
+ call DoubleAddPikachuStepVectorToScreenPixelCoords
+ call GetPikachuWalkingAnimationSpeed
+ call UpdatePikachuWalkingSprite
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ dec [hl]
+ ret nz
+ call ResetPikachuStepVector
+ call ComputePikachuFacingDirection
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $1
+ ret
+
+Func_fca0a:
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $8
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $4
+ call AddPikachuStepVector
+ call AddPikachuStepVector
+asm_fca1c:
+ call DoubleAddPikachuStepVectorToScreenPixelCoords
+ call GetPikachuWalkingAnimationSpeed
+ call UpdatePikachuWalkingSprite
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ dec [hl]
+ ret nz
+ call ResetPikachuStepVector
+ call ComputePikachuFacingDirection
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $1
+ ret
+
+AddPikachuStepVector:
+ ld hl, wSpritePikachuStateData1YStepVector - wSpritePikachuStateData1
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ inc hl
+ ld d, [hl]
+ ld hl, wSpritePikachuStateData2MapY - wSpritePikachuStateData1
+ add hl, bc
+ ld a, [hl]
+ add e
+ ld [hli], a
+ ld a, [hl]
+ add d
+ ld [hl], a
+ ret
+
+TryDoubleAddPikachuStepVectorToScreenPixelCoords:
+ ld a, [wWalkBikeSurfState]
+ cp $1 ; biking
+ jr nz, AddPikachuStepVectorToScreenPixelCoords
+ ld a, [wMovementFlags]
+ bit BIT_LEDGE_OR_FISHING, a
+ jr nz, AddPikachuStepVectorToScreenPixelCoords
+DoubleAddPikachuStepVectorToScreenPixelCoords:
+ ld hl, wSpritePikachuStateData1YStepVector - wSpritePikachuStateData1
+ add hl, bc
+ ld a, [hli]
+ add a
+ add a
+ add [hl]
+ ld [hli], a
+ ld a, [hli]
+ add a
+ add a
+ add [hl]
+ ld [hl], a
+ ret
+
+AddPikachuStepVectorToScreenPixelCoords:
+ ld hl, wSpritePikachuStateData1YStepVector - wSpritePikachuStateData1
+ add hl, bc
+ ld a, [hli]
+ add a
+ add [hl]
+ ld [hli], a
+ ld a, [hli]
+ add a
+ add [hl]
+ ld [hli], a
+ ret
+
+ResetPikachuStepVector:
+ ld hl, wSpritePikachuStateData1YStepVector - wSpritePikachuStateData1
+ add hl, bc
+ xor a
+ ld [hli], a
+ inc hl
+ ld [hl], a
+ ret
+
+GetPikachuWalkingAnimationSpeed:
+ call ComparePikachuHappinessTo80
+ ld d, $2
+ jr nc, .happy
+ ld d, $5
+.happy
+ ld hl, wSpritePikachuStateData1IntraAnimFrameCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld a, [hl]
+ inc a
+ cp d
+ jr nz, .dont_reset
+ xor a
+.dont_reset
+ ld [hli], a
+ ret nz
+ ld a, [hl]
+ inc a
+ and $3
+ ld [hl], a
+ ret
+
+UpdatePikachuWalkingSprite:
+ ld a, [wPikachuOverworldStateFlags]
+ bit 3, a
+ jr nz, .uninitialized
+ ld hl, wSpritePikachuStateData2ImageBaseOffset - wSpritePikachuStateData1
+ add hl, bc
+ ld a, [hl]
+ dec a
+ swap a
+ ld d, a
+ ld a, [wMovementFlags]
+ bit BIT_SPINNING, a
+ jr nz, .copy_player
+ ld hl, wSpritePikachuStateData1FacingDirection - wSpritePikachuStateData1
+ add hl, bc
+ ld a, [hl]
+ or d
+ ld d, a
+ ld a, [wFontLoaded]
+ bit BIT_FONT_LOADED, a
+ jr z, .normal_get_sprite_index
+ call Func_fcae2
+ ret c
+ jr .load_sprite_index
+
+.normal_get_sprite_index
+ ld hl, wSpritePikachuStateData1AnimFrameCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld a, d
+ or [hl]
+ ld d, a
+.load_sprite_index
+ ld hl, wSpritePikachuStateData1ImageIndex - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], d
+ ret
+
+.uninitialized
+ ld hl, wSpritePikachuStateData1ImageIndex - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $ff
+ ret
+
+.copy_player
+ ld a, [wSpritePlayerStateData1ImageIndex]
+ and $f
+ or d
+ ld [wSpritePikachuStateData1ImageIndex], a
+ ret
+
+Func_fcae2:
+ ld hl, wSpritePikachuStateData2MapY - wSpritePikachuStateData1
+ add hl, bc
+ ld a, [wYCoord]
+ add $4
+ cp [hl]
+ jr nz, .on_screen
+ inc hl
+ ld a, [wXCoord]
+ add $4
+ cp [hl]
+ jr nz, .on_screen
+ ld hl, wSpritePikachuStateData1ImageIndex - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $ff
+ scf
+ ret
+
+.on_screen
+ and a
+ ret
+
+IsPikachuRightNextToPlayer:
+ push bc
+ push de
+ push hl
+ ld bc, wSpritePikachuStateData1PictureID
+ ld a, [wXCoord]
+ add $4
+ ld d, a
+ ld a, [wYCoord]
+ add $4
+ ld e, a
+ ld hl, wSpritePlayerStateData2MapY - wSpritePlayerStateData1
+ add hl, bc
+ ld a, [hl]
+ sub e
+ and a
+ jr z, .equal
+ cp $ff
+ jr z, .one_away
+ cp $1
+ jr z, .one_away
+ jr .bad
+
+.one_away
+ ld hl, wSpritePlayerStateData2MapX - wSpritePlayerStateData1
+ add hl, bc
+ ld a, [hl]
+ sub d
+ jr z, .good
+ jr .bad
+
+.equal
+ ld hl, wSpritePlayerStateData2MapX - wSpritePlayerStateData1
+ add hl, bc
+ ld a, [hl]
+ sub d
+ cp $ff
+ jr z, .good
+ cp $1
+ jr z, .good
+ and a
+ jr z, .good
+ jr .bad
+
+.good
+ pop hl
+ pop de
+ pop bc
+ scf
+ ret
+
+.bad
+ pop hl
+ pop de
+ pop bc
+ xor a
+ ret
+
+GetPikachuFacingDirectionAndReturnToE::
+ call GetPikachuFacingDirection
+ ld e, a
+ ret
+
+GetPikachuFacingDirection:
+ ld bc, wSpritePikachuStateData1PictureID
+ ld a, [wXCoord]
+ add $4
+ ld d, a
+ ld a, [wYCoord]
+ add $4
+ ld e, a
+ ld hl, wSpritePlayerStateData2MapY - wSpritePlayerStateData1
+ add hl, bc
+ ld a, [hl]
+ cp e
+ jr z, .asm_fcb71
+ jr nc, .asm_fcb6e
+ ld a, SPRITE_FACING_UP
+ ret
+
+.asm_fcb6e
+ ld a, SPRITE_FACING_DOWN
+ ret
+
+.asm_fcb71
+ ld hl, wSpritePlayerStateData2MapX - wSpritePlayerStateData1
+ add hl, bc
+ ld a, [hl]
+ cp d
+ jr z, .asm_fcb81
+ jr nc, .asm_fcb7e
+ ld a, SPRITE_FACING_LEFT
+ ret
+
+.asm_fcb7e
+ ld a, SPRITE_FACING_RIGHT
+ ret
+
+.asm_fcb81
+ ld a, $ff ; standing
+ ret
+
+ClearPikachuFollowCommandBuffer:
+ push bc
+ ld hl, wPikachuFollowCommandBufferSize
+ ld [hl], $ff
+ inc hl
+ ld bc, $10
+ xor a
+ call FillMemory
+ pop bc
+ ret
+
+AppendPikachuFollowCommandToBuffer:
+ ld hl, wPikachuFollowCommandBufferSize
+ inc [hl]
+ ld e, [hl]
+ ld d, 0
+ ld hl, wPikachuFollowCommandBuffer
+ add hl, de
+ ld [hl], a
+ ret
+
+RefreshPikachuFollow:
+ call ClearPikachuFollowCommandBuffer
+ call ComputePikachuFollowCommand
+ ret c
+ call AppendPikachuFollowCommandToBuffer
+ ret
+
+ComputePikachuFollowCommand:
+ ld bc, wSpritePikachuStateData1PictureID
+ ld hl, wSpritePlayerStateData2MapY - wSpritePlayerStateData1
+ add hl, bc
+ ld a, [wYCoord]
+ add $4
+ sub [hl]
+ jr z, .checkXCoord
+ jr c, .pikaAbovePlayer
+ call CheckAbsoluteValueLessThan2
+ jr c, .return1
+ ld a, $5
+ and a
+ ret
+
+.return1
+ ld a, $1
+ and a
+ ret
+
+.pikaAbovePlayer
+ call CheckAbsoluteValueLessThan2
+ jr c, .return2
+ ld a, $6
+ and a
+ ret
+
+.return2
+ ld a, $2
+ and a
+ ret
+
+.checkXCoord
+ ld hl, wSpritePlayerStateData2MapX - wSpritePlayerStateData1
+ add hl, bc
+ ld a, [wXCoord]
+ add $4
+ sub [hl]
+ jr z, .pikachuOnTopOfPlayer
+ jr c, .pikaToLeftOfPlayer
+ call CheckAbsoluteValueLessThan2
+ jr c, .return4
+ ld a, $8
+ and a
+ ret
+
+.return4
+ ld a, $4
+ and a
+ ret
+
+.pikaToLeftOfPlayer
+ call CheckAbsoluteValueLessThan2
+ jr c, .return3
+ ld a, $7
+ and a
+ ret
+
+.return3
+ ld a, $3
+ and a
+ ret
+
+.pikachuOnTopOfPlayer
+ scf
+ ret
+
+CheckAbsoluteValueLessThan2:
+ jr nc, .positive
+ cpl
+ inc a
+.positive
+ cp $2
+ ret
+
+Func_fcc08::
+ call Func_fcc23
+ ret nc
+ ld a, [wMovementFlags]
+ bit BIT_LEDGE_OR_FISHING, a
+ jr nz, .asm_fcc1b
+ call Func_fcc42
+ ret c
+ call AppendPikachuFollowCommandToBuffer
+ ret
+
+.asm_fcc1b
+ call Func_fcc64
+ ret c
+ call AppendPikachuFollowCommandToBuffer
+ ret
+
+Func_fcc23:
+ ld a, [wPikachuOverworldStateFlags]
+ bit 5, a
+ jr nz, .asm_fcc40
+ ld a, [wPikachuOverworldStateFlags]
+ bit 7, a
+ jr nz, .asm_fcc40
+ ld a, [wd471]
+ bit 7, a
+ jr z, .asm_fcc40
+ ld a, [wWalkBikeSurfState]
+ and a
+ jr nz, .asm_fcc40
+ scf
+ ret
+
+.asm_fcc40
+ and a
+ ret
+
+Func_fcc42:
+ xor a
+ ld a, [wPlayerDirection]
+ bit PLAYER_DIR_BIT_UP, a
+ jr nz, .asm_fcc58
+ bit PLAYER_DIR_BIT_DOWN, a
+ jr nz, .asm_fcc5b
+ bit PLAYER_DIR_BIT_LEFT, a
+ jr nz, .asm_fcc5e
+ bit PLAYER_DIR_BIT_RIGHT, a
+ jr nz, .asm_fcc61
+ scf
+ ret
+
+.asm_fcc58
+ ld a, $2
+ ret
+
+.asm_fcc5b
+ ld a, $1
+ ret
+
+.asm_fcc5e
+ ld a, $3
+ ret
+
+.asm_fcc61
+ ld a, $4
+ ret
+
+Func_fcc64:
+ ld hl, wPikachuOverworldStateFlags
+ bit 6, [hl]
+ jr z, .asm_fcc6e
+ res 6, [hl]
+ ret
+
+.asm_fcc6e
+ set 6, [hl]
+ xor a
+ ld a, [wPlayerDirection]
+ bit PLAYER_DIR_BIT_UP, a
+ jr nz, .asm_fcc86
+ bit PLAYER_DIR_BIT_DOWN, a
+ jr nz, .asm_fcc89
+ bit PLAYER_DIR_BIT_LEFT, a
+ jr nz, .asm_fcc8c
+ bit PLAYER_DIR_BIT_RIGHT, a
+ jr nz, .asm_fcc8f
+ scf
+ ret
+
+.asm_fcc86
+ ld a, $6
+ ret
+
+.asm_fcc89
+ ld a, $5
+ ret
+
+.asm_fcc8c
+ ld a, $7
+ ret
+
+.asm_fcc8f
+ ld a, $8
+ ret
+
+Func_fcc92:
+ ld hl, wPikachuFollowCommandBufferSize
+ ld a, [hl]
+ cp $ff
+ jr z, .asm_fccb0
+ and a
+ jr z, .asm_fccb0
+ dec [hl]
+ ld e, a
+ ld d, 0
+ ld hl, wPikachuFollowCommandBuffer
+ add hl, de
+ inc e
+ ld a, $ff
+.asm_fcca8
+ ld d, [hl]
+ ld [hld], a
+ ld a, d
+ dec e
+ jr nz, .asm_fcca8
+ and a
+ ret
+
+.asm_fccb0
+ scf
+ ret
+
+ComputePikachuFacingDirection::
+ call GetPikachuFollowCommandIfBufferSizeNonzero
+ and a
+ jr z, .check_y
+ dec a
+ and $3
+ add a
+ add a
+ jr .load
+
+.check_y
+ ld a, [wYCoord]
+ add $4
+ ld d, a
+ ld a, [wXCoord]
+ add $4
+ ld e, a
+ ld a, [wSpritePikachuStateData2MapY]
+ cp d
+ jr z, .check_x
+ ld a, SPRITE_FACING_DOWN
+ jr c, .load
+ ld a, SPRITE_FACING_UP
+ jr .load
+
+.check_x
+ ld a, [wSpritePikachuStateData2MapX]
+ cp e
+ jr z, .copy_from_player
+ ld a, SPRITE_FACING_RIGHT
+ jr c, .load
+ ld a, SPRITE_FACING_LEFT
+ jr .load
+
+.copy_from_player
+ ld a, [wSpritePlayerStateData1FacingDirection]
+.load
+ ld [wSpritePikachuStateData1FacingDirection], a
+ ret
+
+GetPikachuFollowCommand:
+ ld hl, wPikachuFollowCommandBufferSize
+ ld a, [hl]
+ cp $ff
+ jr z, .asm_fccff
+ ld e, a
+ ld d, 0
+ ld hl, wPikachuFollowCommandBuffer
+ add hl, de
+ ld a, [hl]
+ ret
+
+.asm_fccff
+ xor a
+ ret
+
+GetPikachuFollowCommandIfBufferSizeNonzero:
+ ld hl, wPikachuFollowCommandBufferSize
+ ld a, [hl]
+ cp $ff
+ jr z, .default
+ and a
+ jr z, .default
+ ld e, a
+ ld d, 0
+ ld hl, wPikachuFollowCommandBuffer
+ add hl, de
+ ld a, [hl]
+ ret
+
+.default
+ xor a
+ ret
+
+AreThereAtLeastTwoStepsInPikachuFollowCommandBuffer:
+ ld a, [wPikachuFollowCommandBufferSize]
+ cp $ff
+ ret z
+ cp $2
+ jr nc, .set_carry
+ and a
+ ret
+
+.set_carry
+ scf
+ ret
+
+WillPikachuSpawnOnTheScreen:
+ ld h, HIGH(wSpriteStateData2)
+ ldh a, [hCurrentSpriteOffset] ; If we're here, this can only be $f0
+ add wSpritePikachuStateData2MapY - wSpritePikachuStateData2
+ ld l, a
+ ld b, [hl]
+ ld a, [wYCoord]
+ cp b
+ jr z, .same_y
+ jr nc, .not_on_screen
+ add (SCREEN_HEIGHT / 2) - 1
+ cp b
+ jr c, .not_on_screen
+.same_y
+ inc l
+ ld b, [hl]
+ ld a, [wXCoord]
+ cp b
+ jr z, .same_x
+ jr nc, .not_on_screen
+ add (SCREEN_WIDTH / 2) - 1
+ cp b
+ jr c, .not_on_screen
+.same_x
+ call .GetNPCCurrentTile
+ ld d, $60
+ ld a, [hli]
+ ld e, a
+ cp d
+ jr nc, .not_on_screen
+ ld a, [hld]
+ cp d
+ jr nc, .not_on_screen
+ ld bc, -20
+ add hl, bc
+ ld a, [hli]
+ cp d
+ jr nc, .not_on_screen
+ ld a, [hl]
+ cp d
+ jr c, .on_screen
+.not_on_screen
+ ld h, HIGH(wSpriteStateData1)
+ ldh a, [hCurrentSpriteOffset]
+ add wSpritePikachuStateData1ImageIndex - wSpritePikachuStateData1
+ ld l, a
+ ld [hl], $ff
+ scf
+ jr .return
+
+.on_screen
+ ld h, HIGH(wSpriteStateData2)
+ ldh a, [hCurrentSpriteOffset]
+ add wSpritePikachuStateData2GrassPriority - wSpritePikachuStateData2
+ ld l, a
+ ld a, [wGrassTile]
+ cp e
+ ld a, $0
+ jr nz, .priority
+ ld a, $80
+.priority
+ ld [hl], a
+ and a
+.return
+ ret
+
+.GetNPCCurrentTile:
+ ld h, HIGH(wSpriteStateData1)
+ ldh a, [hCurrentSpriteOffset]
+ add wSpritePikachuStateData1YPixels - wSpritePikachuStateData1
+ ld l, a
+ ld a, [hli]
+ add $4
+ and $f0
+ srl a
+ ld c, a
+ ld b, $0
+ inc l
+ ld a, [hl]
+ add $2
+ srl a
+ srl a
+ srl a
+ add SCREEN_WIDTH
+ ld d, 0
+ ld e, a
+ ld hl, wTileMap
+REPT 5
+ add hl, bc
+ENDR
+ add hl, de
+ ret
+
+ComparePikachuHappinessTo80:
+; preserves a and bc
+ push bc
+ push af
+ ld a, [wPikachuHappiness]
+ cp 80
+ pop bc
+ ld a, b
+ pop bc
+ ret
diff --git a/engine/pikachu/pikachu_movement.asm b/engine/pikachu/pikachu_movement.asm
new file mode 100644
index 00000000..3643a9bc
--- /dev/null
+++ b/engine/pikachu/pikachu_movement.asm
@@ -0,0 +1,1048 @@
+ApplyPikachuMovementData_::
+ ld a, b
+ ld [wPikachuMovementScriptBank], a
+ ld a, l
+ ld [wPikachuMovementScriptAddress], a
+ ld a, h
+ ld [wPikachuMovementScriptAddress + 1], a
+ call .SwapSpriteStateData
+.loop
+ call LoadPikachuMovementCommandData
+ jr nc, .done
+ call ExecutePikachuMovementCommand
+ jr .loop
+
+.done
+ call .SwapSpriteStateData
+ call DelayFrame
+ ret
+
+.SwapSpriteStateData:
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ push hl
+ push de
+ push bc
+
+ ld hl, wSpritePlayerStateData1
+ ld de, wSpritePikachuStateData1
+ ld c, $10
+ call .SwapBytes
+
+ ld hl, wSpritePlayerStateData2
+ ld de, wSpritePikachuStateData2
+ ld c, $10
+ call .SwapBytes
+
+ pop bc
+ pop de
+ pop hl
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ ret
+
+.SwapBytes:
+ ld b, [hl]
+ ld a, [de]
+ ld [hli], a
+ ld a, b
+ ld [de], a
+ inc de
+ dec c
+ jr nz, .SwapBytes
+ ret
+
+LoadPikachuMovementCommandData:
+ call GetPikachuMovementScriptByte
+ cp $3f
+ ret z
+ ld c, a
+ ld b, 0
+ ld hl, PikachuMovementDatabase
+ add hl, bc
+ add hl, bc
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld [wCurPikaMovementFunc1], a
+ ld a, [hli]
+ cp $80
+ jr nz, .no_param
+ call GetPikachuMovementScriptByte
+.no_param
+ ld [wCurPikaMovementParam1], a
+ ld a, [hli]
+ ld [wCurPikaMovementFunc2], a
+ ld a, [hli]
+ cp $80
+ jr nz, .no_param2
+ call GetPikachuMovementScriptByte
+.no_param2
+ ld [wCurPikaMovementParam2], a
+ xor a
+ ld [wd451], a
+ scf
+ ret
+
+ExecutePikachuMovementCommand:
+ xor a
+ ld [wPikachuMovementFlags], a
+ ld [wPikachuStepTimer], a
+ ld [wPikachuStepSubtimer], a
+ ld a, [wSpritePlayerStateData2GrassPriority]
+ push af
+.loop
+ ld bc, wSpritePlayerStateData1 ; Currently holds Pikachu's sprite state data
+ ld a, [wCurPikaMovementFunc1]
+ ld hl, PikaMovementFunc1Jumptable
+ call .JumpTable
+ ld a, [wCurPikaMovementFunc2]
+ ld hl, PikaMovementFunc2Jumptable
+ call .JumpTable
+ call GetCoordsForPikachuShadow
+ call AnimatePikachuShadow
+ call DelayFrame
+ call DelayFrame
+ ld hl, wPikachuMovementFlags
+ bit 7, [hl]
+ jr z, .loop
+ pop af
+ ld [wSpritePlayerStateData2GrassPriority], a
+ scf
+ ret
+
+.JumpTable:
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+GetCoordsForPikachuShadow:
+ ld hl, wSpritePlayerStateData1ImageIndex - wSpritePlayerStateData1
+ add hl, bc
+ ld a, [wCurPikaMovementSpriteImageIdx]
+ ld [hl], a
+ ld a, [wPikaSpriteY]
+ ld d, a
+ ld a, [wPikachuMovementYOffset]
+ add d
+ ld hl, wSpritePlayerStateData1YPixels - wSpritePlayerStateData1
+ add hl, bc
+ ld [hl], a
+ ld a, [wPikaSpriteX]
+ ld d, a
+ ld a, [wPikachuMovementXOffset]
+ add d
+ ld hl, wSpritePlayerStateData1XPixels - wSpritePlayerStateData1
+ add hl, bc
+ ld [hl], a
+ ld hl, wPikachuMovementFlags
+ bit 6, [hl]
+ ret z
+ ld hl, wSpritePlayerStateData2GrassPriority - wSpritePlayerStateData1
+ add hl, bc
+ ld [hl], 0
+ ret
+
+AnimatePikachuShadow:
+ ld hl, wPikachuMovementFlags
+ bit 6, [hl]
+ res 6, [hl]
+ ld hl, wMovementFlags
+ res BIT_LEDGE_OR_FISHING, [hl]
+ ret z
+ set BIT_LEDGE_OR_FISHING, [hl]
+ call LoadPikachuShadowOAMData
+ ret
+
+PikachuMovementDatabase:
+ db $01, 1 - 1, $00, 1 - 1 ; $00 start
+
+ db $03, $80, $01, 1 - 1 ; $01
+ db $04, $80, $01, 1 - 1 ; $02
+ db $05, $80, $01, 1 - 1 ; $03
+ db $06, $80, $01, 1 - 1 ; $04
+ db $07, $80, $01, 1 - 1 ; $05
+ db $08, $80, $01, 1 - 1 ; $06
+ db $09, $80, $01, 1 - 1 ; $07
+ db $0a, $80, $01, 1 - 1 ; $08
+
+ db $03, $80, $06, 1 - 1 ; $09
+ db $04, $80, $06, 1 - 1 ; $0a
+ db $05, $80, $06, 1 - 1 ; $0b
+ db $06, $80, $06, 1 - 1 ; $0c
+ db $07, $80, $06, 1 - 1 ; $0d
+ db $08, $80, $06, 1 - 1 ; $0e
+ db $09, $80, $06, 1 - 1 ; $0f
+ db $0a, $80, $06, 1 - 1 ; $10
+
+ db $03, $80, $03, $80 ; $11
+ db $04, $80, $03, $80 ; $12
+ db $05, $80, $03, $80 ; $13
+ db $06, $80, $03, $80 ; $14
+ db $07, $80, $03, $80 ; $15
+ db $08, $80, $03, $80 ; $16
+ db $09, $80, $03, $80 ; $17
+ db $0a, $80, $03, $80 ; $18
+
+ db $03, $80, $07, $80 ; $19
+ db $04, $80, $07, $80 ; $1a
+ db $05, $80, $07, $80 ; $1b
+ db $06, $80, $07, $80 ; $1c
+
+ db $0b, (1 << 5) | 8 - 1, $02, 1 - 1 ; $1d step down
+ db $0c, (1 << 5) | 8 - 1, $02, 1 - 1 ; $1e step up
+ db $0d, (1 << 5) | 8 - 1, $02, 1 - 1 ; $1f step left
+ db $0e, (1 << 5) | 8 - 1, $02, 1 - 1 ; $20 step right
+ db $0f, (1 << 5) | 8 - 1, $02, 1 - 1 ; $21 step down left
+ db $10, (1 << 5) | 8 - 1, $02, 1 - 1 ; $22 step down right
+ db $11, (1 << 5) | 8 - 1, $02, 1 - 1 ; $23 step up left
+ db $12, (1 << 5) | 8 - 1, $02, 1 - 1 ; $24 step up right
+
+ db $0b, 16 - 1, $02, 1 - 1 ; $25 slide down
+ db $0c, 16 - 1, $02, 1 - 1 ; $26 slide up
+ db $0d, 16 - 1, $02, 1 - 1 ; $27 slide left
+ db $0e, 16 - 1, $02, 1 - 1 ; $28 slide right
+ db $0f, 16 - 1, $02, 1 - 1 ; $29 slide down left
+ db $10, 16 - 1, $02, 1 - 1 ; $2a slide down right
+ db $11, 16 - 1, $02, 1 - 1 ; $2b slide up left
+ db $12, 16 - 1, $02, 1 - 1 ; $2c slide up right
+
+ db $0b, 16 - 1, $08, (1 << 4) | 8 - 1 ; $2d hop down
+ db $0c, 16 - 1, $08, (1 << 4) | 8 - 1 ; $2e hop up
+ db $0d, 16 - 1, $08, (1 << 4) | 8 - 1 ; $2f hop left
+ db $0e, 16 - 1, $08, (1 << 4) | 8 - 1 ; $30 hop right
+ db $0f, 16 - 1, $08, (1 << 4) | 8 - 1 ; $31 hop down left
+ db $10, 16 - 1, $08, (1 << 4) | 8 - 1 ; $32 hop down right
+ db $11, 16 - 1, $08, (1 << 4) | 8 - 1 ; $33 hop up left
+ db $12, 16 - 1, $08, (1 << 4) | 8 - 1 ; $34 hop up right
+
+ db $13, 16 - 1, $06, 1 - 1 ; $35 look down
+ db $14, 16 - 1, $06, 1 - 1 ; $36 look up
+ db $15, 16 - 1, $06, 1 - 1 ; $37 look left
+ db $16, 16 - 1, $06, 1 - 1 ; $38 look right
+
+ db $02, $80, $04, 1 - 1 ; $39
+ db $02, $80, $05, 1 - 1 ; $3a
+ db $02, $80, $03, $80 ; $3b
+ db $02, $80, $07, $80 ; $3c
+ db $02, $80, $09, $80 ; $3d
+ db $02, $80, $06, 1 - 1 ; $3e
+
+PikaMovementFunc1Jumptable:
+ dw PikaMovementFunc1_EndCommand_ ; 00
+ dw PikaMovementFunc1_LoadPikachuCurrentPosition ; 01
+ dw PikaMovementFunc1_DelayFrames ; 02
+ dw PikaMovementFunc1_WalkInCurrentFacingDirection ; 03
+ dw PikaMovementFunc1_WalkInOppositeFacingDirection ; 04
+ dw PikaMovementFunc1_StepTurningCounterclockwise ; 05
+ dw PikaMovementFunc1_StepTurningClockwise ; 06
+ dw PikaMovementFunc1_StepForwardLeft ; 07
+ dw PikaMovementFunc1_StepForwardRight ; 08
+ dw PikaMovementFunc1_StepBackwardLeft ; 09
+ dw PikaMovementFunc1_StepBackwardRight ; 0a
+ dw PikaMovementFunc1_MoveDown ; 0b
+ dw PikaMovementFunc1_MoveUp ; 0c
+ dw PikaMovementFunc1_MoveLeft ; 0d
+ dw PikaMovementFunc1_MoveRight ; 0e
+ dw PikaMovementFunc1_MoveDownLeft ; 0f
+ dw PikaMovementFunc1_MoveDownRight ; 10
+ dw PikaMovementFunc1_MoveUpLeft ; 11
+ dw PikaMovementFunc1_MoveUpRight ; 12
+ dw PikaMovementFunc1_LookDown ; 13
+ dw PikaMovementFunc1_LookUp ; 14
+ dw PikaMovementFunc1_LookLeft ; 15
+ dw PikaMovementFunc1_LookRight ; 16
+ dw PikaMovementFunc1_EndCommand_ ; 17
+
+PikaMovementFunc1_EndCommand:
+ ld a, [wPikachuMovementFlags]
+ set 7, a
+ ld [wPikachuMovementFlags], a
+ ret
+
+PikaMovementFunc1_EndCommand_:
+ call PikaMovementFunc1_EndCommand
+ ret
+
+PikaMovementFunc1_LoadPikachuCurrentPosition:
+ ld hl, wSpritePlayerStateData1YPixels - wSpritePlayerStateData1
+ add hl, bc
+ ld a, [hl]
+ ld [wPikaSpriteY], a
+ ld hl, wSpritePlayerStateData1XPixels - wSpritePlayerStateData1
+ add hl, bc
+ ld a, [hl]
+ ld [wPikaSpriteX], a
+ xor a
+ ld [wPikachuMovementYOffset], a
+ ld [wPikachuMovementXOffset], a
+ call PikaMovementFunc1_EndCommand
+ ret
+
+PikaMovementFunc1_DelayFrames:
+ call CheckPikachuStepTimer1
+ ret nz
+ call PikaMovementFunc1_EndCommand
+ ret
+
+PikaMovementFunc1_WalkInCurrentFacingDirection:
+ call GetPikachuFacing
+ jr PikaMovementFunc1_ApplyStepVector
+
+PikaMovementFunc1_WalkInOppositeFacingDirection:
+ call GetPikachuFacing
+ xor %100
+ jr PikaMovementFunc1_ApplyStepVector
+
+PikaMovementFunc1_StepTurningCounterclockwise:
+ call GetPikachuFacing
+ ld hl, .Data
+ call PikaMovementFunc1_GetNextFacing
+ jr PikaMovementFunc1_ApplyStepVector
+
+.Data:
+ db SPRITE_FACING_DOWN, PIKASTEPDIR_RIGHT << 2
+ db SPRITE_FACING_UP, PIKASTEPDIR_LEFT << 2
+ db SPRITE_FACING_LEFT, PIKASTEPDIR_DOWN << 2
+ db SPRITE_FACING_RIGHT, PIKASTEPDIR_UP << 2
+ db $ff
+
+PikaMovementFunc1_StepTurningClockwise:
+ call GetPikachuFacing
+ ld hl, .Data
+ call PikaMovementFunc1_GetNextFacing
+ jr PikaMovementFunc1_ApplyStepVector
+
+.Data:
+ db SPRITE_FACING_DOWN, PIKASTEPDIR_LEFT << 2
+ db SPRITE_FACING_UP, PIKASTEPDIR_RIGHT << 2
+ db SPRITE_FACING_LEFT, PIKASTEPDIR_UP << 2
+ db SPRITE_FACING_RIGHT, PIKASTEPDIR_DOWN << 2
+ db $ff
+
+PikaMovementFunc1_StepForwardLeft:
+ call GetPikachuFacing
+ ld hl, .Data
+ call PikaMovementFunc1_GetNextFacing
+ jr PikaMovementFunc1_ApplyStepVector
+
+.Data:
+ db SPRITE_FACING_DOWN, PIKASTEPDIR_DOWN_RIGHT << 2
+ db SPRITE_FACING_UP, PIKASTEPDIR_UP_LEFT << 2
+ db SPRITE_FACING_LEFT, PIKASTEPDIR_DOWN_LEFT << 2
+ db SPRITE_FACING_RIGHT, PIKASTEPDIR_UP_RIGHT << 2
+
+PikaMovementFunc1_StepForwardRight:
+ call GetPikachuFacing
+ ld hl, .Data
+ call PikaMovementFunc1_GetNextFacing
+ jr PikaMovementFunc1_ApplyStepVector
+
+.Data:
+ db SPRITE_FACING_DOWN, PIKASTEPDIR_DOWN_LEFT << 2
+ db SPRITE_FACING_UP, PIKASTEPDIR_UP_RIGHT << 2
+ db SPRITE_FACING_LEFT, PIKASTEPDIR_UP_LEFT << 2
+ db SPRITE_FACING_RIGHT, PIKASTEPDIR_DOWN_RIGHT << 2
+
+PikaMovementFunc1_StepBackwardLeft:
+ call GetPikachuFacing
+ ld hl, .Data
+ call PikaMovementFunc1_GetNextFacing
+ jr PikaMovementFunc1_ApplyStepVector
+
+.Data:
+ db SPRITE_FACING_DOWN, PIKASTEPDIR_UP_RIGHT << 2
+ db SPRITE_FACING_UP, PIKASTEPDIR_DOWN_LEFT << 2
+ db SPRITE_FACING_LEFT, PIKASTEPDIR_DOWN_RIGHT << 2
+ db SPRITE_FACING_RIGHT, PIKASTEPDIR_UP_LEFT << 2
+
+PikaMovementFunc1_StepBackwardRight:
+ call GetPikachuFacing
+ ld hl, .Data
+ call PikaMovementFunc1_GetNextFacing
+ jr PikaMovementFunc1_ApplyStepVector
+
+.Data:
+ db SPRITE_FACING_DOWN, PIKASTEPDIR_UP_LEFT << 2
+ db SPRITE_FACING_UP, PIKASTEPDIR_DOWN_RIGHT << 2
+ db SPRITE_FACING_LEFT, PIKASTEPDIR_UP_RIGHT << 2
+ db SPRITE_FACING_RIGHT, PIKASTEPDIR_DOWN_LEFT << 2
+
+PikaMovementFunc1_ApplyStepVector:
+ rrca
+ rrca
+ and $7
+ ld e, a
+ call GetPikachuStepVectorMagnitude
+ ld d, a
+ call UpdatePikachuPosition
+ call CheckPikachuStepTimer1
+ ret nz
+ call PikaMovementFunc1_EndCommand
+ ret
+
+PikaMovementFunc1_GetNextFacing:
+ push de
+ ld d, a
+.loop
+ ld a, [hli]
+ cp d
+ jr z, .found
+ inc hl
+ cp $ff
+ jr nz, .loop
+ pop de
+ ret
+
+.found
+ ld a, [hl]
+ pop de
+ scf
+ ret
+
+PikaMovementFunc1_MoveDown:
+ ld a, PIKASTEPDIR_DOWN
+ jr PikaMovementFunc1_ApplyFacingAndMove
+
+PikaMovementFunc1_MoveUp:
+ ld a, PIKASTEPDIR_UP
+ jr PikaMovementFunc1_ApplyFacingAndMove
+
+PikaMovementFunc1_MoveLeft:
+ ld a, PIKASTEPDIR_LEFT
+ jr PikaMovementFunc1_ApplyFacingAndMove
+
+PikaMovementFunc1_MoveRight:
+ ld a, PIKASTEPDIR_RIGHT
+ jr PikaMovementFunc1_ApplyFacingAndMove
+
+PikaMovementFunc1_MoveDownLeft:
+ ld e, PIKASTEPDIR_DOWN_LEFT
+ jr PikaMovementFunc1_MoveDiagonally
+
+PikaMovementFunc1_MoveDownRight:
+ ld e, PIKASTEPDIR_DOWN_RIGHT
+ jr PikaMovementFunc1_MoveDiagonally
+
+PikaMovementFunc1_MoveUpLeft:
+ ld e, PIKASTEPDIR_UP_LEFT
+ jr PikaMovementFunc1_MoveDiagonally
+
+PikaMovementFunc1_MoveUpRight:
+ ld e, PIKASTEPDIR_UP_RIGHT
+ jr PikaMovementFunc1_MoveDiagonally
+
+PikaMovementFunc1_ApplyFacingAndMove:
+ ld e, a
+ call SetPikachuFacing
+PikaMovementFunc1_MoveDiagonally:
+ call GetPikachuStepVectorMagnitude
+ ld d, a
+ push de
+ call UpdatePikachuPosition
+ pop de
+ call CheckPikachuStepTimer1
+ ret nz
+ ld a, e
+ call ApplyPikachuStepVector
+ call PikaMovementFunc1_EndCommand
+ ret
+
+PikaMovementFunc1_LookDown:
+ ld a, PIKASTEPDIR_DOWN
+ jr PikaMovementFunc1_ApplyFacing
+
+PikaMovementFunc1_LookUp:
+ ld a, PIKASTEPDIR_UP
+ jr PikaMovementFunc1_ApplyFacing
+
+PikaMovementFunc1_LookLeft:
+ ld a, PIKASTEPDIR_LEFT
+ jr PikaMovementFunc1_ApplyFacing
+
+PikaMovementFunc1_LookRight:
+ ld a, PIKASTEPDIR_RIGHT
+ jr PikaMovementFunc1_ApplyFacing
+
+PikaMovementFunc1_ApplyFacing:
+ call SetPikachuFacing
+ call PikaMovementFunc1_EndCommand
+ ret
+
+UpdatePikachuPosition:
+ push de
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ pop de
+ ld a, d
+ jp hl
+
+.Jumptable:
+ dw .Down
+ dw .Up
+ dw .Left
+ dw .Right
+ dw .DownLeft
+ dw .DownRight
+ dw .UpLeft
+ dw .UpRight
+
+.Down:
+ ld d, 0
+ ld e, a
+ jr .ApplyVector
+
+.Up:
+ ld d, 0
+ cpl
+ inc a
+ ld e, a
+ jr .ApplyVector
+
+.Left:
+ cpl
+ inc a
+ ld d, a
+ ld e, 0
+ jr .ApplyVector
+
+.Right:
+ ld d, a
+ ld e, 0
+ jr .ApplyVector
+
+.DownLeft:
+ ld e, a
+ cpl
+ inc a
+ ld d, a
+ jr .ApplyVector
+
+.DownRight:
+ ld e, a
+ ld d, a
+ jr .ApplyVector
+
+.UpLeft:
+ cpl
+ inc a
+ ld e, a
+ ld d, a
+ jr .ApplyVector
+
+.UpRight:
+ ld d, a
+ cpl
+ inc a
+ ld e, a
+ jr .ApplyVector
+
+.ApplyVector:
+ ld a, [wPikaSpriteX]
+ add d
+ ld [wPikaSpriteX], a
+ ld a, [wPikaSpriteY]
+ add e
+ ld [wPikaSpriteY], a
+ ret
+
+PikaMovementFunc2Jumptable:
+ dw PikaMovementFunc2_ResetFrameCounterAndFaceCurrent ; 0
+ dw PikaMovementFunc2_UpdateSpriteImageIdxWithPreviousImageIdxDirection ; 1
+ dw PikaMovementFunc2_UpdateSpriteImageIdxWithFacing ; 2
+ dw PikaMovementFunc2_TurnParameter ; 3
+ dw PikaMovementFunc2_TurnClockwise ; 4
+ dw PikaMovementFunc2_TurnCounterClockwise ; 5
+ dw PikaMovementFunc2_CopySpriteImageIdxDirectionToSpriteImageIdx ; 6
+ dw PikaMovementFunc2_UpdateJumpWithPreviousImageIdxDirection ; 7
+ dw PikaMovementFunc2_UpdateJumpWithFacing ; 8
+ dw PikaMovementFunc2_CopyFacingToJump ; 9
+ dw PikaMovementFunc2_nop ; 10
+
+PikaMovement_SetSpawnShadow:
+ ld hl, wPikachuMovementFlags
+ set 6, [hl]
+ ret
+
+PikaMovementFunc2_ResetFrameCounterAndFaceCurrent:
+ ld hl, wSpritePlayerStateData1IntraAnimFrameCounter - wSpritePlayerStateData1
+ add hl, bc
+ xor a
+ ld [hli], a
+ ld [hl], a
+ call PikaMovementFunc2_GetImageBaseOffset
+ ld d, a
+ call GetPikachuFacing
+ or d
+ ld [wCurPikaMovementSpriteImageIdx], a
+ ret
+
+PikaMovementFunc2_nop:
+ ret
+
+PikaMovementFunc2_CopySpriteImageIdxDirectionToSpriteImageIdx:
+ call PikaMovementFunc2_GetImageBaseOffset
+ ld d, a
+ call PikaMovementFunc2_GetSpriteImageIdxDirection
+ or d
+ ld [wCurPikaMovementSpriteImageIdx], a
+ ret
+
+PikaMovementFunc2_UpdateSpriteImageIdxWithFacing:
+ call PikaMovementFunc2_GetImageBaseOffset
+ ld d, a
+ call GetPikachuFacing
+ or d
+ ld d, a
+ jr PikaMovementFunc2_UpdateSpriteImageIdx
+
+PikaMovementFunc2_UpdateSpriteImageIdxWithPreviousImageIdxDirection:
+ call PikaMovementFunc2_GetImageBaseOffset
+ ld d, a
+ call PikaMovementFunc2_GetSpriteImageIdxDirection
+ or d
+ ld d, a
+PikaMovementFunc2_UpdateSpriteImageIdx:
+ ld hl, wSpritePlayerStateData1AnimFrameCounter - wSpritePlayerStateData1
+ add hl, bc
+ call CheckPikachuStepTimer2 ; does not preserve hl
+ jr nz, .skip
+ inc [hl]
+.skip
+ ld a, [hl]
+ rrca
+ rrca
+ and 3
+ or d
+ ld [wCurPikaMovementSpriteImageIdx], a
+ ret
+
+PikaMovementFunc2_UpdateJumpWithFacing:
+ call GetPikachuFacing
+ ld d, a
+ jr PikaMovementFunc2_UpdateJump
+
+PikaMovementFunc2_UpdateJumpWithPreviousImageIdxDirection:
+ call PikaMovementFunc2_GetSpriteImageIdxDirection
+ ld d, a
+PikaMovementFunc2_UpdateJump:
+ call PikaMovementFunc2_GetImageBaseOffset
+ or d
+ ld d, a
+ call PikaMovementFunc2_Timer
+ or d
+ ld [wCurPikaMovementSpriteImageIdx], a
+ call PikaMovementFunc_Sine
+ ld [wPikachuMovementYOffset], a
+ and a
+ ret z
+ call PikaMovement_SetSpawnShadow
+ ret
+
+PikaMovementFunc2_CopyFacingToJump:
+ call GetPikachuFacing
+ ld d, a
+ call PikaMovementFunc2_GetImageBaseOffset
+ or d
+ ld [wCurPikaMovementSpriteImageIdx], a
+ call PikaMovementFunc_Sine
+ ld [wPikachuMovementYOffset], a
+ ret
+
+PikaMovementFunc2_TurnParameter:
+ ld a, [wCurPikaMovementParam2]
+ and $40
+ cp $40
+ jr z, PikaMovementFunc2_TurnClockwise
+ jr PikaMovementFunc2_TurnCounterClockwise
+
+PikaMovementFunc2_TurnClockwise:
+ call PikaMovementFunc2_GetSpriteImageIdxDirection
+ ld d, a
+ call CheckPikachuStepTimer2
+ jr nz, .skip
+ ld hl, Data_fd731
+.loop
+ ld a, [hli]
+ cp d
+ jr nz, .loop
+ ld d, [hl]
+.skip
+ call PikaMovementFunc2_GetImageBaseOffset
+ or d
+ ld [wCurPikaMovementSpriteImageIdx], a
+ ret
+
+PikaMovementFunc2_TurnCounterClockwise:
+ call PikaMovementFunc2_GetSpriteImageIdxDirection
+ ld d, a
+ call CheckPikachuStepTimer2
+ jr nz, .skip
+ ld hl, Data_fd731End
+.loop
+ ld a, [hld]
+ cp d
+ jr nz, .loop
+ ld d, [hl]
+.skip
+ call PikaMovementFunc2_GetImageBaseOffset
+ or d
+ ld [wCurPikaMovementSpriteImageIdx], a
+ ret
+
+Data_fd731:
+ db SPRITE_FACING_DOWN
+ db SPRITE_FACING_LEFT
+ db SPRITE_FACING_UP
+ db SPRITE_FACING_RIGHT
+ db SPRITE_FACING_DOWN
+Data_fd731End:
+
+PikaMovementFunc2_Timer:
+ push hl
+ ld hl, wSpritePlayerStateData1IntraAnimFrameCounter - wSpritePlayerStateData1
+ add hl, bc
+ ld a, [hl]
+ inc a
+ and $3
+ ld [hli], a
+ jr nz, .load_pop
+ ld a, [hl]
+ inc a
+ and $3
+ ld [hl], a
+.load_pop
+ ld a, [hl]
+ pop hl
+ ret
+
+PikaMovementFunc2_GetImageBaseOffset:
+ push hl
+ ld hl, wSpritePlayerStateData2ImageBaseOffset - wSpritePlayerStateData1
+ add hl, bc
+ ld a, [hl]
+ dec a
+ swap a
+ pop hl
+ ret
+
+PikaMovementFunc2_GetSpriteImageIdxDirection:
+ push hl
+ ld hl, wSpritePlayerStateData1ImageIndex - wSpritePlayerStateData1
+ add hl, bc
+ ld a, [hl]
+ and $c
+ pop hl
+ ret
+
+GetPikachuFacing:
+ push hl
+ ld hl, wSpritePlayerStateData1FacingDirection - wSpritePlayerStateData1
+ add hl, bc
+ ld a, [hl]
+ and $c
+ pop hl
+ ret
+
+SetPikachuFacing:
+ push hl
+ ld hl, wSpritePlayerStateData1FacingDirection - wSpritePlayerStateData1
+ add hl, bc
+ add a
+ add a
+ and $c
+ ld [hl], a
+ pop hl
+ ret
+
+CheckPikachuStepTimer1:
+ ld hl, wPikachuStepTimer
+ inc [hl]
+ ld a, [wCurPikaMovementParam1]
+ and $1f
+ inc a
+ cp [hl]
+ ret nz
+ ld [hl], 0
+ ret
+
+GetPikachuStepVectorMagnitude:
+ ; *XX*****
+ ld a, [wCurPikaMovementParam1]
+ swap a
+ rrca
+ and $3
+ inc a
+ ret
+
+CheckPikachuStepTimer2:
+ ld hl, wPikachuStepSubtimer
+ inc [hl]
+ ld a, [wCurPikaMovementParam2]
+ and $f
+ inc a
+ cp [hl]
+ ret nz
+ ld [hl], 0
+ ret
+
+PikaMovementFunc_Sine:
+ call .GetArgument
+ ld a, [wPikachuStepSubtimer]
+ add e
+ ld [wPikachuStepSubtimer], a
+ add $20
+ ld e, a
+ push hl
+ push bc
+ call Sine_e
+ pop bc
+ pop hl
+ ret
+
+.GetArgument:
+ ld a, [wCurPikaMovementParam2]
+ and $f
+ inc a
+ ld d, a
+ ld a, [wCurPikaMovementParam2]
+ swap a
+ and $7
+ ld e, a
+ ld a, 1
+ jr z, .okay
+.loop
+ add a
+ dec e
+ jr nz, .loop
+.okay
+ ld e, a
+ ret
+
+ApplyPikachuStepVector:
+ push bc
+ ld c, a
+ ld b, 0
+ ld hl, .StepVectors
+ add hl, bc
+ add hl, bc
+ ld d, [hl]
+ inc hl
+ ld e, [hl]
+ pop bc
+ ld hl, wSpritePlayerStateData2MapY - wSpritePlayerStateData1
+ add hl, bc
+ ld a, [hl]
+ add e
+ ld [hli], a
+ ld a, [hl]
+ add d
+ ld [hl], a
+ ret
+
+.StepVectors:
+ db 0, 1
+ db 0, -1
+ db -1, 0
+ db 1, 0
+ db -1, 1
+ db 1, 1
+ db -1, -1
+ db 1, -1
+
+LoadPikachuShadowOAMData:
+ push bc
+ push de
+ push hl
+
+ ld bc, wShadowOAMSprite36
+ ld a, [wPikaSpriteY]
+ ld e, a
+ ld a, [wPikaSpriteX]
+ ld d, a
+ ld hl, .OAMData
+ call .LoadOAMData
+
+ pop hl
+ pop de
+ pop bc
+ ret
+
+.OAMData:
+ db 2
+ db $0c, $00, $ff, 0
+ db $0c, $08, $ff, OAM_XFLIP
+
+.LoadOAMData:
+ ld a, e
+ add $10
+ ld e, a
+ ld a, d
+ add $8
+ ld d, a
+ ld a, [hli]
+.loop
+ push af
+ ld a, [hli]
+ add e
+ ld [bc], a
+ inc bc
+ ld a, [hli]
+ add d
+ ld [bc], a
+ inc bc
+ ld a, [hli]
+ ld [bc], a
+ inc bc
+ ld a, [hli]
+ ld [bc], a
+ inc bc
+ pop af
+ dec a
+ jr nz, .loop
+ ret
+
+LoadPikachuShadowIntoVRAM::
+ ld hl, vNPCSprites2 + $7f * $10
+ ld de, LedgeHoppingShadowGFX_3F
+ lb bc, BANK(LedgeHoppingShadowGFX_3F), (LedgeHoppingShadowGFX_3FEnd - LedgeHoppingShadowGFX_3F) / 8
+ jp CopyVideoDataDoubleAlternate
+
+LedgeHoppingShadowGFX_3F:
+INCBIN "gfx/overworld/shadow.1bpp"
+LedgeHoppingShadowGFX_3FEnd:
+
+LoadPikachuBallIconIntoVRAM:
+ ld hl, vNPCSprites2 + $7e * $10
+ ld de, OverworldPikachuBallGFX
+ lb bc, BANK(OverworldPikachuBallGFX), 1
+ jp CopyVideoDataDoubleAlternate
+
+Func_fd851:
+ ld hl, vNPCSprites + $c * $10
+ ld a, 3
+.loop
+ push af
+ push hl
+ ld de, OverworldPikachuBallGFX
+ lb bc, BANK(OverworldPikachuBallGFX), 4
+ call CopyVideoDataAlternate
+ pop hl
+ ld de, 4 * $10
+ add hl, de
+ pop af
+ dec a
+ jr nz, .loop
+ ret
+
+OverworldPikachuBallGFX:
+INCBIN "gfx/overworld/pikachu_ball.2bpp"
+
+LoadPikachuSpriteIntoVRAM:
+ ld de, PikachuSprite
+ lb bc, BANK(PikachuSprite), (SandshrewSprite - PikachuSprite) / 32
+ ld hl, vNPCSprites + $c * $10
+ push bc
+ call CopyVideoDataAlternate
+ ld de, PikachuSprite + $c * $10
+ ld hl, vNPCSprites2 + $c * $10
+ ldh a, [hPikachuSpriteVRAMOffset]
+ and a
+ jr z, .load
+ ld de, PikachuSprite + $c * $10
+ ld hl, vNPCSprites2 + $4c * $10
+.load
+ pop bc
+ call CopyVideoDataAlternate
+ call LoadPikachuShadowIntoVRAM
+ call LoadPikachuBallIconIntoVRAM
+ ret
+
+PikachuPewterPokecenterCheck:
+ ld a, [wCurMap]
+ cp PEWTER_POKECENTER
+ ret nz
+ call EnablePikachuFollowingPlayer
+ call StarterPikachuEmotionCommand_turnawayfromplayer
+ ret
+
+PikachuFanClubCheck:
+ ld a, [wCurMap]
+ cp POKEMON_FAN_CLUB
+ ret nz
+ call EnablePikachuFollowingPlayer
+ call StarterPikachuEmotionCommand_turnawayfromplayer
+ ret
+
+PikachuBillsHouseCheck:
+ ld a, [wCurMap]
+ cp BILLS_HOUSE
+ ret nz
+ call EnablePikachuFollowingPlayer
+ ret
+
+Pikachu_LoadCurrentMapViewUpdateSpritesAndDelay3:
+ call LoadCurrentMapView
+ call UpdateSprites
+ call Delay3
+ ret
+
+Cosine_e: ; cosine?
+ ld a, e
+ add $10
+ jr asm_fd908
+
+Sine_e: ; sine?
+ ld a, e
+asm_fd908:
+ and $3f
+ cp $20
+ jr nc, .asm_fd913
+ call GetSine
+ ld a, h
+ ret
+
+.asm_fd913
+ and $1f
+ call GetSine
+ ld a, h
+ cpl
+ inc a
+ ret
+
+GetSine:
+ ld e, a
+ ld a, d
+ ld d, 0
+ ld hl, SineWave_3f
+ add hl, de
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld hl, 0
+.asm_fd92b
+ srl a
+ jr nc, .asm_fd930
+ add hl, de
+.asm_fd930
+ sla e
+ rl d
+ and a
+ jr nz, .asm_fd92b
+ ret
+
+SineWave_3f:
+ sine_table 32
diff --git a/engine/pikachu/pikachu_pcm.asm b/engine/pikachu/pikachu_pcm.asm
new file mode 100644
index 00000000..643492ce
--- /dev/null
+++ b/engine/pikachu/pikachu_pcm.asm
@@ -0,0 +1,165 @@
+PlayPikachuSoundClip::
+ vc_hook Unknown_PlayPikachuSoundClip_start
+ ld a, e
+ ld e, a
+ ld d, $0
+ ld hl, PikachuCriesPointerTable
+ add hl, de
+ add hl, de
+ add hl, de
+ ld b, [hl] ; bank of pikachu cry data
+ inc hl
+ ld a, [hli] ; cry data pointer
+ ld h, [hl]
+ ld l, a
+ ld c, $4
+.loop
+ dec c
+ jr z, .done_delay
+ call DelayFrame
+ jr .loop
+
+.done_delay
+ di
+ push bc
+ push hl
+ ld a, $80
+ ldh [rAUDENA], a
+ ld a, $77
+ ldh [rAUDVOL], a
+ xor a
+ ldh [rAUD3ENA], a
+ ld hl, _AUD3WAVERAM
+ ld de, wRedrawRowOrColumnSrcTiles
+.saveWaveDataLoop
+ ld a, [hl]
+ ld [de], a
+ inc de
+ ld a, $ff
+ ld [hli], a
+ ld a, l
+ cp $40 ; end of wave data
+ jr nz, .saveWaveDataLoop
+ vc_patch Unknown_PlayPikachuSoundClip_end
+IF DEF(_YELLOW_VC)
+ ld a, 0
+ELSE
+ ld a, $80
+ENDC
+ vc_patch_end
+ ldh [rAUD3ENA], a
+ ldh a, [rAUDTERM]
+ or $44
+ ldh [rAUDTERM], a
+ ld a, $ff
+ ldh [rAUD3LEN], a
+ ld a, $20
+ ldh [rAUD3LEVEL], a
+ ld a, $ff
+ ldh [rAUD3LOW], a
+ ld a, $87
+ ldh [rAUD3HIGH], a
+ pop hl
+ pop bc
+ call PlayPikachuPCM
+ xor a
+ ld [wc0f3], a
+ ld [wc0f3 + 1], a
+ ld a, $80
+ ldh [rAUDENA], a
+ xor a
+ ldh [rAUD3ENA], a
+ ld hl, _AUD3WAVERAM
+ ld de, wRedrawRowOrColumnSrcTiles
+.reloadWaveDataLoop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, l
+ cp $40 ; end of wave data
+ jr nz, .reloadWaveDataLoop
+ ld a, $80
+ ldh [rAUD3ENA], a
+ ldh a, [rAUDTERM]
+ and $bb
+ ldh [rAUDTERM], a
+ xor a
+ ld [wChannelSoundIDs + CHAN5], a
+ ld [wChannelSoundIDs + CHAN6], a
+ ld [wChannelSoundIDs + CHAN7], a
+ ld [wChannelSoundIDs + CHAN8], a
+ ldh a, [hLoadedROMBank]
+ ei
+ ret
+
+PikachuCriesPointerTable::
+; format:
+; db bank
+; dw pointer to cry
+
+ const_def
+
+; bank 21
+ pikacry_def PikachuCry1
+ pikacry_def PikachuCry2
+ pikacry_def PikachuCry3
+ pikacry_def PikachuCry4
+
+; bank 22
+ pikacry_def PikachuCry5
+ pikacry_def PikachuCry6
+ pikacry_def PikachuCry7
+
+; bank 23
+ pikacry_def PikachuCry8
+ pikacry_def PikachuCry9
+ pikacry_def PikachuCry10
+
+; bank 24
+ pikacry_def PikachuCry11
+ pikacry_def PikachuCry12
+ pikacry_def PikachuCry13
+
+; bank 25
+ pikacry_def PikachuCry14
+ pikacry_def PikachuCry15
+
+; banks 31-34, in no particular order
+
+ pikacry_def PikachuCry16
+ pikacry_def PikachuCry17
+ pikacry_def PikachuCry18
+ pikacry_def PikachuCry19
+ pikacry_def PikachuCry20
+ pikacry_def PikachuCry21
+ pikacry_def PikachuCry22
+ pikacry_def PikachuCry23
+ pikacry_def PikachuCry24
+ pikacry_def PikachuCry25
+ pikacry_def PikachuCry26
+
+; bank 35
+ pikacry_def PikachuCry27
+ pikacry_def PikachuCry28
+ pikacry_def PikachuCry29
+ pikacry_def PikachuCry30
+ pikacry_def PikachuCry31
+
+; bank 36
+ pikacry_def PikachuCry32
+ pikacry_def PikachuCry33
+ pikacry_def PikachuCry34
+
+; bank 37
+ pikacry_def PikachuCry35
+ pikacry_def PikachuCry36
+
+; banks 36-38
+ pikacry_def PikachuCry37
+ pikacry_def PikachuCry38
+ pikacry_def PikachuCry39
+ pikacry_def PikachuCry40
+ pikacry_def PikachuCry41
+ pikacry_def PikachuCry42
+
+DEF NUM_PIKA_CRIES EQU const_value
diff --git a/engine/pikachu/pikachu_pic_animation.asm b/engine/pikachu/pikachu_pic_animation.asm
new file mode 100644
index 00000000..40f88dc5
--- /dev/null
+++ b/engine/pikachu/pikachu_pic_animation.asm
@@ -0,0 +1,852 @@
+GetPikaPicAnimationScriptIndex:
+ ld hl, PikachuMoodLookupTable
+ ld a, [wPikachuMood]
+ ld d, a
+.get_mood_param
+ ld a, [hli]
+ inc hl
+ cp d
+ jr c, .get_mood_param
+ dec hl
+ ld e, [hl]
+ ld hl, PikaPicAnimationScriptPointerLookupTable
+ ld a, [wPikachuHappiness]
+ ld d, a
+ ld bc, 6
+.get_happiness_param
+ ld a, [hl]
+ cp d
+ jr nc, .got_animation
+ add hl, bc
+ jr .get_happiness_param
+
+.got_animation
+ ld d, 0
+ add hl, de
+ ld a, [hl]
+ ret
+
+PikachuMoodLookupTable:
+; First byte: mood threshold
+; Second byte: column index in PikaPicAnimationScriptPointerLookupTable
+ db 40, 1
+ db 127, 2
+ db 128, 3
+ db 210, 4
+ db 255, 5
+
+PikaPicAnimationScriptPointerLookupTable:
+; First byte: happiness threshold
+; Remaining bytes: loaded based on Pikachu's mood
+ db 50
+ dpikapic PikaPicAnimScript14
+ dpikapic PikaPicAnimScript14
+ dpikapic PikaPicAnimScript6
+ dpikapic PikaPicAnimScript13
+ dpikapic PikaPicAnimScript13
+
+ db 100
+ dpikapic PikaPicAnimScript9
+ dpikapic PikaPicAnimScript9
+ dpikapic PikaPicAnimScript5
+ dpikapic PikaPicAnimScript12
+ dpikapic PikaPicAnimScript12
+
+ db 130
+ dpikapic PikaPicAnimScript3
+ dpikapic PikaPicAnimScript3
+ dpikapic PikaPicAnimScript1
+ dpikapic PikaPicAnimScript8
+ dpikapic PikaPicAnimScript8
+
+ db 160
+ dpikapic PikaPicAnimScript3
+ dpikapic PikaPicAnimScript3
+ dpikapic PikaPicAnimScript4
+ dpikapic PikaPicAnimScript15
+ dpikapic PikaPicAnimScript15
+
+ db 200
+ dpikapic PikaPicAnimScript17
+ dpikapic PikaPicAnimScript17
+ dpikapic PikaPicAnimScript7
+ dpikapic PikaPicAnimScript2
+ dpikapic PikaPicAnimScript2
+
+ db 250
+ dpikapic PikaPicAnimScript17
+ dpikapic PikaPicAnimScript17
+ dpikapic PikaPicAnimScript16
+ dpikapic PikaPicAnimScript10
+ dpikapic PikaPicAnimScript10
+
+ db 255
+ dpikapic PikaPicAnimScript17
+ dpikapic PikaPicAnimScript17
+ dpikapic PikaPicAnimScript19
+ dpikapic PikaPicAnimScript20
+ dpikapic PikaPicAnimScript20
+
+StarterPikachuEmotionCommand_pikapic:
+ ldh a, [hAutoBGTransferEnabled]
+ push af
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ld a, [de]
+ ld [wPikaPicAnimNumber], a
+ inc de
+ push de
+ call .RunPikapic
+ pop de
+ pop af
+ ldh [hAutoBGTransferEnabled], a
+ ret
+
+.RunPikapic:
+ call PlacePikapicTextBoxBorder
+ callfar LoadOverworldPikachuFrontpicPalettes
+ call ResetPikaPicAnimBuffer
+ call LoadCurrentPikaPicAnimScriptPointer
+ call ExecutePikaPicAnimScript
+ call PlacePikapicTextBoxBorder
+ call RunDefaultPaletteCommand
+ ret
+
+ResetPikaPicAnimBuffer:
+ ld hl, wCurPikaMovementData
+ ld bc, wCurPikaMovementDataEnd - wCurPikaMovementData
+ xor a
+ call FillMemory
+ ld hl, wPikaPicAnimObjectDataBufferSize
+ ld bc, wPikaPicAnimObjectDataBufferEnd - wPikaPicAnimObjectDataBufferSize
+ xor a
+ call FillMemory
+ call ClearPikaPicUsedGFXBuffer
+ ld hl, 100
+ ld a, l
+ ld [wPikaPicAnimTimer], a
+ ld a, h
+ ld [wPikaPicAnimTimer + 1], a
+ ld a, $7
+ ld [wPikaPicPikaDrawStartX], a
+ ld a, $6
+ ld [wPikaPicPikaDrawStartY], a
+ ret
+
+PlacePikapicTextBoxBorder:
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ hlcoord 6, 5
+ lb bc, 5, 5
+ call TextBoxBorder
+ call Delay3
+ call UpdateSprites
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call Delay3
+ ret
+
+LoadCurrentPikaPicAnimScriptPointer:
+ ld a, [wPikaPicAnimNumber]
+ cp $1d
+ jr c, .valid
+ ld a, $0
+.valid
+ ld e, a
+ ld d, 0
+ ld hl, PikaPicAnimPointers
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call UpdatePikaPicAnimPointer
+ ret
+
+MACRO pikapic_def
+\1_id:
+ dw \1
+ENDM
+
+PikaPicAnimPointers:
+ pikapic_def PikaPicAnimScript0 ; 00
+ pikapic_def PikaPicAnimScript1 ; 01
+ pikapic_def PikaPicAnimScript2 ; 02
+ pikapic_def PikaPicAnimScript3 ; 03
+ pikapic_def PikaPicAnimScript4 ; 04
+ pikapic_def PikaPicAnimScript5 ; 05
+ pikapic_def PikaPicAnimScript6 ; 06
+ pikapic_def PikaPicAnimScript7 ; 07
+ pikapic_def PikaPicAnimScript8 ; 08
+ pikapic_def PikaPicAnimScript9 ; 09
+ pikapic_def PikaPicAnimScript10 ; 0a
+ pikapic_def PikaPicAnimScript11 ; 0b
+ pikapic_def PikaPicAnimScript12 ; 0c
+ pikapic_def PikaPicAnimScript13 ; 0d
+ pikapic_def PikaPicAnimScript14 ; 0e
+ pikapic_def PikaPicAnimScript15 ; 0f
+ pikapic_def PikaPicAnimScript16 ; 10
+ pikapic_def PikaPicAnimScript17 ; 11
+ pikapic_def PikaPicAnimScript18 ; 12
+ pikapic_def PikaPicAnimScript19 ; 13
+ pikapic_def PikaPicAnimScript20 ; 14
+ pikapic_def PikaPicAnimScript21 ; 15
+ pikapic_def PikaPicAnimScript22 ; 16
+ pikapic_def PikaPicAnimScript23 ; 17
+ pikapic_def PikaPicAnimScript24 ; 18
+ pikapic_def PikaPicAnimScript25 ; 19
+ pikapic_def PikaPicAnimScript26 ; 1a
+ pikapic_def PikaPicAnimScript27 ; 1b
+ pikapic_def PikaPicAnimScript28 ; 1c
+ pikapic_def PikaPicAnimScript29 ; 1d
+
+ExecutePikaPicAnimScript:
+.loop
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call RunPikaPicAnimSetupScript
+ call DummyFunction_fdad5
+ call AnimateCurrentPikaPicAnimFrame
+ call DummyFunction_fdad5
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call PikaPicAnimTimerAndJoypad
+ and a
+ jr z, .loop
+ ret
+
+PikaPicAnimTimerAndJoypad:
+ call Delay3
+ call CheckPikaPicAnimTimer
+ and a
+ ret nz
+ call JoypadLowSensitivity
+ ldh a, [hJoyPressed]
+ and PAD_A | PAD_B
+ ret
+
+CheckPikaPicAnimTimer:
+ ld hl, wPikaPicAnimTimer
+ dec [hl]
+ jr nz, .not_done_yet
+ inc hl
+ ld a, [hl]
+ and a
+ jr z, .timer_expired
+ dec [hl]
+.not_done_yet
+ xor a
+ ret
+
+.timer_expired
+ ld a, $1
+ ret
+
+DummyFunction_fdad5:
+ ret
+
+AnimateCurrentPikaPicAnimFrame:
+ ld bc, wPikaPicAnimObjectDataBuffer
+ ld a, 4
+.loop
+ push af
+ push bc
+ ld hl, 0 ; struct index
+ add hl, bc
+ ld a, [hli]
+ and a
+ jr z, .skip
+ ld a, [hli]
+ ld [wCurPikaPicAnimObjectScriptIdx], a
+ ld a, [hli]
+ ld [wCurPikaPicAnimObjectFrameIdx], a
+ ld a, [hli]
+ ld [wCurPikaPicAnimObjectFrameTimer], a
+ ld a, [hli]
+ ld [wCurPikaPicAnimObjectVTileOffset], a
+ ld a, [hli]
+ ld [wCurPikaPicAnimObjectXOffset], a
+ ld a, [hli]
+ ld [wCurPikaPicAnimObjectYOffset], a
+ ld a, [hli]
+ ld [wCurPikaPicAnimObject + 6], a
+ push bc
+ call LoadPikaPicAnimObjectData
+ pop bc
+ ld hl, 1 ; script index
+ add hl, bc
+ ld a, [wCurPikaPicAnimObjectScriptIdx]
+ ld [hli], a
+ ld a, [wCurPikaPicAnimObjectFrameIdx]
+ ld [hli], a
+ ld a, [wCurPikaPicAnimObjectFrameTimer]
+ ld [hli], a
+ ld a, [wCurPikaPicAnimObjectVTileOffset]
+ ld [hli], a
+ ld a, [wCurPikaPicAnimObjectXOffset]
+ ld [hli], a
+ ld a, [wCurPikaPicAnimObjectYOffset]
+ ld [hli], a
+ ld a, [wCurPikaPicAnimObject + 6]
+ ld [hl], a
+.skip
+ pop bc
+ ld hl, 8
+ add hl, bc
+ ld b, h
+ ld c, l
+ pop af
+ dec a
+ jr nz, .loop
+ ret
+
+PikaPicAnimCommand_object:
+ ld hl, wPikaPicAnimObjectDataBuffer
+ ld de, 8
+ ld c, 4
+.loop
+ ld a, [hl]
+ and a
+ jr z, .found
+ add hl, de
+ dec c
+ jr nz, .loop
+ scf
+ ret
+
+.found
+ ld a, [wPikaPicAnimObjectDataBufferSize]
+ inc a
+ ld [wPikaPicAnimObjectDataBufferSize], a
+ ld [hli], a
+ call GetPikaPicAnimByte
+ ld [hli], a
+ call GetPikaPicAnimByte
+ ld [hl], a
+ xor a
+ ld [hli], a ; overloads
+ ld [hli], a
+ call GetPikaPicAnimByte
+ ld [hli], a
+ call GetPikaPicAnimByte
+ ld [hli], a
+ call GetPikaPicAnimByte
+ ld [hli], a
+ and a
+ ret
+
+PikaPicAnimCommand_deleteobject:
+ call GetPikaPicAnimByte
+ ld b, a
+ ld hl, wPikaPicAnimObjectDataBuffer
+ ld de, 8
+ ld c, 4
+.search
+ ld a, [hl]
+ cp b
+ jr z, .delete
+ add hl, de
+ dec c
+ jr nz, .search
+ scf
+ ret
+
+.delete
+ xor a
+ ld [hl], a
+ ret
+
+LoadPikaPicAnimObjectData:
+.loop
+ ld a, [wCurPikaPicAnimObjectScriptIdx]
+ cp $23
+ jr c, .valid
+ ld a, $4
+.valid
+ ld e, a
+ ld d, 0
+ ld hl, PikaPicAnimBGFramesPointers
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [wCurPikaPicAnimObjectFrameIdx]
+ ld e, a
+ ld d, 0
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ cp $e0
+ jr z, .end
+ jr .init
+
+.end
+ xor a
+ ld [wCurPikaPicAnimObjectFrameIdx], a
+ ld [wCurPikaPicAnimObjectFrameTimer], a
+ jr .loop
+
+.init
+ push hl
+ call LoadCurPikaPicObjectTilemap
+ pop hl
+ ld a, [hl]
+ and a
+ jr z, .not_done ; lasts forever
+ ld a, [wCurPikaPicAnimObjectFrameTimer]
+ inc a
+ ld [wCurPikaPicAnimObjectFrameTimer], a
+ cp [hl]
+ jr nz, .not_done
+ xor a
+ ld [wCurPikaPicAnimObjectFrameTimer], a
+ ld a, [wCurPikaPicAnimObjectFrameIdx]
+ inc a
+ ld [wCurPikaPicAnimObjectFrameIdx], a
+.not_done
+ ret
+
+INCLUDE "data/pikachu/pikachu_pic_objects.asm"
+
+LoadCurPikaPicObjectTilemap:
+ and a
+ ret z
+ ld e, a
+ ld d, 0
+ ld hl, PikaPicTilemapPointers
+ add hl, de
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld a, [de]
+ ld c, a
+ inc de
+ ld a, [de]
+ ld b, a
+ inc de
+ push de
+ push bc
+ call .GetStartCoords
+ pop bc
+ pop de
+.row
+ push bc
+ push hl
+ ld a, [wCurPikaPicAnimObjectVTileOffset] ; tile id offset
+ ld c, a
+.col
+ ld a, [de]
+ inc de
+ cp $ff
+ jr z, .skip
+ add c
+ ld [hl], a
+.skip
+ inc hl
+ dec b
+ jr nz, .col
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec c
+ jr nz, .row
+ ret
+
+.GetStartCoords:
+ push bc
+ ld a, [wCurPikaPicAnimObjectYOffset] ; Y offset
+ ld b, a
+ ld a, [wPikaPicPikaDrawStartY]
+ add b
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH
+ call AddNTimes
+ ld a, [wCurPikaPicAnimObjectXOffset] ; X offset
+ ld c, a
+ ld a, [wPikaPicPikaDrawStartX]
+ add c
+ ld c, a
+ ld b, 0
+ add hl, bc
+ pop bc
+ ret
+
+INCLUDE "data/pikachu/pikachu_pic_tilemaps.asm"
+
+LoadPikaPicAnimGFXHeader:
+ push hl
+ ld e, a
+ ld d, 0
+ ld hl, PikaPicAnimGFXHeaders
+ add hl, de
+ add hl, de
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld c, a
+ ld a, [hli]
+ ld b, a
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ pop hl
+ ret
+
+RunPikaPicAnimSetupScript:
+ call .CheckAndAdvanceTimer
+ ret c
+ xor a
+ ld [wPikaPicAnimPointerSetupFinished], a
+.loop
+ call GetPikaPicAnimByte
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call JumpToAddress
+ ld a, [wPikaPicAnimPointerSetupFinished]
+ and a
+ jr z, .loop
+ ret
+
+.CheckAndAdvanceTimer:
+ ld a, [wPikaPicAnimDelay]
+ and a
+ ret z
+ dec a
+ ld [wPikaPicAnimDelay], a
+ scf
+ ret
+
+.Jumptable:
+ dw PikaPicAnimCommand_nop ; 00, 0 params
+ dw PikaPicAnimCommand_writebyte ; 01, 1 param
+ dw PikaPicAnimCommand_loadgfx ; 02, 1 param
+ dw PikaPicAnimCommand_object ; 03, 5 params
+ dw PikaPicAnimCommand_nop4 ; 04, 0 params
+ dw PikaPicAnimCommand_nop5 ; 05, 0 params
+ dw PikaPicAnimCommand_deleteobject ; 06, 1 param
+ dw PikaPicAnimCommand_nop7 ; 07, 0 params
+ dw PikaPicAnimCommand_nop8 ; 08, 0 params
+ dw PikaPicAnimCommand_jump ; 09, 1 dw param
+ dw PikaPicAnimCommand_setduration ; 0a, 1 dw param
+ dw PikaPicAnimCommand_cry ; 0b, 1 param
+ dw PikaPicAnimCommand_thunderbolt ; 0c, 0 params
+ dw PikaPicAnimCommand_run ; 0d, 0 params (ret)
+ dw PikaPicAnimCommand_ret ; 0e, 0 params (ret)
+
+PikaPicAnimCommand_nop:
+ ret
+
+PikaPicAnimCommand_ret:
+ ld a, 1
+ ld [wPikaPicAnimTimer], a
+ xor a
+ ld [wPikaPicAnimTimer + 1], a
+ jr PikaPicAnimCommand_run
+
+; XXX
+ ret
+
+PikaPicAnimCommand_setduration:
+ call GetPikaPicAnimByte
+ ld [wPikaPicAnimTimer], a
+ call GetPikaPicAnimByte
+ ld [wPikaPicAnimTimer + 1], a
+ ret
+
+PikaPicAnimCommand_run:
+ ld a, $ff
+ ld [wPikaPicAnimPointerSetupFinished], a
+ ret
+
+PikaPicAnimCommand_writebyte:
+ call GetPikaPicAnimByte
+ ld [wPikaPicAnimDelay], a
+ ret
+
+PikaPicAnimCommand_nop4:
+PikaPicAnimCommand_nop5:
+PikaPicAnimCommand_nop7:
+PikaPicAnimCommand_nop8:
+ ret
+
+PikaPicAnimCommand_jump:
+ call GetPikaPicAnimByte
+ ld l, a
+ call GetPikaPicAnimByte
+ ld h, a
+ call UpdatePikaPicAnimPointer
+ ret
+
+GetPikaPicAnimByte:
+ push hl
+ ld hl, wPikaPicAnimPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [hli]
+ call UpdatePikaPicAnimPointer
+ pop hl
+ ret
+
+UpdatePikaPicAnimPointer:
+ push af
+ ld a, l
+ ld [wPikaPicAnimPointer], a
+ ld a, h
+ ld [wPikaPicAnimPointer + 1], a
+ pop af
+ ret
+
+PikaPicAnimCommand_loadgfx:
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ ldh a, [hAutoBGTransferEnabled]
+ push af
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ldh a, [hTileAnimations]
+ push af
+ xor a
+ ldh [hTileAnimations], a
+ call GetPikaPicAnimByte
+ ld [wPikaPicAnimCurGraphicID], a
+ ld a, [wPikaPicAnimCurGraphicID]
+ call LoadPikaPicAnimGFXHeader
+ ld a, c
+ cp $ff
+ jr z, .compressed
+ call RequestPikaPicAnimGFX
+ jr .done
+
+.compressed
+ call DecompressRequestPikaPicAnimGFX
+.done
+ pop af
+ ldh [hTileAnimations], a
+ pop af
+ ldh [hAutoBGTransferEnabled], a
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ ret
+
+RequestPikaPicAnimGFX:
+ push de
+ ld a, [wPikaPicAnimCurGraphicID]
+ ld d, a
+ ld e, c
+ call CheckIfThereIsRoomForPikaPicAnimGFX
+ pop de
+ jr c, .failed
+ call GetPikaPicVRAMAddressForNewGFX
+ call CopyVideoDataAlternate
+ and a
+.failed
+ ret
+
+DecompressRequestPikaPicAnimGFX:
+ push de
+ ld a, [wPikaPicAnimCurGraphicID]
+ ld d, a
+ ld e, 5 * 5
+ call CheckIfThereIsRoomForPikaPicAnimGFX
+ pop de
+ jr c, .failed
+ ld a, b
+ call UncompressSpriteFromDE
+ ld a, BANK("Sprite Buffers")
+ call OpenSRAM
+ ld hl, sSpriteBuffer1
+ ld de, sSpriteBuffer0
+ ld bc, SPRITEBUFFERSIZE * 2
+ call CopyData
+ call CloseSRAM
+ ld a, [wPikaPicAnimCurGraphicID]
+ call LookUpTileOffsetForCurrentPikaPicAnimGFX
+ call GetPikaPicVRAMAddressForNewGFX
+ ld d, h
+ ld e, l
+ call InterlaceMergeSpriteBuffers
+.failed
+ ret
+
+ClearPikaPicUsedGFXBuffer:
+ ld hl, wPikaPicUsedGFXCount
+ ld bc, wPikaPicUsedGFXEnd - wPikaPicUsedGFXCount
+ xor a
+ call FillMemory
+ ret
+
+GetPikaPicVRAMAddressForNewGFX:
+ ld hl, vNPCSprites
+ push bc
+ ld b, a
+ and $f
+ swap a
+ ld c, a
+ ld a, b
+ and $f0
+ swap a
+ ld b, a
+ add hl, bc
+ pop bc
+ ret
+
+CheckIfThereIsRoomForPikaPicAnimGFX:
+; d: idx
+; e: size
+; FATAL: If the graphic has already been loaded, or if there are
+; already 8 graphics objects loaded, the game will execute arbitrary
+; code.
+ push bc
+ push hl
+ ld hl, wPikaPicUsedGFX
+ ld c, 8
+.loop
+ ld a, [hl]
+ and a
+ jr z, .empty
+ cp d
+ jr z, .found
+ inc hl
+ inc hl
+ dec c
+ jr nz, .loop
+ scf
+ ret ; execute hl, then bc
+
+.found
+ inc hl
+ ld a, [hl]
+ ret ; execute hl, then bc
+
+.empty
+ ld [hl], d
+ inc hl
+ ld a, [wPikaPicUsedGFXCount]
+ add $80
+ ld [hl], a
+ ld a, [wPikaPicUsedGFXCount]
+ add e
+ ld [wPikaPicUsedGFXCount], a
+ cp $80
+ jr z, .okay
+ jr nc, .failed
+.okay
+ ld a, [hl]
+ and a
+ jr .pop_ret
+
+.failed
+ scf
+.pop_ret
+ pop hl
+ pop bc
+ ret
+
+LookUpTileOffsetForCurrentPikaPicAnimGFX:
+ push bc
+ push hl
+ ld b, a
+ ld hl, wPikaPicUsedGFX
+ ld c, 8
+.loop
+ ld a, [hli]
+ cp b
+ jr z, .found
+ inc hl
+ dec c
+ jr nz, .loop
+ scf
+ jr .pop_ret
+
+.found
+ ld a, [hl]
+ and a
+.pop_ret
+ pop hl
+ pop bc
+ ret
+
+PikaPicAnimCommand_cry:
+ call GetPikaPicAnimByte
+ cp $ff
+ ret z
+ ld e, a
+ callfar PlayPikachuSoundClip
+ ret
+
+PikaPicAnimCommand_thunderbolt:
+ ld a, $1
+ ld [wMuteAudioAndPauseMusic], a
+ call DelayFrame
+ ld a, [wAudioROMBank]
+ push af
+ ld a, BANK(SFX_Battle_2F)
+ ld [wAudioROMBank], a
+ ld [wAudioSavedROMBank], a
+ call .LoadAudio
+ call PlaySound
+ call .FlashScreen
+ call WaitForSoundToFinish
+ pop af
+ ld [wAudioROMBank], a
+ ld [wAudioSavedROMBank], a
+ xor a
+ ld [wMuteAudioAndPauseMusic], a
+ ret
+
+.LoadAudio:
+ ld hl, MoveSoundTable
+ ld e, THUNDERBOLT
+ ld d, 0
+ add hl, de
+ add hl, de
+ add hl, de
+ ld a, BANK(MoveSoundTable)
+ call GetFarByte
+ ld b, a
+ inc hl
+ ld a, BANK(MoveSoundTable)
+ call GetFarByte
+ inc hl
+ ld [wFrequencyModifier], a
+ ld a, BANK(MoveSoundTable)
+ call GetFarByte
+ ld [wTempoModifier], a
+ ld a, b
+ ret
+
+.FlashScreen:
+ ld hl, PikaPicAnimThunderboltPals
+.loop
+ ld a, [hli]
+ cp $ff
+ ret z
+ ld c, a
+ ld b, [hl]
+ inc hl
+ push hl
+ call .UpdatePal
+ pop hl
+ jr .loop
+
+.UpdatePal:
+ ld a, b
+ ldh [rBGP], a
+ call UpdateCGBPal_BGP
+ call DelayFrames
+ ret
+
+INCLUDE "data/pikachu/pikachu_pic_animation.asm"
diff --git a/engine/pikachu/pikachu_status.asm b/engine/pikachu/pikachu_status.asm
new file mode 100644
index 00000000..ffd2b718
--- /dev/null
+++ b/engine/pikachu/pikachu_status.asm
@@ -0,0 +1,260 @@
+IsStarterPikachuAliveInOurParty::
+ ld hl, wPartySpecies
+ ld de, wPartyMon1OTID
+ ld bc, wPartyMonOT
+ push hl
+.loop
+ pop hl
+ ld a, [hli]
+ push hl
+ inc a
+ jr z, .noPlayerPikachu
+ cp STARTER_PIKACHU + 1
+ jr nz, .curMonNotPlayerPikachu
+ ld h, d
+ ld l, e
+ ld a, [wPlayerID]
+ cp [hl]
+ jr nz, .curMonNotPlayerPikachu
+ inc hl
+ ld a, [wPlayerID+1]
+ cp [hl]
+ jr nz, .curMonNotPlayerPikachu
+
+ push de
+ push bc
+ ld hl, wPlayerName
+ ld d, NAME_LENGTH_JP
+.nameCompareLoop
+ dec d
+ jr z, .sameOT
+ ld a, [bc]
+ inc bc
+ cp [hl]
+ inc hl
+ jr z, .nameCompareLoop
+ pop bc
+ pop de
+
+.curMonNotPlayerPikachu
+ ld hl, wPartyMon2 - wPartyMon1
+ add hl, de
+ ld d, h
+ ld e, l
+ ld hl, NAME_LENGTH
+ add hl, bc
+ ld b, h
+ ld c, l
+ jr .loop
+
+.sameOT
+ pop bc
+ pop de
+ ld h, d
+ ld l, e
+ ld bc, wPartyMon1HP - wPartyMon1OTID
+ add hl, bc
+ ld a, [hli]
+ or [hl]
+ jr z, .noPlayerPikachu ; fainted Starter Pikachu
+ pop hl
+ scf
+ ret
+
+.noPlayerPikachu
+ pop hl
+ and a
+ ret
+
+IsThisBoxMonStarterPikachu::
+ ld hl, wBoxMon1
+ ld bc, wBoxMon2 - wBoxMon1
+ ld de, wBoxMonOT
+ jr IsThisMonStarterPikachu
+
+IsThisPartyMonStarterPikachu::
+ ld hl, wPartyMon1
+ ld bc, wPartyMon2 - wPartyMon1
+ ld de, wPartyMonOT
+IsThisMonStarterPikachu:
+ ld a, [wWhichPokemon]
+ call AddNTimes
+ ld a, [hl]
+ cp STARTER_PIKACHU
+ jr nz, .notPlayerPikachu
+ ld bc, wPartyMon1OTID - wPartyMon1
+ add hl, bc
+ ld a, [wPlayerID]
+ cp [hl]
+ jr nz, .notPlayerPikachu
+ inc hl
+ ld a, [wPlayerID+1]
+ cp [hl]
+ jr nz, .notPlayerPikachu
+ ld h, d
+ ld l, e
+ ld a, [wWhichPokemon]
+ ld bc, NAME_LENGTH
+ call AddNTimes
+ ld de, wPlayerName
+ ld b, NAME_LENGTH_JP
+.loop
+ dec b
+ jr z, .isPlayerPikachu
+ ld a, [de]
+ inc de
+ cp [hl]
+ inc hl
+ jr z, .loop
+.notPlayerPikachu
+ and a
+ ret
+
+.isPlayerPikachu
+ scf
+ ret
+
+UpdatePikachuMoodAfterBattle::
+; because d is always $82 at this function, it serves to
+; ensure Pikachu's mood is at least 130 after battle
+ push de
+ call IsStarterPikachuAliveInOurParty
+ pop de
+ ret nc
+ ld a, d
+ cp 128
+ ld a, [wPikachuMood]
+ jr c, .d_less_than_128 ; we never jump
+ cp d
+ jr c, .load_d_into_mood
+ ret
+
+.d_less_than_128
+ cp d
+ ret c
+.load_d_into_mood
+ ld a, d
+ ld [wPikachuMood], a
+ ret
+
+CheckPikachuStatusCondition::
+; set carry flag if Starter Pikachu has a status condition
+; also return d = 0 if fainted, but no function uses it
+ xor a
+ ld [wWhichPokemon], a
+ ld hl, wPartyCount
+.loop
+ inc hl
+ ld a, [hl]
+ cp $ff
+ jr z, .noAilment
+ push hl
+ call IsThisPartyMonStarterPikachu
+ pop hl
+ jr nc, .next
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMon1HP
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+ ld a, [hli]
+ or [hl]
+ ld d, a
+ inc hl
+ inc hl
+ ld a, [hl] ; status
+ and a
+ jr nz, .hasAilment
+ jr .noAilment
+
+.next
+ ld a, [wWhichPokemon]
+ inc a
+ ld [wWhichPokemon], a
+ jr .loop
+
+.hasAilment
+ scf
+ ret
+
+.noAilment
+ and a
+ ret
+
+IsSurfingStarterPikachuInParty::
+ ld hl, wPartySpecies
+ ld de, wPartyMon1Moves
+ ld bc, wPartyMonOT
+ push hl
+.loop
+ pop hl
+ ld a, [hli]
+ push hl
+ inc a
+ jr z, .noSurfingPlayerPikachu
+ cp STARTER_PIKACHU + 1
+ jr nz, .curMonNotSurfingPlayerPikachu
+ ld h, d
+ ld l, e
+ push hl
+ push bc
+ ld b, NUM_MOVES
+.moveSearchLoop
+ ld a, [hli]
+ cp SURF
+ jr z, .foundSurfingPikachu
+ dec b
+ jr nz, .moveSearchLoop
+ pop bc
+ pop hl
+ jr .curMonNotSurfingPlayerPikachu
+
+.foundSurfingPikachu
+ pop bc
+ pop hl
+ inc hl
+ inc hl
+ inc hl
+ inc hl
+ ld a, [wPlayerID]
+ cp [hl]
+ jr nz, .curMonNotSurfingPlayerPikachu
+ inc hl
+ ld a, [wPlayerID+1]
+ cp [hl]
+ jr nz, .curMonNotSurfingPlayerPikachu
+ push de
+ push bc
+ ld hl, wPlayerName
+ ld d, NAME_LENGTH_JP
+.nameCompareLoop
+ dec d
+ jr z, .foundSurfingPlayerPikachu
+ ld a, [bc]
+ inc bc
+ cp [hl]
+ inc hl
+ jr z, .nameCompareLoop
+ pop bc
+ pop de
+.curMonNotSurfingPlayerPikachu
+ ld hl, wPartyMon2 - wPartyMon1
+ add hl, de
+ ld d, h
+ ld e, l
+ ld hl, NAME_LENGTH
+ add hl, bc
+ ld b, h
+ ld c, l
+ jr .loop
+
+.foundSurfingPlayerPikachu
+ pop bc
+ pop de
+ pop hl
+ scf
+ ret
+
+.noSurfingPlayerPikachu
+ pop hl
+ and a
+ ret
diff --git a/engine/pikachu/respawn_overworld_pikachu.asm b/engine/pikachu/respawn_overworld_pikachu.asm
new file mode 100644
index 00000000..e412df5d
--- /dev/null
+++ b/engine/pikachu/respawn_overworld_pikachu.asm
@@ -0,0 +1,6 @@
+RespawnOverworldPikachu:
+ callfar IsThisPartyMonStarterPikachu
+ ret nc
+ ld a, $3
+ ld [wPikachuSpawnState], a
+ ret
diff --git a/engine/play_time.asm b/engine/play_time.asm
deleted file mode 100644
index 9b4491de..00000000
--- a/engine/play_time.asm
+++ /dev/null
@@ -1,61 +0,0 @@
-TrackPlayTime::
- call CountDownIgnoreInputBitReset
- ld a, [wStatusFlags6]
- bit BIT_GAME_TIMER_COUNTING, a
- ret z
- ld a, [wPlayTimeMaxed]
- and a
- ret nz
- ld a, [wPlayTimeFrames]
- inc a
- ld [wPlayTimeFrames], a
- cp 60
- ret nz
- xor a
- ld [wPlayTimeFrames], a
- ld a, [wPlayTimeSeconds]
- inc a
- ld [wPlayTimeSeconds], a
- cp 60
- ret nz
- xor a
- ld [wPlayTimeSeconds], a
- ld a, [wPlayTimeMinutes]
- inc a
- ld [wPlayTimeMinutes], a
- cp 60
- ret nz
- xor a
- ld [wPlayTimeMinutes], a
- ld a, [wPlayTimeHours]
- inc a
- ld [wPlayTimeHours], a
- cp $ff
- ret nz
- ld a, $ff
- ld [wPlayTimeMaxed], a
- ret
-
-CountDownIgnoreInputBitReset:
- ld a, [wIgnoreInputCounter]
- and a
- jr nz, .decrement
- ld a, $ff
- jr .continue
-.decrement
- dec a
-.continue
- ld [wIgnoreInputCounter], a
- and a
- ret nz
- ld a, [wStatusFlags5]
- res BIT_UNKNOWN_5_1, a
- res BIT_UNKNOWN_5_2, a
- bit BIT_DISABLE_JOYPAD, a
- res BIT_DISABLE_JOYPAD, a
- ld [wStatusFlags5], a
- ret z
- xor a
- ldh [hJoyPressed], a
- ldh [hJoyHeld], a
- ret
diff --git a/engine/pokemon/add_mon.asm b/engine/pokemon/add_mon.asm
index c92acfcb..24d360b2 100644
--- a/engine/pokemon/add_mon.asm
+++ b/engine/pokemon/add_mon.asm
@@ -170,6 +170,12 @@ _AddPartyMon::
inc de
ld a, [hli] ; catch rate (held item in gen 2)
ld [de], a
+ ld a, [wCurPartySpecies]
+ cp KADABRA
+ jr nz, .notKadabra
+ ld a, TWISTEDSPOON_GSC
+ ld [de], a
+.notKadabra
ld hl, wMonHMoves
ld a, [hli]
inc de
diff --git a/engine/pokemon/bills_pc.asm b/engine/pokemon/bills_pc.asm
index 09adfa37..c8f24560 100644
--- a/engine/pokemon/bills_pc.asm
+++ b/engine/pokemon/bills_pc.asm
@@ -11,18 +11,15 @@ DisplayPCMainMenu::
and a
jr nz, .leaguePCAvailable
hlcoord 0, 0
- ld b, 8
- ld c, 14
+ lb bc, 8, 14
jr .next
.noOaksPC
hlcoord 0, 0
- ld b, 6
- ld c, 14
+ lb bc, 6, 14
jr .next
.leaguePCAvailable
hlcoord 0, 0
- ld b, 10
- ld c, 14
+ lb bc, 10, 14
.next
call TextBoxBorder
call UpdateSprites
@@ -119,10 +116,13 @@ BillsPCMenu:
lb bc, BANK(PokeballTileGraphics), 1
call CopyVideoData
call LoadScreenTilesFromBuffer2DisableBGTransfer
+ hlcoord 0, 12
+ lb bc, 4, 18
+ call TextBoxBorder
hlcoord 0, 0
- ld b, 10
- ld c, 12
+ lb bc, 12, 12
call TextBoxBorder
+ call UpdateSprites
hlcoord 2, 2
ld de, BillsPCMenuText
call PlaceString
@@ -133,7 +133,7 @@ BillsPCMenu:
ld [hli], a ; wTopMenuItemX
inc hl
inc hl
- ld a, 4
+ ld a, 5
ld [hli], a ; wMaxMenuItem
ld a, PAD_A | PAD_B
ld [hli], a ; wMenuWatchedKeys
@@ -144,11 +144,8 @@ BillsPCMenu:
ld [hli], a ; wListScrollOffset
ld [hl], a ; wMenuWatchMovingOutOfBounds
ld [wPlayerMonNumber], a
- ld hl, WhatText
- call PrintText
hlcoord 9, 14
- ld b, 2
- ld c, 9
+ lb bc, 2, 9
call TextBoxBorder
ld a, [wCurrentBoxNum]
and BOX_NUM_MASK
@@ -184,6 +181,8 @@ BillsPCMenu:
jp z, BillsPCRelease ; release
cp $3
jp z, BillsPCChangeBox ; change box
+ cp $4
+ jp z, BillsPCPrintBox
ExitBillsPC:
ld a, [wMiscFlags]
@@ -204,6 +203,10 @@ ExitBillsPC:
res BIT_NO_TEXT_DELAY, [hl]
ret
+BillsPCPrintBox:
+ callfar PrintPCBox
+ jp BillsPCMenu
+
BillsPCDeposit:
ld a, [wPartyCount]
dec a
@@ -222,11 +225,26 @@ BillsPCDeposit:
ld hl, wPartyCount
call DisplayMonListMenu
jp c, BillsPCMenu
+ callfar IsThisPartyMonStarterPikachu
+ jr nc, .asm_215ad
+ call CheckPikachuFollowingPlayer
+ jr z, .asm_215ad
+ ld hl, SleepingPikachuText2
+ call PrintText
+ jp BillsPCMenu
+.asm_215ad
call DisplayDepositWithdrawMenu
jp nc, BillsPCMenu
+ callfar IsThisPartyMonStarterPikachu
+ jr nc, .asm_215c9
+ ldpikacry e, PikachuCry28
+ callfar PlayPikachuSoundClip
+ jr .asm_215cf
+.asm_215c9
ld a, [wCurPartySpecies]
- call GetCryData
- call PlaySoundWaitForCurrent
+ call PlayCry
+.asm_215cf
+ farcall_ModifyPikachuHappiness PIKAHAPPY_DEPOSITED
ld a, PARTY_TO_BOX
ld [wMoveMonType], a
call MoveMon
@@ -253,6 +271,10 @@ BillsPCDeposit:
call PrintText
jp BillsPCMenu
+SleepingPikachuText2:
+ text_far _SleepingPikachuText2
+ text_end
+
BillsPCWithdraw:
ld a, [wBoxCount]
and a
@@ -276,9 +298,15 @@ BillsPCWithdraw:
ld a, [wWhichPokemon]
ld hl, wBoxMonNicks
call GetPartyMonName
+ callfar IsThisBoxMonStarterPikachu
+ jr nc, .asm_21660
+ ldpikacry e, PikachuCry35
+ callfar PlayPikachuSoundClip
+ jr .asm_21666
+.asm_21660
ld a, [wCurPartySpecies]
- call GetCryData
- call PlaySoundWaitForCurrent
+ call PlayCry
+.asm_21666
xor a ; BOX_TO_PARTY
ld [wMoveMonType], a
call MoveMon
@@ -301,6 +329,8 @@ BillsPCRelease:
ld hl, wBoxCount
call DisplayMonListMenu
jp c, BillsPCMenu
+ callfar IsThisBoxMonStarterPikachu
+ jr c, .asm_216cb
ld hl, OnceReleasedText
call PrintText
call YesNoChoice
@@ -317,6 +347,16 @@ BillsPCRelease:
call PrintText
jp BillsPCMenu
+.asm_216cb
+ ld a, [wWhichPokemon]
+ ld hl, wBoxMonNicks
+ call GetPartyMonName
+ ldpikacry e, PikachuCry40
+ callfar PlayPikachuSoundClip
+ ld hl, PikachuUnhappyText
+ call PrintText
+ jp BillsPCMenu
+
BillsPCChangeBox:
farcall ChangeBox
jp BillsPCMenu
@@ -343,6 +383,7 @@ BillsPCMenuText:
next "DEPOSIT <PKMN>"
next "RELEASE <PKMN>"
next "CHANGE BOX"
+ next "PRINT BOX"
next "SEE YA!"
db "@"
@@ -381,8 +422,7 @@ INCLUDE "data/moves/hm_moves.asm"
DisplayDepositWithdrawMenu:
hlcoord 9, 10
- ld b, 6
- ld c, 9
+ lb bc, 6, 9
call TextBoxBorder
ld a, [wParentMenuItem]
and a ; was the Deposit or Withdraw item selected in the parent menu?
@@ -488,6 +528,10 @@ CantTakeMonText:
text_far _CantTakeMonText
text_end
+PikachuUnhappyText:
+ text_far _PikachuUnhappyText
+ text_end
+
ReleaseWhichMonText:
text_far _ReleaseWhichMonText
text_end
diff --git a/engine/pokemon/evos_moves.asm b/engine/pokemon/evos_moves.asm
index 794cb164..f4d5039a 100644
--- a/engine/pokemon/evos_moves.asm
+++ b/engine/pokemon/evos_moves.asm
@@ -9,7 +9,7 @@ TryEvolvingMon:
call Evolution_FlagAction
; this is only called after battle
-; it is supposed to do level up evolutions, though there is a bug that allows item evolutions to occur
+; it does level up evolutions, though there was a bug in red/blue that allows item evolutions to occur which is patched here
EvolutionAfterBattle:
ldh a, [hTileAnimations]
push af
@@ -93,9 +93,11 @@ Evolution_PartyMonLoop: ; loop over party mons
jp c, Evolution_PartyMonLoop ; if so, go the next mon
jr .doEvolution
.checkItemEvo
+ ld a, [wIsInBattle] ; are we in battle?
+ and a
ld a, [hli]
- ; Bug: Wild encounters can cause stone evolutions without
- ; having any stones available. This was fixed in Yellow.
+ jp nz, .nextEvoEntry1 ; don't evolve if we're in a battle as wCurPartySpecies could be holding the last mon sent out
+
ld b, a ; evolution item
ld a, [wCurItem] ; same as [wCurPartySpecies]
cp b ; was the evolution item in this entry used?
@@ -142,7 +144,7 @@ Evolution_PartyMonLoop: ; loop over party mons
ld [wEvoNewSpecies], a
ld a, MONSTER_NAME
ld [wNameListType], a
- ld a, BANK(TrainerNames) ; bank is not used for monster names
+ ld a, BANK(MonsterNames) ; bank is not used for monster names
ld [wPredefBank], a
call GetName
push hl
@@ -321,23 +323,9 @@ Evolution_ReloadTilesetTilePatterns:
jp ReloadTilesetTilePatterns
LearnMoveFromLevelUp:
- ld hl, EvosMovesPointerTable
ld a, [wPokedexNum] ; species
ld [wCurPartySpecies], a
- dec a
- ld bc, 0
- ld hl, EvosMovesPointerTable
- add a
- rl b
- ld c, a
- add hl, bc
- ld a, [hli]
- ld h, [hl]
- ld l, a
-.skipEvolutionDataLoop ; loop to skip past the evolution data, which comes before the move data
- ld a, [hli]
- and a ; have we reached the end of the evolution data?
- jr nz, .skipEvolutionDataLoop ; if not, jump back up
+ call GetMonLearnset
.learnSetLoop ; loop over the learn set until we reach a move that is learnt at the current level or the end of the list
ld a, [hli]
and a ; have we reached the end of the learn set?
@@ -373,33 +361,146 @@ LearnMoveFromLevelUp:
call GetMoveName
call CopyToStringBuffer
predef LearnMove
+ ld a, b
+ and a
+ jr z, .done
+ callfar IsThisPartyMonStarterPikachu
+ jr nc, .done
+ ld a, [wMoveNum]
+ cp THUNDERBOLT
+ jr z, .foundThunderOrThunderbolt
+ cp THUNDER
+ jr nz, .done
+.foundThunderOrThunderbolt
+ ld a, $5
+ ld [wd49b], a
+ ld a, $85
+ ld [wPikachuMood], a
.done
ld a, [wCurPartySpecies]
ld [wPokedexNum], a
ret
-; writes the moves a mon has at level [wCurEnemyLevel] to [de]
-; move slots are being filled up sequentially and shifted if all slots are full
-WriteMonMoves:
- call GetPredefRegisters
- push hl
- push de
- push bc
- ld hl, EvosMovesPointerTable
- ld b, 0
+Func_3b079:
ld a, [wCurPartySpecies]
- dec a
- add a
- rl b
- ld c, a
+ push af
+ call Func_3b0a2
+ jr c, .asm_3b09c
+
+ call Func_3b10f
+ jr nc, .asm_3b096
+
+ call Func_3b0a2
+ jr c, .asm_3b09c
+
+ call Func_3b10f
+ jr nc, .asm_3b096
+
+ call Func_3b0a2
+ jr c, .asm_3b09c
+.asm_3b096
+ pop af
+ ld [wCurPartySpecies], a
+ and a
+ ret
+.asm_3b09c
+ pop af
+ ld [wCurPartySpecies], a
+ scf
+ ret
+
+Func_3b0a2:
+ ld a, [wTempTMHM]
+ ld [wMoveNum], a
+ predef CanLearnTM
+ ld a, c
+ and a
+ jr nz, .asm_3b0ec
+ ld hl, Pointer_3b0ee
+ ld a, [wCurPartySpecies]
+ ld de, $1
+ call IsInArray
+ jr c, .asm_3b0d2
+ ld a, $ff
+ ld [wMonHGrowthRate], a
+ ld a, [wTempTMHM]
+ ld hl, wMonHMoves
+ ld de, $1
+ call IsInArray
+ jr c, .asm_3b0ec
+.asm_3b0d2
+ ld a, [wTempTMHM]
+ ld d, a
+ call GetMonLearnset
+.loop
+ ld a, [hli]
+ and a
+ jr z, .asm_3b0ea
+ ld b, a
+ ld a, [wCurEnemyLevel]
+ cp b
+ jr c, .asm_3b0ea
+ ld a, [hli]
+ cp d
+ jr z, .asm_3b0ec
+ jr .loop
+.asm_3b0ea
+ and a
+ ret
+.asm_3b0ec
+ scf
+ ret
+
+INCLUDE "data/pokemon/unknown_list.asm"
+
+Func_3b10f:
+ ld c, $0
+.asm_3b111
+ ld hl, EvosMovesPointerTable
+ ld b, $0
+ add hl, bc
add hl, bc
ld a, [hli]
ld h, [hl]
ld l, a
-.skipEvoEntriesLoop
+.asm_3b11b
ld a, [hli]
and a
- jr nz, .skipEvoEntriesLoop
+ jr z, .asm_3b130
+ cp $2
+ jr nz, .asm_3b124
+ inc hl
+.asm_3b124
+ inc hl
+ ld a, [wCurPartySpecies]
+ cp [hl]
+ jr z, .asm_3b138
+ inc hl
+ ld a, [hl]
+ and a
+ jr nz, .asm_3b11b
+.asm_3b130
+ inc c
+ ld a, c
+ cp VICTREEBEL
+ jr c, .asm_3b111
+ and a
+ ret
+.asm_3b138
+ inc c
+ ld a, c
+ ld [wCurPartySpecies], a
+ scf
+ ret
+
+; writes the moves a mon has at level [wCurEnemyLevel] to [de]
+; move slots are being filled up sequentially and shifted if all slots are full
+WriteMonMoves:
+ call GetPredefRegisters
+ push hl
+ push de
+ push bc
+ call GetMonLearnset
jr .firstMove
.nextMove
pop de
@@ -513,4 +614,21 @@ WriteMonMoves_ShiftMoveData:
Evolution_FlagAction:
predef_jump FlagActionPredef
+GetMonLearnset:
+ ld hl, EvosMovesPointerTable
+ ld b, 0
+ ld a, [wCurPartySpecies]
+ dec a
+ ld c, a
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+.skipEvolutionDataLoop ; loop to skip past the evolution data, which comes before the move data
+ ld a, [hli]
+ and a ; have we reached the end of the evolution data?
+ jr nz, .skipEvolutionDataLoop ; if not, jump back up
+ ret
+
INCLUDE "data/pokemon/evos_moves.asm"
diff --git a/engine/pokemon/learn_move.asm b/engine/pokemon/learn_move.asm
index b57fedcd..7843cc59 100644
--- a/engine/pokemon/learn_move.asm
+++ b/engine/pokemon/learn_move.asm
@@ -121,8 +121,7 @@ TryingToLearn:
ld hl, WhichMoveToForgetText
call PrintText
hlcoord 4, 7
- ld b, 4
- ld c, 14
+ lb bc, 4, 14
call TextBoxBorder
hlcoord 6, 8
ld de, wMovesString
@@ -206,11 +205,36 @@ TryingToLearnText:
text_end
OneTwoAndText:
+; bugfix: In Red/Blue, the SFX_SWAP sound was played in the wrong bank, which played an incorrect sound
+; Yellow has fixed this by swapping to the correct bank
text_far _OneTwoAndText
text_pause
text_asm
+ push af
+ push bc
+ push de
+ push hl
+ ld a, $1
+ ld [wMuteAudioAndPauseMusic], a
+ call DelayFrame
+ ld a, [wAudioROMBank]
+ push af
+ ld a, BANK(SFX_Swap_1)
+ ld [wAudioROMBank], a
+ ld [wAudioSavedROMBank], a
+ call WaitForSoundToFinish
ld a, SFX_SWAP
- call PlaySoundWaitForCurrent
+ call PlaySound
+ call WaitForSoundToFinish
+ pop af
+ ld [wAudioROMBank], a
+ ld [wAudioSavedROMBank], a
+ xor a
+ ld [wMuteAudioAndPauseMusic], a
+ pop hl
+ pop de
+ pop bc
+ pop af
ld hl, PoofText
ret
diff --git a/engine/pokemon/load_mon_data.asm b/engine/pokemon/load_mon_data.asm
index 87a2be8b..e46dc2db 100644
--- a/engine/pokemon/load_mon_data.asm
+++ b/engine/pokemon/load_mon_data.asm
@@ -15,7 +15,7 @@ LoadMonData_::
ld a, [wWhichPokemon]
ld e, a
- callfar GetMonSpecies
+ call GetMonSpecies
.GetMonHeader
ld a, [wCurPartySpecies]
@@ -47,3 +47,22 @@ LoadMonData_::
ld de, wLoadedMon
ld bc, PARTYMON_STRUCT_LENGTH
jp CopyData
+
+; get species of mon e in list [wMonDataLocation] for LoadMonData
+GetMonSpecies:
+ ld hl, wPartySpecies
+ ld a, [wMonDataLocation]
+ and a
+ jr z, .getSpecies
+ dec a
+ jr z, .enemyParty
+ ld hl, wBoxSpecies
+ jr .getSpecies
+.enemyParty
+ ld hl, wEnemyPartySpecies
+.getSpecies
+ ld d, 0
+ add hl, de
+ ld a, [hl]
+ ld [wCurPartySpecies], a
+ ret
diff --git a/engine/pokemon/status_screen.asm b/engine/pokemon/status_screen.asm
index 84a56d5a..7e8ad615 100644
--- a/engine/pokemon/status_screen.asm
+++ b/engine/pokemon/status_screen.asm
@@ -168,8 +168,25 @@ StatusScreen:
call GBPalNormal
hlcoord 1, 0
call LoadFlippedFrontSpriteByMonIndex ; draw Pokémon picture
+ ld a, [wMonDataLocation]
+ cp ENEMY_PARTY_DATA
+ jr z, .playRegularCry
+ cp BOX_DATA
+ jr z, .checkBoxData
+ callfar IsThisPartyMonStarterPikachu
+ jr nc, .playRegularCry
+ jr .playPikachuSoundClip
+.checkBoxData
+ callfar IsThisBoxMonStarterPikachu
+ jr nc, .playRegularCry
+.playPikachuSoundClip
+ ldpikacry e, PikachuCry17
+ callfar PlayPikachuSoundClip
+ jr .continue
+.playRegularCry
ld a, [wCurPartySpecies]
call PlayCry
+.continue
call WaitForTextScrollButtonPress
pop af
ldh [hTileAnimations], a
@@ -241,16 +258,14 @@ PrintStatsBox:
and a
jr nz, .LevelUpStatsBox ; battle or Rare Candy
hlcoord 0, 8
- ld b, 8
- ld c, 8
+ lb bc, 8, 8
call TextBoxBorder
hlcoord 1, 9
ld bc, SCREEN_WIDTH + 5 ; one row down and 5 columns right
jr .PrintStats
.LevelUpStatsBox
hlcoord 9, 2
- ld b, 8
- ld c, 9
+ lb bc, 8, 9
call TextBoxBorder
hlcoord 11, 3
ld bc, SCREEN_WIDTH + 4 ; one row down and 4 columns right
@@ -306,8 +321,7 @@ StatusScreen2:
hlcoord 19, 3
ld [hl], $78
hlcoord 0, 8
- ld b, 8
- ld c, 18
+ lb bc, 8, 18
call TextBoxBorder ; Draw move container
hlcoord 2, 9
ld de, wMovesString
diff --git a/engine/printer/printer.asm b/engine/printer/printer.asm
new file mode 100644
index 00000000..fa3a5afa
--- /dev/null
+++ b/engine/printer/printer.asm
@@ -0,0 +1,979 @@
+PrintPokedexEntry:
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ xor a
+ ld [wUpdateSpritesEnabled], a
+ ldh [hCanceledPrinting], a
+ call Printer_PlayPrinterMusic
+ ldh a, [rIE]
+ push af
+ xor a
+ ldh [rIF], a
+ ld a, $9
+ ldh [rIE], a
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call Printer_GetDexEntryRegisters
+ call Printer_StartTransmission
+ ld a, [wPrinterPokedexMonIsOwned]
+ and a
+ jr z, .not_caught
+ ld a, 16
+ jr .got_size
+
+.not_caught
+ ld a, 19
+.got_size
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call ClearScreen
+ callfar Pokedex_DrawInterface
+ callfar Pokedex_PlacePokemonList
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call .TryPrintPage
+ jr c, .finish_printing
+ ld a, [wPrinterPokedexMonIsOwned]
+ and a
+ jr z, .finish_printing
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ ld c, $c
+ call DelayFrames
+ call SaveScreenTilesToBuffer1
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call Printer_PrepareDexEntryForPrinting
+ ld a, $7
+ call Printer_StartTransmission
+ ld a, $3
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call .TryPrintPage
+.finish_printing
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ xor a
+ ldh [rIF], a
+ pop af
+ ldh [rIE], a
+ call ReloadMapAfterPrinter
+ call Printer_PlayMapMusic
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ ret
+
+.TryPrintPage:
+ call Printer_ResetJoypadHRAM
+.print_loop
+ call JoypadLowSensitivity
+ call Printer_StopIfPressB
+ jr c, .pressed_b
+ ld a, [wPrinterSendState]
+ bit 7, a
+ jr nz, .completed
+ call PrinterTransmissionJumptable
+ call GBPrinter_CheckForErrors
+ call GBPrinter_UpdateStatusMessage
+ call DelayFrame
+ jr .print_loop
+
+.completed
+ and a
+ ret
+
+.pressed_b
+ scf
+ ret
+
+Printer_GetDexEntryRegisters:
+ callfar DrawDexEntryOnScreen
+ ld a, l
+ ld [wPrinterPokedexEntryTextPointer], a
+ ld a, h
+ ld [wPrinterPokedexEntryTextPointer + 1], a
+ ld a, $0
+ rla ; copy carry flag state to bit 0
+ ld [wPrinterPokedexMonIsOwned], a
+ and a
+ jr z, .not_caught
+ ld a, $5
+ jr .got_num_rows
+
+.not_caught
+ ld a, $9
+.got_num_rows
+ ret
+
+Printer_PrepareDexEntryForPrinting:
+ call ClearScreen
+ callfar Pokedex_PrepareDexEntryForPrinting
+ ret
+
+PrintSurfingMinigameHighScore::
+ xor a
+ ldh [hCanceledPrinting], a
+ call Printer_PlayPrinterMusic
+ call Printer_PrepareSurfingMinigameHighScoreTileMap
+ ldh a, [rIE]
+ push af
+ xor a
+ ldh [rIF], a
+ ld a, $9
+ ldh [rIE], a
+ call StartTransmission_Send9Rows
+ ld a, $13
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call Printer_ResetJoypadHRAM
+.loop
+ call JoypadLowSensitivity
+ call Printer_StopIfPressB
+ jr c, .quit
+ ld a, [wPrinterSendState]
+ bit 7, a
+ jr nz, .quit
+ call PrinterTransmissionJumptable
+ call GBPrinter_CheckForErrors
+ call GBPrinter_UpdateStatusMessage
+ call DelayFrame
+ jr .loop
+
+.quit
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ call Printer_CopyTileMapFromPrinterTileBuffer
+ xor a
+ ldh [rIF], a
+ pop af
+ ldh [rIE], a
+ call ReloadMapAfterPrinter
+ call Printer_PlayMapMusic
+ ret
+
+PrintDiploma::
+ xor a
+ ldh [hCanceledPrinting], a
+ call Printer_PlayPrinterMusic
+ call DisplayDiplomaTop
+ ldh a, [rIE]
+ push af
+ xor a
+ ldh [rIF], a
+ ld a, $9
+ ldh [rIE], a
+ call StartTransmission_Send9Rows
+ ld a, $10
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call PrintDiplomaPage
+ jr c, .quit
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ ld c, $c
+ call DelayFrames
+ call SaveScreenTilesToBuffer1
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call DisplayDiplomaBottom
+ call StartTransmission_Send9Rows
+ ld a, $3
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ call PrintDiplomaPage
+.quit
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ call Printer_CopyTileMapFromPrinterTileBuffer
+ xor a
+ ldh [rIF], a
+ pop af
+ ldh [rIE], a
+ call ReloadMapAfterPrinter
+ call Printer_PlayMapMusic
+ ret
+
+PrintDiplomaPage:
+ call Printer_ResetJoypadHRAM
+.print_loop
+ call JoypadLowSensitivity
+ call Printer_StopIfPressB
+ jr c, .pressed_b
+ ld a, [wPrinterSendState]
+ bit 7, a
+ jr nz, .completed
+ call PrinterTransmissionJumptable
+ call GBPrinter_CheckForErrors
+ call GBPrinter_UpdateStatusMessage
+ call DelayFrame
+ jr .print_loop
+
+.completed
+ and a
+ ret
+
+.pressed_b
+ scf
+ ret
+
+PrintPCBox::
+ ld a, [wBoxCount]
+ and a
+ jp z, .emptyBox
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ xor a
+ ld [wUpdateSpritesEnabled], a
+ ldh [hCanceledPrinting], a
+ call Printer_PlayPrinterMusic
+ ldh a, [rIE]
+ push af
+ xor a
+ ldh [rIF], a
+ ld a, $9
+ ldh [rIE], a
+ call SaveScreenTilesToBuffer1
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call PrintPCBox_DrawPage1
+ call StartTransmission_Send9Rows
+ ld a, $10
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ call PrintPCBoxPage
+ jr c, .quit
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ ld c, 12
+ call DelayFrames
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call PrintPCBox_DrawPage2
+ call StartTransmission_Send9Rows
+ ld a, $0
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ call PrintPCBoxPage
+ jr c, .quit
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ ld c, 12
+ call DelayFrames
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call PrintPCBox_DrawPage3
+ call StartTransmission_Send9Rows
+ ld a, $0
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ call PrintPCBoxPage
+ jr c, .quit
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ ld c, 12
+ call DelayFrames
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call PrintPCBox_DrawPage4
+ call StartTransmission_Send9Rows
+ ld a, $3
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ call PrintPCBoxPage
+.quit
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ xor a
+ ldh [rIF], a
+ pop af
+ ldh [rIE], a
+ call ReloadMapAfterPrinter
+ call Printer_PlayMapMusic
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ ret
+
+.emptyBox
+ ld hl, NoPokemonText
+ call PrintText
+ ret
+
+PrintPCBoxPage:
+ call Printer_ResetJoypadHRAM
+.print_loop
+ call JoypadLowSensitivity
+ call Printer_StopIfPressB
+ jr c, .pressed_b
+ ld a, [wPrinterSendState]
+ bit 7, a
+ jr nz, .completed
+ call PrinterTransmissionJumptable
+ call GBPrinter_CheckForErrors
+ call GBPrinter_UpdateStatusMessage
+ call DelayFrame
+ jr .print_loop
+
+.completed
+ and a
+ ret
+
+.pressed_b
+ scf
+ ret
+
+NoPokemonText:
+ text_far _NoPokemonText
+ text_end
+
+PrintFanClubPortrait::
+ xor a
+ ldh [hCanceledPrinting], a
+ call Printer_PlayPrinterMusic
+ call Printer_GetMonStats
+ ldh a, [rIE]
+ push af
+ xor a
+ ldh [rIF], a
+ ld a, $9
+ ldh [rIE], a
+ call StartTransmission_Send9Rows
+ ld a, $13
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call Printer_ResetJoypadHRAM
+.print_loop
+ call JoypadLowSensitivity
+ call Printer_StopIfPressB
+ jr c, .quit
+ ld a, [wPrinterSendState]
+ bit 7, a
+ jr nz, .quit
+ call PrinterTransmissionJumptable
+ call GBPrinter_CheckForErrors
+ call GBPrinter_UpdateStatusMessage
+ call DelayFrame
+ jr .print_loop
+
+.quit
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ call Printer_CopyTileMapFromPrinterTileBuffer
+ xor a
+ ldh [rIF], a
+ pop af
+ ldh [rIE], a
+ call ReloadMapAfterPrinter
+ call Printer_PlayMapMusic
+ ret
+
+PrinterDebug:
+ push af
+ push bc
+ push de
+ push hl
+ call StopAllMusic
+ ldh a, [rIE]
+ push af
+ xor a
+ ldh [rIF], a
+ ld a, $9
+ ldh [rIE], a
+ call StartTransmission_Send9Rows
+ ld a, $13
+ ld [wcae2], a
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call PrinterDebug_LoadGFX
+.loop
+ ld a, [wPrinterSendState]
+ bit 7, a
+ jr nz, .quit
+ call PrinterDebug_DoFunction
+ call PrinterDebug_ConvertStatusFlagsToTiles
+ call DelayFrame
+ jr .loop
+
+.quit
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ ld hl, wShadowOAMSprite32
+ ld bc, 8 * 4
+ xor a
+ call FillMemory
+ xor a
+ ldh [rIF], a
+ pop af
+ ldh [rIE], a
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ret
+
+Printer_StopIfPressB:
+ ldh a, [hJoyHeld]
+ and PAD_B
+ jr nz, .quit
+ and a
+ ret
+
+.quit
+ ld a, [wPrinterSendState]
+ cp $c
+ jr nz, .already_done
+.wait_current_task
+ ld a, [wPrinterOpcode]
+ and a
+ jr nz, .wait_current_task
+ ld a, $16
+ ld [wPrinterOpcode], a
+ ld a, $88
+ ldh [rSB], a
+ ld a, $1
+ ldh [rSC], a
+ ld a, $81
+ ldh [rSC], a
+.wait_send_cancel
+ ld a, [wPrinterOpcode]
+ and a
+ jr nz, .wait_send_cancel
+.already_done
+ ld a, $1
+ ldh [hCanceledPrinting], a
+ scf
+ ret
+
+Printer_CopyTileMapToPrinterTileBuffer:
+ hlcoord 0, 0
+ decoord 0, 0, wPrinterTileBuffer
+ ld bc, SCREEN_AREA
+ call CopyData
+ ret
+
+Printer_CopyTileMapFromPrinterTileBuffer:
+ hlcoord 0, 0, wPrinterTileBuffer
+ decoord 0, 0
+ ld bc, SCREEN_AREA
+ call CopyData
+ ret
+
+Printer_ResetJoypadHRAM:
+ xor a
+ ldh [hJoyLast], a
+ ldh [hJoyReleased], a
+ ldh [hJoyPressed], a
+ ldh [hJoyHeld], a
+ ldh [hJoy5], a
+ ldh [hJoy6], a
+ ret
+
+Printer_PlayPrinterMusic:
+ call Printer_FadeOutMusicAndWait
+ ld a, [wAudioROMBank]
+ ld [wAudioSavedROMBank], a
+ ld a, BANK(Music_GBPrinter)
+ ld [wAudioROMBank], a
+ ld a, MUSIC_GB_PRINTER
+ ld [wNewSoundID], a
+ call PlaySound
+ ret
+
+Printer_PlayMapMusic:
+ call Printer_FadeOutMusicAndWait
+ call PlayDefaultMusic
+ ret
+
+Printer_FadeOutMusicAndWait:
+ ld a, $4
+ ld [wAudioFadeOutControl], a
+ call StopAllMusic
+.wait_music_stop
+ ld a, [wAudioFadeOutControl]
+ and a
+ jr nz, .wait_music_stop
+ ret
+
+GBPrinter_CheckForErrors:
+ ld a, [wPrinterHandshake]
+ cp $81
+ jr z, .check_other_errors
+ ld a, [wPrinterStatusFlags]
+ cp $ff
+ jr z, .error2
+ xor a
+ jr .load_status
+
+.check_other_errors
+ ld a, [wPrinterStatusFlags]
+ and %11100000
+ ret z
+ bit 7, a
+ jr nz, .error1
+ bit 6, a
+ jr nz, .error4
+ ; error 3
+ ld a, PRINTER_ERROR_3
+ jr .load_status
+
+.error4
+ ld a, PRINTER_ERROR_4
+ jr .load_status
+
+.error1
+ ld a, PRINTER_ERROR_1
+ jr .load_status
+
+.error2
+ ld a, PRINTER_ERROR_2
+.load_status
+ ld [wPrinterStatusIndicator], a
+ ret
+
+GBPrinter_UpdateStatusMessage:
+ ld a, [wPrinterStatusIndicator]
+ and a
+ ret z
+ push af
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ hlcoord 0, 5
+ lb bc, 10, 18
+ call TextBoxBorder
+ pop af
+ ld e, a
+ ld d, $0
+ ld hl, .PrinterStatusMessages
+ add hl, de
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ hlcoord 1, 7
+ call PlaceString
+ hlcoord 2, 15
+ ld de, .PressBToCancel
+ call PlaceString
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ xor a
+ ld [wPrinterStatusIndicator], a
+ ret
+
+.PressBToCancel:
+ db "Press B to Cancel@"
+
+.PrinterStatusMessages:
+ dw .Blank
+ dw .CheckingLink
+ dw .Transmitting
+ dw .Printing
+ dw .Error1
+ dw .Error2
+ dw .Error3
+ dw .Error4
+ dw .WrongDevice
+
+.Blank:
+ db "@"
+.CheckingLink:
+ db ""
+ next " CHECKING LINK...@"
+.Transmitting:
+ db ""
+ next " TRANSMITTING...@"
+.Printing:
+ db ""
+ next " PRINTING...@"
+.Error1:
+ db " Printer Error 1"
+ next ""
+ next "Check the Game Boy"
+ next "Printer Manual.@"
+.Error2:
+ db " Printer Error 2"
+ next ""
+ next "Check the Game Boy"
+ next "Printer Manual.@"
+.Error3:
+ db " Printer Error 3"
+ next ""
+ next "Check the Game Boy"
+ next "Printer Manual.@"
+.Error4:
+ db " Printer Error 4"
+ next ""
+ next "Check the Game Boy"
+ next "Printer Manual.@"
+.WrongDevice:
+ db "This is not the"
+ next "Game Boy Printer!@"
+
+Printer_PrepareSurfingMinigameHighScoreTileMap::
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ ld de, SurfingPikachu2Graphics
+ ld hl, vChars2
+ lb bc, BANK(SurfingPikachu2Graphics), (SurfingPikachu2GraphicsEnd - SurfingPikachu2Graphics) / $10
+ call CopyVideoData
+ hlcoord 0, 0
+ call .PlaceRowAlternatingTiles
+ hlcoord 0, 17
+ call .PlaceRowAlternatingTiles
+ hlcoord 0, 0
+ call .PlaceColumnAlternatingTiles
+ hlcoord 19, 0
+ call .PlaceColumnAlternatingTiles
+ ld a, $4
+ hlcoord 0, 0
+ ld [hl], a
+ hlcoord 0, 17
+ ld [hl], a
+ hlcoord 19, 0
+ ld [hl], a
+ hlcoord 19, 17
+ ld [hl], a
+ ld de, .Tilemap1
+ hlcoord 10, 8
+ lb bc, 3, 8
+ call Diploma_Surfing_CopyBox
+ ld de, .Tilemap2
+ hlcoord 2, 11
+ lb bc, 6, 16
+ call Diploma_Surfing_CopyBox
+ ld de, .PikachusBeachString
+ hlcoord 3, 2
+ call PlaceString
+ ld de, .HiScoreString
+ hlcoord 9, 4
+ call PlaceString
+ ld de, .PointsString
+ hlcoord 12, 6
+ call PlaceString
+ ld de, wPlayerName
+ ld hl, wPlayerName
+ ld bc, 0
+.find_end_of_name
+ ld a, [hli]
+ inc c
+ cp '@'
+ jr nz, .find_end_of_name
+ ld a, 8
+ sub c
+ jr nc, .got_name_length
+ xor a
+.got_name_length
+ ld c, a
+ hlcoord 2, 4
+ add hl, bc
+ call PlaceString
+ call CopySurfingMinigameScore
+ ld b, SET_PAL_GENERIC
+ call RunPaletteCommand
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call Delay3
+ call GBPalNormal
+ ret
+
+.PlaceRowAlternatingTiles:
+ ld c, SCREEN_WIDTH / 2
+.row_loop
+ ld [hl], $0
+ inc hl
+ ld [hl], $1
+ inc hl
+ dec c
+ jr nz, .row_loop
+ ret
+
+.PlaceColumnAlternatingTiles:
+ ld c, SCREEN_HEIGHT / 2
+ ld de, SCREEN_WIDTH
+.col_loop
+ ld [hl], $2
+ add hl, de
+ ld [hl], $3
+ add hl, de
+ dec c
+ jr nz, .col_loop
+ ret
+
+.Tilemap1:
+INCBIN "gfx/surfing_pikachu/high_score_1.tilemap"
+
+.Tilemap2:
+INCBIN "gfx/surfing_pikachu/high_score_2.tilemap"
+
+.PikachusBeachString:
+ db "Pikachu's Beach@"
+.HiScoreString:
+ db "'s Hi-Score@"
+.PointsString:
+ db "Points@"
+
+Diploma_Surfing_CopyBox:
+.y
+ push bc
+ push hl
+.x
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .x
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .y
+ ret
+
+CopySurfingMinigameScore:
+ ld de, wSurfingMinigameHiScore + 1
+ hlcoord 7, 6
+ ld a, [de]
+ call .BCDConvertScore
+ ld a, [de]
+.BCDConvertScore:
+ ld c, a
+ swap a
+ and $f
+ add -10
+ ld [hli], a
+ ld a, c
+ and $f
+ add -10
+ ld [hli], a
+ dec de
+ ret
+
+SurfingPikachu2Graphics: INCBIN "gfx/surfing_pikachu/surfing_pikachu_2.2bpp"
+SurfingPikachu2GraphicsEnd:
+
+PrintPCBox_DrawPage1:
+ xor a
+ ld [wBoxNumString], a
+ call ClearScreen
+ call PrintPCBox_PlaceHorizontalLines
+ hlcoord 0, 0
+ ld bc, 11 * SCREEN_WIDTH
+ ld a, ' '
+ call FillMemory
+ call PrintPCBox_DrawLeftAndRightBorders
+ call PrintPCBox_DrawTopBorder
+ hlcoord 4, 4
+ ld de, .PokemonListString
+ call PlaceString
+ hlcoord 7, 6
+ ld de, .BoxString
+ call PlaceString
+ hlcoord 11, 6
+ ld a, [wCurrentBoxNum]
+ and $7f
+ cp 9
+ jr c, .less_than_9
+ sub 9
+ ld [hl], '1'
+ inc hl
+ add '0'
+ jr .placed_box_number
+
+.less_than_9
+ add '1'
+.placed_box_number
+ ld [hl], a
+ hlcoord 4, 9
+ ld de, wBoxSpecies
+ ld c, $3
+ call PrintPCBox_PlaceBoxMonInfo
+ ret
+
+.PokemonListString: db "POKéMON LIST@"
+.BoxString: db "BOX@"
+
+PrintPCBox_DrawPage2:
+ call ClearScreen
+ call PrintPCBox_PlaceHorizontalLines
+ call PrintPCBox_DrawLeftAndRightBorders
+ ld a, [wBoxDataStart]
+ cp 4
+ ret c
+ hlcoord 4, 0
+ ld de, wBoxSpecies + 3
+ ld c, 6
+ call PrintPCBox_PlaceBoxMonInfo
+ ret
+
+PrintPCBox_DrawPage3:
+ call ClearScreen
+ call PrintPCBox_PlaceHorizontalLines
+ call PrintPCBox_DrawLeftAndRightBorders
+ ld a, [wBoxDataStart]
+ cp 10
+ ret c
+ hlcoord 4, 0
+ ld de, wBoxSpecies + 9
+ ld c, 6
+ call PrintPCBox_PlaceBoxMonInfo
+ ret
+
+PrintPCBox_DrawPage4:
+ call ClearScreen
+ call PrintPCBox_PlaceHorizontalLines
+ call PrintPCBox_DrawLeftAndRightBorders
+ hlcoord 0, 15
+ call PrintPCBox_DrawBottomBorderAtHL
+ hlcoord 0, 16
+ ld bc, 2 * SCREEN_WIDTH
+ ld a, ' '
+ call FillMemory
+ ld a, [wBoxDataStart]
+ cp 16
+ ret c
+ hlcoord 4, 0
+ ld de, wBoxSpecies + 15
+ ld c, 5
+ call PrintPCBox_PlaceBoxMonInfo
+ ret
+
+PrintPCBox_PlaceBoxMonInfo:
+.loop
+ ld a, c
+ and a
+ jr z, .done
+ dec c
+ ld a, [de]
+ cp $ff
+ jr z, .done
+ ld [wPokedexNum], a
+ push bc
+ push hl
+ push de
+ push hl
+ ld bc, 12
+ ld a, ' '
+ call FillMemory
+ pop hl
+ push hl
+ ld de, SCREEN_WIDTH
+ add hl, de
+ ld bc, 12
+ ld a, ' '
+ call FillMemory
+ pop hl
+ push hl
+ call GetMonName
+ pop hl
+ call PlaceString
+ push hl
+ ld hl, wBoxMonNicks
+ ld bc, NAME_LENGTH
+ ld a, [wBoxNumString]
+ call AddNTimes
+ ld e, l
+ ld d, h
+ pop hl
+ ld bc, SCREEN_WIDTH + 1
+ add hl, bc
+ ld [hl], ' ' ; blank tile instead of "/" separator in Yellow
+ inc hl
+ call PlaceString
+ ld hl, wBoxNumString
+ inc [hl]
+ pop de
+ pop hl
+ ld bc, 3 * SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ inc de
+ jr .loop
+
+.done
+ ret
+
+PrintPCBox_DrawTopBorder:
+ hlcoord 0, 0
+ ld a, $79
+ ld [hli], a
+ ld a, $7a
+ ld c, SCREEN_WIDTH - 2
+.loop
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ld a, $7b
+ ld [hl], a
+ ret
+
+PrintPCBox_DrawLeftAndRightBorders:
+ hlcoord 0, 0
+ ld de, SCREEN_WIDTH - 1
+ ld c, SCREEN_HEIGHT
+.loop
+ ld a, $7c
+ ld [hl], a
+ add hl, de
+ ld a, $7c
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ret
+
+PrintPCBox_DrawBottomBorder:
+ hlcoord 0, 17
+PrintPCBox_DrawBottomBorderAtHL:
+ ld a, $7d
+ ld [hli], a
+ ld a, $7a
+ ld c, SCREEN_WIDTH - 2
+.loop
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ld a, $7e
+ ld [hl], a
+ ret
+
+PrintPCBox_PlaceHorizontalLines:
+ hlcoord 4, 0
+ ld c, 6
+ call .PlaceHorizontalLine
+ hlcoord 6, 1
+ ld c, 6
+.PlaceHorizontalLine:
+.loop
+ push bc
+ push hl
+ ld de, .HorizontalLineString
+ call PlaceString
+ pop hl
+ ld bc, 3 * SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+.HorizontalLineString:
+ db "----------@"
diff --git a/engine/printer/printer2.asm b/engine/printer/printer2.asm
new file mode 100644
index 00000000..b7cabbf8
--- /dev/null
+++ b/engine/printer/printer2.asm
@@ -0,0 +1,973 @@
+Printer_GetMonStats:
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ call LoadHpBarAndStatusTilePatterns
+ ld de, GFX_ea563
+ ld hl, vChars2 + $710
+ lb bc, BANK(GFX_ea563), (GFX_ea563End - GFX_ea563) / 8
+ call CopyVideoDataDouble
+
+ ld de, GFX_ea56b
+ ld hl, vChars2 + $6e0
+ lb bc, BANK(GFX_ea56b), (GFX_ea56bEnd - GFX_ea56b) / 8
+ call CopyVideoDataDouble
+
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ xor a
+ ld [wWhichTradeMonSelectionMenu], a
+ call LoadMonData
+
+ ld hl, wTileMap
+ lb bc, 16, 18
+ call TextBoxBorder
+
+ hlcoord 0, 12
+ lb bc, 4, 18
+ call TextBoxBorder
+
+ hlcoord 3, 10
+ call PrintLevelFull
+
+ hlcoord 2, 10
+ ld a, $6e
+ ld [hli], a
+ ld [hl], ' '
+
+ hlcoord 2, 11
+ ld [hl], '’'
+
+ hlcoord 4, 11
+ ld de, wLoadedMonMaxHP
+ lb bc, 2, 3
+ call PrintNumber
+
+ ld a, [wMonHIndex]
+ ld [wPokedexNum], a
+ ld [wCurSpecies], a
+ ld hl, wPartyMonNicks
+ call .GetNamePointer
+ hlcoord 8, 2
+ call PlaceString
+
+ call GetMonName
+ hlcoord 9, 3
+ call PlaceString
+
+ predef IndexToPokedex
+ hlcoord 2, 8
+ ld [hl], '№'
+ inc hl
+ ld [hl], $f2
+ inc hl
+ ld de, wPokedexNum
+ lb bc, $80 | 1, 3
+ call PrintNumber
+
+ hlcoord 8, 4
+ ld de, .OT
+ call PlaceString
+
+ ld hl, wPartyMonOT
+ call .GetNamePointer
+ hlcoord 9, 5
+ call PlaceString
+
+ hlcoord 9, 6
+ ld de, .IDNo
+ call PlaceString
+
+ hlcoord 13, 6
+ ld de, wLoadedMonOTID
+ lb bc, $80 | 2, 5
+ call PrintNumber
+
+ hlcoord 9, 8
+ ld de, .Stats
+ ldh a, [hUILayoutFlags]
+ set BIT_SINGLE_SPACED_LINES, a
+ ldh [hUILayoutFlags], a
+ call PlaceString
+ ldh a, [hUILayoutFlags]
+ res BIT_SINGLE_SPACED_LINES, a
+ ldh [hUILayoutFlags], a
+
+ hlcoord 16, 8
+ ld de, wLoadedMonAttack
+ ld a, 4
+.loop
+ push af
+ push de
+
+ push hl
+ lb bc, 2, 3
+ call PrintNumber
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+
+ pop de
+ inc de
+ inc de
+ pop af
+ dec a
+ jr nz, .loop
+
+ hlcoord 1, 13
+ ld a, [wLoadedMonMoves]
+ call .PlaceMoveName
+
+ hlcoord 1, 14
+ ld a, [wLoadedMonMoves + 1]
+ call .PlaceMoveName
+
+ hlcoord 1, 15
+ ld a, [wLoadedMonMoves + 2]
+ call .PlaceMoveName
+
+ hlcoord 1, 16
+ ld a, [wLoadedMonMoves + 3]
+ call .PlaceMoveName
+
+ ld b, SET_PAL_POKEDEX
+ call RunPaletteCommand
+
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call Delay3
+ call GBPalNormal
+ hlcoord 1, 1
+ call LoadFlippedFrontSpriteByMonIndex
+ ret
+
+.GetNamePointer:
+ ld bc, NAME_LENGTH
+ ld a, [wWhichPokemon]
+ call AddNTimes
+ ld e, l
+ ld d, h
+ ret
+
+.PlaceMoveName:
+ and a
+ jr z, .no_move
+ ld [wNamedObjectIndex], a
+ call GetMoveName
+ jr .place_string
+
+.no_move
+ ld de, .Blank
+.place_string
+ call PlaceString
+ ret
+
+.OT:
+ db "OT/@"
+
+.IDNo:
+ db "<ID>№/@"
+
+.Stats:
+ db "ATTACK"
+ next "DEFENSE"
+ next "SPEED"
+ next "SPECIAL@"
+
+.Blank:
+ db "--------------@"
+
+GFX_ea563:
+INCBIN "gfx/printer/hp.1bpp"
+GFX_ea563End:
+
+GFX_ea56b:
+INCBIN "gfx/printer/lv.1bpp"
+GFX_ea56bEnd:
+
+PrinterDebug_LoadGFX:
+ ld hl, vChars1 + $7e0
+ ld de, GFX_ea597
+ lb bc, BANK(GFX_ea597), (GFX_ea597End - GFX_ea597) / 16
+ call CopyVideoData
+
+ ld hl, wShadowOAMSprite32
+ ld a, $8
+ ld c, $8
+.loop
+ ld [hl], $10
+ inc hl
+ ld [hl], a
+ inc hl
+ ld [hl], $fe
+ inc hl
+ ld [hl], $0
+ inc hl
+ add $8
+ dec c
+ jr nz, .loop
+ ret
+
+GFX_ea597:
+INCBIN "gfx/printer/01.2bpp"
+GFX_ea597End:
+
+PrinterDebug_ConvertStatusFlagsToTiles:
+ ld hl, wShadowOAMSprite32TileID
+ ld de, 4
+ ld a, [wPrinterStatusFlags]
+ ld c, 8
+.loop
+ sla a
+ jr c, .place_1
+ ld [hl], $fe
+ jr .okay
+
+.place_1
+ ld [hl], $ff
+.okay
+ add hl, de
+ dec c
+ jr nz, .loop
+ ret
+
+PrinterDebug_DoFunction:
+ ld a, [wPrinterSendState]
+ 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 Func_ea623
+ dw Func_ea6d2
+ dw Func_ea6af
+ dw Func_ea645
+ dw Func_ea701
+ dw Func_ea6bd
+ dw Func_ea671
+ dw Func_ea701
+ dw Func_ea6af
+ dw Func_ea68a
+ dw Func_ea701
+ dw Func_ea6af
+ dw Func_ea721
+ dw Func_ea610
+ dw Func_ea61a
+ dw Func_ea6af
+ dw Func_ea61e
+ dw Func_ea72f
+ dw Func_ea732
+
+Func_ea606:
+ ld hl, wPrinterSendState
+ inc [hl]
+ ret
+
+Func_ea60b:
+ ld hl, wPrinterSendState
+ dec [hl]
+ ret
+
+Func_ea610:
+ xor a
+ ld [wPrinterStatusFlags], a
+ ld hl, wPrinterSendState
+ set 7, [hl]
+ ret
+
+Func_ea61a:
+ call Func_ea606
+ ret
+
+Func_ea61e:
+ xor a
+ ld [wPrinterSendState], a
+ ret
+
+Func_ea623:
+ call Func_ea784
+ ld hl, Data_ea9de
+ call Func_ea76b
+ xor a
+ ld [wPrinterDataSize], a
+ ld [wPrinterDataSize + 1], a
+ ld a, [wPrinterQueueLength]
+ ld [wPrinterRowIndex], a
+ call Func_ea606
+ call Func_ea74c
+ ld a, $1
+ ld [wPrinterStatusIndicator], a
+ ret
+
+Func_ea645:
+ call Func_ea784
+ ld hl, wPrinterRowIndex
+ ld a, [hl]
+ and a
+ jr z, Func_ea671
+ ld hl, Data_ea9ea
+ call Func_ea76b
+ call PrinterDebug_PrepOAMForPrinting
+ ld a, $80
+ ld [wPrinterDataSize], a
+ ld a, $2
+ ld [wPrinterDataSize + 1], a
+ call Func_ea7a2
+ call Func_ea606
+ call Func_ea74c
+ ld a, $2
+ ld [wPrinterStatusIndicator], a
+ ret
+
+Func_ea671:
+ ld a, $6
+ ld [wPrinterSendState], a
+ ld hl, Data_ea9f0
+ call Func_ea76b
+ xor a
+ ld [wPrinterDataSize], a
+ ld [wPrinterDataSize + 1], a
+ call Func_ea606
+ call Func_ea74c
+ ret
+
+Func_ea68a:
+ call Func_ea784
+ ld hl, Data_ea9e4
+ call Func_ea76b
+ call Func_ea7d2
+ ld a, $4
+ ld [wPrinterDataSize], a
+ ld a, $0
+ ld [wPrinterDataSize + 1], a
+ call Func_ea7a2
+ call Func_ea606
+ call Func_ea74c
+ ld a, $3
+ ld [wPrinterStatusIndicator], a
+ ret
+
+Func_ea6af:
+ ld hl, wPrinterSerialFrameDelay
+ inc [hl]
+ ld a, [hl]
+ cp $6
+ ret c
+ xor a
+ ld [hl], a
+ call Func_ea606
+ ret
+
+Func_ea6bd:
+ ld hl, wPrinterSerialFrameDelay
+ inc [hl]
+ ld a, [hl]
+ cp 6
+ ret c
+ xor a
+ ld [hl], a
+ ld hl, wPrinterRowIndex
+ dec [hl]
+ call Func_ea60b
+ call Func_ea60b
+ ret
+
+Func_ea6d2:
+ call Func_ea742
+ ret c
+ ld a, [wPrinterHandshake]
+ cp $ff
+ jr nz, .asm_ea6e4
+ ld a, [wPrinterStatusFlags]
+ cp $ff
+ jr z, .asm_ea6fb
+.asm_ea6e4
+ ld a, [wPrinterHandshake]
+ cp $81
+ jr nz, .asm_ea6fb
+ ld a, [wPrinterStatusFlags]
+ cp $0
+ jr nz, .asm_ea6fb
+ ld hl, wPrinterConnectionOpen
+ set 1, [hl]
+ call Func_ea606
+ ret
+
+.asm_ea6fb
+ ld a, $e
+ ld [wPrinterSendState], a
+ ret
+
+Func_ea701:
+ call Func_ea742
+ ret c
+ ld a, [wPrinterStatusFlags]
+ and $f0
+ jr nz, .asm_ea71b
+ ld a, [wPrinterStatusFlags]
+ and $1
+ jr nz, .asm_ea717
+ call Func_ea606
+ ret
+
+.asm_ea717
+ call Func_ea60b
+ ret
+
+.asm_ea71b
+ ld a, $11
+ ld [wPrinterSendState], a
+ ret
+
+Func_ea721:
+ call Func_ea742
+ ret c
+ ld a, [wPrinterStatusFlags]
+ and $f3
+ ret nz
+ call Func_ea606
+ ret
+
+Func_ea72f:
+ call Func_ea606
+Func_ea732:
+ ld a, [wPrinterOpcode]
+ and a
+ ret nz
+ ld a, [wPrinterStatusFlags]
+ and $f0
+ ret nz
+ xor a
+ ld [wPrinterSendState], a
+ ret
+
+Func_ea742:
+ ld a, [wPrinterOpcode]
+ and a
+ jr nz, .asm_ea74a
+ and a
+ ret
+
+.asm_ea74a
+ scf
+ ret
+
+Func_ea74c:
+.asm_ea74c
+ ld a, [wPrinterOpcode]
+ and a
+ jr nz, .asm_ea74c
+ ld a, $1
+ ld [wPrinterOpcode], a
+ xor a
+ ld [wPrinterSendByteOffset], a
+ ld [wPrinterSendByteOffset + 1], a
+ ld a, $88
+ ldh [rSB], a
+ ld a, $1
+ ldh [rSC], a
+ ld a, $81
+ ldh [rSC], a
+ ret
+
+Func_ea76b:
+ ld a, [hli]
+ ld [wPrinterDataHeader], a
+ ld a, [hli]
+ ld [wPrinterDataHeader + 1], a
+ ld a, [hli]
+ ld [wPrinterDataHeader + 2], a
+ ld a, [hli]
+ ld [wPrinterDataHeader + 3], a
+ ld a, [hli]
+ ld [wPrinterDataHeader + 4], a
+ ld a, [hl]
+ ld [wPrinterDataHeader + 5], a
+ ret
+
+Func_ea784:
+ xor a
+ ld hl, wPrinterDataHeader
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ld hl, wPrinterDataHeader + 4
+ ld [hli], a
+ ld [hl], a
+ xor a
+ ld [wPrinterDataSize], a
+ ld [wPrinterDataSize + 1], a
+ ld hl, wPrinterSendDataSource1
+ ld bc, $280
+ call FillMemory
+ ret
+
+Func_ea7a2:
+ ld hl, $0
+ ld bc, $4
+ ld de, wPrinterDataHeader
+ call Func_ea7c5
+ ld a, [wPrinterDataSize]
+ ld c, a
+ ld a, [wPrinterDataSize + 1]
+ ld b, a
+ ld de, wPrinterSendDataSource1
+ call Func_ea7c5
+ ld a, l
+ ld [wPrinterDataHeader + 4], a
+ ld a, h
+ ld [wPrinterDataHeader + 5], a
+ ret
+
+Func_ea7c5:
+.asm_ea7c5
+ ld a, [de]
+ inc de
+ add l
+ jr nc, .asm_ea7cb
+ inc h
+.asm_ea7cb
+ ld l, a
+ dec bc
+ ld a, c
+ or b
+ jr nz, .asm_ea7c5
+ ret
+
+Func_ea7d2:
+ ld a, $1
+ ld [wPrinterSendDataSource1], a
+ ld a, [wcae2]
+ ld [wPrinterStatusReceived], a
+ ld a, $e4
+ ld [wc6f2], a
+ ld a, [wPrinterSettingsTempCopy]
+ ld [wc6f3], a
+ ret
+
+PrinterDebug_PrepOAMForPrinting:
+ ld a, [wPrinterRowIndex]
+ ld b, a
+ ld a, [wPrinterQueueLength]
+ sub b
+ ld hl, wPrinterTileBuffer
+ ld de, $28
+.get_start_addr
+ and a
+ jr z, .start_working
+ add hl, de
+ dec a
+ jr .get_start_addr
+
+.start_working
+ ld e, l
+ ld d, h
+ ld hl, wPrinterSendDataSource1
+ ld c, $28
+.prep_loop
+ ld a, [de]
+ inc de
+ push bc
+ push de
+ push hl
+ swap a
+ ld d, a
+ and $f0
+ ld e, a
+ ld a, d
+ and $f
+ ld d, a
+ and $8
+ ld a, d
+ jr nz, .vtiles1
+ or $90
+ jr .got_vram_address
+
+.vtiles1
+ or $80
+.got_vram_address
+ ld d, a
+ lb bc, BANK(PrinterDebug_PrepOAMForPrinting), $1
+ call CopyVideoData
+ pop hl
+ ld de, $10
+ add hl, de
+ pop de
+ pop bc
+ dec c
+ jr nz, .prep_loop
+ call .UnnecessaryCall
+ ret
+
+.UnnecessaryCall:
+ ld hl, wcbdc
+ ld bc, $20
+ xor a
+ call FillMemory
+ ld hl, wShadowOAM
+ ld c, $28
+.master_loop
+ push bc
+ push hl
+ call .AreWePrintingThisSegment
+ jr nc, .skip_segment
+ call .GetVRAMAddress
+ call .GetOAMFlags
+ call .ApplyObjectPalettes
+ call .PlaceObject
+.skip_segment
+ pop hl
+ inc hl
+ inc hl
+ inc hl
+ inc hl
+ pop bc
+ dec c
+ jr nz, .master_loop
+ ret
+
+.AreWePrintingThisSegment:
+ ld a, [wPrinterRowIndex]
+ ld b, a
+ ld a, [wPrinterQueueLength]
+ sub b
+ ld c, a
+ ld b, $10
+.add_n_times
+ ld a, c
+ and a
+ jr z, .check
+ ld a, b
+ add $10
+ ld b, a
+ dec c
+ jr .add_n_times
+
+.check
+ ld a, b
+ ld e, a
+ add $10
+ ld d, a
+ ld a, [hl]
+ cp e
+ jr c, .not_printing
+ cp d
+ jr nc, .not_printing
+ scf
+ ret
+
+.not_printing
+ and a
+ ret
+
+.GetVRAMAddress:
+ push hl
+ inc hl
+ inc hl
+ ld a, [hl]
+ swap a
+ ld d, a
+ and $f0
+ ld e, a
+ ld a, d
+ and $f
+ or $80
+ ld d, a
+ ld hl, wcbdc
+ lb bc, BANK(.GetVRAMAddress), $1
+ call CopyVideoData
+ pop hl
+ ret
+
+.GetOAMFlags:
+ push hl
+ inc hl
+ inc hl
+ inc hl
+ ld a, [hl]
+ call .DoBitOperation
+ pop hl
+ ret
+
+.DoBitOperation:
+ and $60
+ swap a
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Jumptable:
+ dw .nop
+ dw .xflip
+ dw .yflip
+ dw .both
+
+.nop:
+ ret
+
+.xflip:
+ call .XFlip
+ ret
+
+.yflip:
+ call .YFlip
+ ret
+
+.both:
+ call .XFlip
+ call .YFlip
+ ret
+
+.XFlip:
+ ld hl, wcbdc
+ ld c, 16
+.byte_loop
+ ld d, [hl]
+ ld a, 0
+ ld b, 8
+.bit_loop
+ sla d
+ rr a
+ dec b
+ jr nz, .bit_loop
+ ld [hli], a
+ dec c
+ jr nz, .byte_loop
+ ret
+
+.YFlip:
+ ld hl, wcbdc
+ ld de, wcbea
+ ld c, $4
+.swap_loop
+ ld b, [hl]
+ ld a, [de]
+ ld [hli], a
+ ld a, b
+ ld [de], a
+ inc de
+ ld b, [hl]
+ ld a, [de]
+ ld [hli], a
+ ld a, b
+ ld [de], a
+ dec de
+ dec de
+ dec de
+ dec c
+ jr nz, .swap_loop
+ ret
+
+.ApplyObjectPalettes:
+ push hl
+ ld hl, wcbdc
+ ld de, wcbec
+ ld a, 8
+.loop1
+ push af
+ ld bc, $0
+ ld a, 8
+.loop2
+ push af
+ xor a
+ rlc [hl]
+ rl a
+ inc hl
+ rlc [hl]
+ rl a
+ dec hl
+ push hl
+ push de
+ call .ExpandPalettesToBC
+ pop de
+ pop hl
+ pop af
+ dec a
+ jr nz, .loop2
+ inc hl
+ inc hl
+ ld a, b
+ ld [de], a
+ inc de
+ ld a, c
+ ld [de], a
+ inc de
+ pop af
+ dec a
+ jr nz, .loop1
+ pop hl
+ ret
+
+.ExpandPalettesToBC:
+ call .GetPaletteFunction
+ call .ApplyPaletteFunction
+ ret
+
+.GetPaletteFunction:
+ ld e, a
+ ld d, 0
+ ld hl, .PalJumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.PalJumptable:
+ dw .Pal0
+ dw .Pal1
+ dw .Pal2
+ dw .Pal3
+
+.Pal0:
+ ldh a, [rOBP0]
+ and $3
+ ret
+
+.Pal2:
+ ldh a, [rOBP0]
+ and $c
+ srl a
+ srl a
+ ret
+
+.Pal1:
+ ldh a, [rOBP0]
+ and $30
+ swap a
+ ret
+
+.Pal3:
+ ldh a, [rOBP0]
+ and $c0
+ rlca
+ rlca
+ ret
+
+.ApplyPaletteFunction:
+ ld e, a
+ ld d, 0
+ ld hl, .PalFunJumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.PalFunJumptable:
+ dw .zero_zero
+ dw .xflip_zero
+ dw .zero_xflip
+ dw .xflip_xflip
+
+.zero_zero:
+ sla b
+ sla c
+ ret
+
+.xflip_zero:
+ scf
+ rl b
+ sla c
+ ret
+
+.zero_xflip:
+ sla b
+ scf
+ rl c
+ ret
+
+.xflip_xflip:
+ scf
+ rl b
+ scf
+ rl c
+ ret
+
+.PlaceObject:
+ push hl
+ ld a, [hli]
+ ld c, [hl]
+ and $8
+ jr nz, .use_source_2
+ ld hl, wPrinterSendDataSource1
+ jr .got_data_source
+
+.use_source_2
+ ld hl, wPrinterSendDataSource2
+.got_data_source
+ ld b, $0
+ ld a, c
+ and %11111000
+ sub $8
+ ld c, a
+ sla c
+ rl b
+ add hl, bc
+ ld e, l
+ ld d, h
+ ld hl, wcbec
+ ld c, $8
+.coord_copy_loop
+ call .GetBitMask
+ ld a, [de]
+ and b
+ or [hl]
+ ld [de], a
+ inc hl
+ inc de
+ ld a, [de]
+ and b
+ or [hl]
+ ld [de], a
+ inc hl
+ inc de
+ dec c
+ jr nz, .coord_copy_loop
+ pop hl
+ ret
+
+.GetBitMask:
+ push hl
+ push de
+ ld de, -$10
+ add hl, de
+ ld a, [hli]
+ or [hl]
+ xor $ff
+ ld b, a
+ pop de
+ pop hl
+ ret
+
+Data_ea9de:
+ db 1, 0, $00, 0
+ dw 1
+Data_ea9e4:
+ db 2, 0, $04, 0
+ dw 0
+Data_ea9ea:
+ db 4, 0, $80, 2
+ dw 0
+Data_ea9f0:
+ db 4, 0, $00, 0
+ dw 4
+Data_ea9f6:
+ db 8, 0, $00, 0
+ dw 8
+Data_ea9fc:
+ db 15, 0, $00, 0
+ dw 15
diff --git a/engine/printer/serial.asm b/engine/printer/serial.asm
new file mode 100644
index 00000000..fd4dd056
--- /dev/null
+++ b/engine/printer/serial.asm
@@ -0,0 +1,632 @@
+ const_def
+ const PRINTER_STATUS_BLANK
+ const PRINTER_STATUS_CHECKING_LINK
+ const PRINTER_STATUS_TRANSMITTING
+ const PRINTER_STATUS_PRINTING
+ const PRINTER_ERROR_1
+ const PRINTER_ERROR_2
+ const PRINTER_ERROR_3
+ const PRINTER_ERROR_4
+ const PRINTER_ERROR_WRONG_DEVICE
+
+StartTransmission_Send9Rows:
+ ld a, 9
+Printer_StartTransmission:
+ push af
+ ld hl, wPrinterData
+ ld bc, wPrinterDataEnd - wPrinterData
+ xor a
+ call Printer_FillMemory
+ xor a
+ ldh [rSB], a
+ ldh [rSC], a
+ ld [wPrinterOpcode], a
+ ld hl, wPrinterConnectionOpen
+ set 0, [hl]
+ ld a, [wPrinterSettings]
+ ld [wPrinterSettingsTempCopy], a
+ pop af
+ ld [wPrinterQueueLength], a
+ ret
+
+PrinterTransmissionJumptable:
+ ld a, [wPrinterSendState]
+ 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 Printer_InitSerial ; 00
+ dw Printer_CheckConnectionStatus ; 01
+ dw Printer_WaitSerial ; 02
+ dw Printer_StartTransmittingTilemap ; 03
+ dw Printer_TransmissionLoop ; 04
+ dw Printer_WaitSerialAndLoopBack2 ; 05
+ dw Printer_EndTilemapTransmission ; 06
+ dw Printer_TransmissionLoop ; 07
+ dw Printer_WaitSerial ; 08
+
+ dw Printer_SignalSendHeader ; 09
+ dw Printer_TransmissionLoop ; 0a
+ dw Printer_WaitSerial ; 0b
+ dw Printer_WaitUntilFinished ; 0c
+ dw Printer_Quit ; 0d
+
+ dw Printer_Next_ ; 0e
+ dw Printer_WaitSerial ; 0f
+ dw Printer_SignalLoopBack ; 10
+ dw Printer_LoopBack ; 11
+ dw Printer_WaitLoopBack ; 12
+ dw Printer_WaitLoopBack_ ; 13
+
+Printer_Next:
+ ld hl, wPrinterSendState
+ inc [hl]
+ ret
+
+Printer_Back:
+ ld hl, wPrinterSendState
+ dec [hl]
+ ret
+
+Printer_Quit:
+ xor a
+ ld [wPrinterStatusFlags], a
+ ld hl, wPrinterSendState
+ set 7, [hl]
+ ret
+
+Printer_Next_:
+ call Printer_Next
+ ret
+
+Printer_LoopBack:
+ ld a, $1
+ ld [wPrinterSendState], a
+ ret
+
+Printer_InitSerial:
+ call ResetPrinterData
+ ld hl, PrinterDataPacket1
+ call CopyPrinterDataHeader
+ xor a
+ ld [wPrinterDataSize], a
+ ld [wPrinterDataSize + 1], a
+ ld a, [wPrinterQueueLength]
+ ld [wPrinterRowIndex], a
+ call Printer_Next
+ call Printer_PrepareToSend
+ ld a, PRINTER_STATUS_CHECKING_LINK
+ ld [wPrinterStatusIndicator], a
+ ret
+
+Printer_StartTransmittingTilemap:
+ call ResetPrinterData
+ ld hl, wPrinterRowIndex
+ ld a, [hl]
+ and a
+ jr z, Printer_EndTilemapTransmission
+ ld hl, PrinterDataPacket3
+ call CopyPrinterDataHeader
+ call Printer_Convert2RowsTo2bpp
+ ld a, LOW(wPrinterSendDataSource1End - wPrinterSendDataSource1)
+ ld [wPrinterDataSize], a
+ ld a, HIGH(wPrinterSendDataSource1End - wPrinterSendDataSource1)
+ ld [wPrinterDataSize + 1], a
+ call ComputePrinterChecksum
+ call Printer_Next
+ call Printer_PrepareToSend
+ ld a, PRINTER_STATUS_TRANSMITTING
+ ld [wPrinterStatusIndicator], a
+ ret
+
+Printer_EndTilemapTransmission:
+ ld a, $6
+ ld [wPrinterSendState], a
+ ld hl, PrinterDataPacket4
+ call CopyPrinterDataHeader
+ xor a
+ ld [wPrinterDataSize], a
+ ld [wPrinterDataSize + 1], a
+ call Printer_Next
+ call Printer_PrepareToSend
+ ret
+
+Printer_SignalSendHeader:
+ call ResetPrinterData
+ ld hl, PrinterDataPacket2
+ call CopyPrinterDataHeader
+ call Printer_StageHeaderForSend
+ ld a, $4
+ ld [wPrinterDataSize], a
+ ld a, $0
+ ld [wPrinterDataSize + 1], a
+ call ComputePrinterChecksum
+ call Printer_Next
+ call Printer_PrepareToSend
+ ld a, PRINTER_STATUS_PRINTING
+ ld [wPrinterStatusIndicator], a
+ ret
+
+Printer_SignalLoopBack:
+ call ResetPrinterData
+ ld hl, PrinterDataPacket1
+ call CopyPrinterDataHeader
+ xor a
+ ld [wPrinterDataSize], a
+ ld [wPrinterDataSize + 1], a
+ ld a, [wPrinterQueueLength]
+ ld [wPrinterRowIndex], a
+ call Printer_Next
+ call Printer_PrepareToSend
+ ret
+
+Printer_WaitSerial:
+ ld hl, wPrinterSerialFrameDelay
+ inc [hl]
+ ld a, [hl]
+ cp $6
+ ret c
+ xor a
+ ld [hl], a
+ call Printer_Next
+ ret
+
+Printer_WaitSerialAndLoopBack2:
+ ld hl, wPrinterSerialFrameDelay
+ inc [hl]
+ ld a, [hl]
+ cp $6
+ ret c
+ xor a
+ ld [hl], a
+ ld hl, wPrinterRowIndex
+ dec [hl]
+ call Printer_Back
+ call Printer_Back
+ ret
+
+Printer_CheckConnectionStatus:
+ ld a, [wPrinterOpcode]
+ and a
+ ret nz
+ ld a, [wPrinterHandshake]
+ cp $ff
+ jr nz, .asm_e88dc
+ ld a, [wPrinterStatusFlags]
+ cp $ff
+ jr z, .asm_e88f8
+.asm_e88dc
+ ld a, [wPrinterHandshake]
+ cp $81
+ jr nz, .asm_e88f8
+ ld a, [wPrinterStatusFlags]
+ cp $0
+ jr nz, .asm_e88f8
+ ld hl, wPrinterConnectionOpen
+ set 1, [hl]
+ ld a, $5
+ ld [wHandshakeFrameDelay], a
+ call Printer_Next
+ ret
+
+.asm_e88f8
+ ld a, $ff
+ ld [wPrinterHandshake], a
+ ld [wPrinterStatusFlags], a
+ ld a, $e
+ ld [wPrinterSendState], a
+ ret
+
+Printer_TransmissionLoop:
+ ld a, [wPrinterOpcode]
+ and a
+ ret nz
+ ld a, [wPrinterStatusFlags]
+ and $f0
+ jr nz, .asm_e8921
+ ld a, [wPrinterStatusFlags]
+ and $1
+ jr nz, .asm_e891d
+ call Printer_Next
+ ret
+
+.asm_e891d
+ call Printer_Back
+ ret
+
+.asm_e8921
+ ld a, $12
+ ld [wPrinterSendState], a
+ ret
+
+Printer_WaitUntilFinished:
+ ld a, [wPrinterOpcode]
+ and a
+ ret nz
+ ld a, [wPrinterStatusFlags]
+ and $f3
+ ret nz
+ call Printer_Next
+ ret
+
+Printer_WaitLoopBack:
+ call Printer_Next
+Printer_WaitLoopBack_:
+ ld a, [wPrinterOpcode]
+ and a
+ ret nz
+ ld a, [wPrinterStatusFlags]
+ and $f0
+ ret nz
+ xor a
+ ld [wPrinterSendState], a
+ ret
+
+Printer_PrepareToSend:
+.wait_printer_operation
+ ld a, [wPrinterOpcode]
+ and a
+ jr nz, .wait_printer_operation
+ xor a
+ ld [wPrinterSendByteOffset], a
+ ld [wPrinterSendByteOffset + 1], a
+ ld a, $1
+ ld [wPrinterOpcode], a
+ ld a, $88
+ ldh [rSB], a
+ ld a, $1
+ ldh [rSC], a
+ ld a, $81
+ ldh [rSC], a
+ ret
+
+CopyPrinterDataHeader:
+ ld a, [hli]
+ ld [wPrinterDataHeader], a
+ ld a, [hli]
+ ld [wPrinterDataHeader + 1], a
+ ld a, [hli]
+ ld [wPrinterDataHeader + 2], a
+ ld a, [hli]
+ ld [wPrinterDataHeader + 3], a
+ ld a, [hli]
+ ld [wPrinterChecksum], a
+ ld a, [hl]
+ ld [wPrinterChecksum + 1], a
+ ret
+
+ResetPrinterData:
+ xor a
+ ld hl, wPrinterDataHeader
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ld hl, wPrinterChecksum
+ ld [hli], a
+ ld [hl], a
+ xor a
+ ld [wPrinterDataSize], a
+ ld [wPrinterDataSize + 1], a
+ ld hl, wPrinterSendDataSource1
+ ld bc, wPrinterSendDataSource1End - wPrinterSendDataSource1
+ call Printer_FillMemory
+ ret
+
+ComputePrinterChecksum:
+ ld hl, $0
+ ld bc, $4
+ ld de, wPrinterDataHeader
+ call .AddToChecksum
+ ld a, [wPrinterDataSize]
+ ld c, a
+ ld a, [wPrinterDataSize + 1]
+ ld b, a
+ ld de, wPrinterSendDataSource1
+ call .AddToChecksum
+ ld a, l
+ ld [wPrinterChecksum], a
+ ld a, h
+ ld [wPrinterChecksum + 1], a
+ ret
+
+.AddToChecksum:
+.loop
+ ld a, [de]
+ inc de
+ add l
+ jr nc, .no_carry
+ inc h
+.no_carry
+ ld l, a
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ ret
+
+Printer_StageHeaderForSend:
+ ld a, $1
+ ld [wPrinterSendDataSource1], a
+ ld a, [wcae2]
+ ld [wPrinterSendDataSource1 + 1], a
+ ld a, %11100100
+ ld [wPrinterSendDataSource1 + 2], a
+ ld a, [wPrinterSettingsTempCopy]
+ ld [wPrinterSendDataSource1 + 3], a
+ ret
+
+Printer_Convert2RowsTo2bpp:
+ ld a, [wPrinterRowIndex]
+ ld b, a
+ ld a, [wPrinterQueueLength]
+ sub b
+ ld hl, wPrinterTileBuffer
+ ld de, 2 * SCREEN_WIDTH
+.get_row
+ and a
+ jr z, .got_row
+ add hl, de
+ dec a
+ jr .get_row
+
+.got_row
+ ld e, l
+ ld d, h
+ ld hl, wPrinterSendDataSource1
+ ld c, 2 * SCREEN_WIDTH
+.loop
+ ld a, [de]
+ inc de
+ push bc
+ push de
+ push hl
+ swap a
+ ld d, a
+ and $f0
+ ld e, a
+ ld a, d
+ and $f
+ ld d, a
+ and $8
+ ld a, d
+ jr nz, .vchars1
+ or $90
+ jr .got_addr
+
+.vchars1
+ or $80
+.got_addr
+ ld d, a
+ lb bc, BANK(Printer_Convert2RowsTo2bpp), 1
+ call CopyVideoData
+ pop hl
+ ld de, $10
+ add hl, de
+ pop de
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+Printer_FillMemory:
+ push de
+ ld e, a
+.loop
+ ld [hl], e
+ inc hl
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ ld a, e
+ pop de
+ ret
+
+PrinterDataPacket1:
+ db 1, 0, $00, 0
+ dw 1
+PrinterDataPacket2:
+ db 2, 0, $04, 0
+ dw 0
+PrinterDataPacket3:
+ db 4, 0, $80, 2
+ dw 0
+PrinterDataPacket4:
+ db 4, 0, $00, 0
+ dw 4
+PrinterDataPacket5: ; unused
+ db 8, 0, $00, 0
+ dw 8
+PrinterDataPacket6: ; unused
+ db 15, 0, $00, 0
+ dw 15
+
+PrinterSerial_::
+ ld a, [wPrinterOpcode]
+ 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 .Nop
+
+ dw .SignalTransmissionStart
+ dw .SendHeaderByte1
+ dw .SendHeaderByte2
+ dw .SendHeaderByte3
+ dw .SendHeaderByte4
+ dw .DataByte
+ dw .SendChecksumLo
+ dw .SendChecksumHi
+ dw .SignalTransmissionEnd
+ dw .Receive1
+ dw .Receive2
+
+ dw .SignalTransmissionStart
+ dw .Send_0F
+ dw .Send_00
+ dw .Send_00
+ dw .Send_00
+ dw .Send_0F
+ dw .Send_00
+ dw .SignalTransmissionEnd
+ dw .Receive1
+ dw .Receive2_
+
+ dw .SignalTransmissionStart
+ dw .SignalQuit
+ dw .Send_00
+ dw .Send_00
+ dw .Send_00
+ dw .SignalQuit
+ dw .Send_00
+ dw .SignalTransmissionEnd
+ dw .Receive1
+ dw .Receive2
+
+.NextInstruction:
+ ld hl, wPrinterOpcode
+ inc [hl]
+ ret
+
+.Nop:
+ ret
+
+.SignalTransmissionStart:
+ ld a, $33
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.SendHeaderByte1:
+ ld a, [wPrinterDataHeader]
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.SendHeaderByte2:
+ ld a, [wPrinterDataHeader + 1]
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.SendHeaderByte3:
+ ld a, [wPrinterDataHeader + 2]
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.SendHeaderByte4:
+ ld a, [wPrinterDataHeader + 3]
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.DataByte:
+ ld hl, wPrinterDataSize
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld a, e
+ or d
+ jr z, .sent_last_byte
+ dec de
+ ld [hl], d
+ dec hl
+ ld [hl], e
+ ld a, [wPrinterSendByteOffset]
+ ld e, a
+ ld a, [wPrinterSendByteOffset + 1]
+ ld d, a
+ ld hl, wPrinterSendDataSource1
+ add hl, de
+ inc de
+ ld a, e
+ ld [wPrinterSendByteOffset], a
+ ld a, d
+ ld [wPrinterSendByteOffset + 1], a
+ ld a, [hl]
+ call .SendByte
+ ret
+
+.sent_last_byte
+ call .NextInstruction
+.SendChecksumLo:
+ ld a, [wPrinterChecksum]
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.SendChecksumHi:
+ ld a, [wPrinterChecksum + 1]
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.SignalTransmissionEnd:
+ ld a, $0
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.Receive1:
+ ldh a, [rSB]
+ ld [wPrinterHandshake], a
+ ld a, $0
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.Receive2:
+ ldh a, [rSB]
+ ld [wPrinterStatusFlags], a
+ xor a
+ ld [wPrinterOpcode], a
+ ret
+
+.Send_0F:
+ ld a, $f
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.Send_00:
+ ld a, $0
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.SignalQuit:
+ ld a, $8
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.SendByte:
+ ldh [rSB], a
+ ld a, $1
+ ldh [rSC], a
+ ld a, $81
+ ldh [rSC], a
+ ret
+
+.Receive2_:
+ ldh a, [rSB]
+ ld [wPrinterStatusFlags], a
+ xor a
+ ld [wPrinterOpcode], a
+ ret
diff --git a/engine/slots/slot_machine.asm b/engine/slots/slot_machine.asm
index 2e02caf3..fbbdbcb6 100644
--- a/engine/slots/slot_machine.asm
+++ b/engine/slots/slot_machine.asm
@@ -24,9 +24,11 @@ PromptUserToPlaySlots:
call LoadFontTilePatterns
ld b, SET_PAL_SLOTS
call RunPaletteCommand
+ call Delay3
call GBPalNormal
ld a, $e4
ldh [rOBP0], a
+ call UpdateCGBPal_OBP0
ld hl, wStatusFlags5
set BIT_NO_TEXT_DELAY, [hl]
xor a
@@ -81,8 +83,7 @@ MainSlotMachineLoop:
ld [wLastMenuItem], a
ld [wMenuWatchMovingOutOfBounds], a
hlcoord 14, 11
- ld b, 5
- ld c, 4
+ lb bc, 5, 4
call TextBoxBorder
hlcoord 16, 12
ld de, CoinMultiplierSlotMachineText
@@ -458,6 +459,7 @@ SlotMachine_CheckForMatches:
ldh a, [rBGP]
xor $40
ldh [rBGP], a
+ call UpdateCGBPal_BGP
ld c, 5
call DelayFrames
dec b
@@ -474,6 +476,7 @@ SlotMachine_CheckForMatches:
call SlotMachine_PrintPayoutCoins
ld a, $e4
ldh [rOBP0], a
+ call UpdateCGBPal_OBP0
jp .done
SymbolLinedUpSlotMachineText:
@@ -699,6 +702,7 @@ SlotMachine_PayCoinsToPlayer:
ldh a, [rOBP0]
xor $40 ; make the slot wheel symbols flash
ldh [rOBP0], a
+ call UpdateCGBPal_OBP0
ld a, 5
.skip1
ld [wAnimCounter], a
@@ -853,17 +857,17 @@ LoadSlotMachineTiles:
ld de, vChars0
ld bc, $1c tiles ; should be SlotMachineTiles2End - SlotMachineTiles2, or $18 tiles
ld a, BANK(SlotMachineTiles2)
- call FarCopyData2
+ call FarCopyData
ld hl, SlotMachineTiles1
ld de, vChars2
ld bc, SlotMachineTiles1End - SlotMachineTiles1
ld a, BANK(SlotMachineTiles1)
- call FarCopyData2
+ call FarCopyData
ld hl, SlotMachineTiles2
ld de, vChars2 tile $25
ld bc, $1c tiles ; should be SlotMachineTiles2End - SlotMachineTiles2, or $18 tiles
ld a, BANK(SlotMachineTiles2)
- call FarCopyData2
+ call FarCopyData
ld hl, SlotMachineMap
decoord 0, 0
ld bc, SlotMachineMapEnd - SlotMachineMap
@@ -885,10 +889,5 @@ SlotMachineMapEnd:
INCLUDE "data/events/slot_machine_wheels.asm"
SlotMachineTiles1:
-IF DEF(_RED)
- INCBIN "gfx/slots/red_slots_1.2bpp"
-ENDC
-IF DEF(_BLUE)
- INCBIN "gfx/slots/blue_slots_1.2bpp"
-ENDC
+ INCBIN "gfx/slots/slots_1.2bpp"
SlotMachineTiles1End: