summaryrefslogtreecommitdiff
path: root/engine
diff options
context:
space:
mode:
Diffstat (limited to 'engine')
-rwxr-xr-xengine/HoF_room_pc.asm283
-rw-r--r--engine/add_mon.asm6
-rwxr-xr-xengine/animated_objects_3e.asm394
-rw-r--r--engine/bank30.binbin0 -> 16384 bytes
-rw-r--r--engine/bank3c.asm189
-rw-r--r--engine/bank3d.asm495
-rw-r--r--engine/bank3e.asm5
-rw-r--r--engine/bank3f.asm23
-rwxr-xr-xengine/battle/animations.asm766
-rw-r--r--engine/battle/bank3d_battle.asm291
-rwxr-xr-xengine/battle/bank_e_misc.asm19
-rw-r--r--engine/battle/battle_transitions.asm8
-rw-r--r--engine/battle/common_text.asm16
-rwxr-xr-xengine/battle/core.asm710
-rw-r--r--engine/battle/draw_hud_pokeball_gfx.asm10
-rwxr-xr-xengine/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/link_battle_versus_text.asm3
-rw-r--r--engine/battle/moveEffects/heal_effect.asm6
-rw-r--r--engine/battle/moveEffects/reflect_light_screen_effect.asm6
-rw-r--r--engine/battle/moveEffects/transform_effect.asm11
-rwxr-xr-xengine/battle/read_trainer_party.asm103
-rwxr-xr-xengine/battle/safari_zone.asm10
-rw-r--r--engine/battle/scale_sprites.asm7
-rw-r--r--engine/battle/trainer_ai.asm37
-rw-r--r--engine/battle/wild_encounters.asm7
-rw-r--r--engine/bcd.asm62
-rw-r--r--engine/bg_map_attributes.asm219
-rw-r--r--engine/black_out.asm2
-rwxr-xr-xengine/cable_club.asm61
-rwxr-xr-xengine/clear_save.asm4
-rw-r--r--engine/debug1.asm25
-rwxr-xr-xengine/diploma_3a.asm166
-rw-r--r--engine/display_text_id_init.asm9
-rwxr-xr-xengine/evolution.asm8
-rwxr-xr-xengine/evolve_trade.asm44
-rwxr-xr-xengine/evos_moves.asm219
-rwxr-xr-xengine/gamefreak.asm50
-rwxr-xr-xengine/give_pokemon.asm5
-rwxr-xr-xengine/hall_of_fame.asm37
-rwxr-xr-xengine/hidden_object_functions14.asm2
-rwxr-xr-xengine/hidden_object_functions17.asm111
-rwxr-xr-xengine/hidden_object_functions18.asm52
-rwxr-xr-xengine/hidden_object_functions3.asm2
-rwxr-xr-xengine/hidden_object_functions7.asm75
-rwxr-xr-xengine/hp_bar.asm8
-rwxr-xr-xengine/in_game_trades.asm58
-rw-r--r--engine/init_player_data.asm5
-rwxr-xr-xengine/intro.asm354
-rw-r--r--engine/items/inventory.asm9
-rwxr-xr-xengine/items/items.asm588
-rwxr-xr-xengine/items/tms.asm6
-rw-r--r--engine/joypad.asm38
-rwxr-xr-xengine/learn_move.asm42
-rw-r--r--engine/load_mon_data.asm21
-rw-r--r--engine/menu/bills_pc.asm90
-rw-r--r--[-rwxr-xr-x]engine/menu/diploma.asm100
-rw-r--r--engine/menu/draw_start_menu.asm10
-rwxr-xr-xengine/menu/league_pc.asm5
-rw-r--r--engine/menu/link_menu.asm910
-rwxr-xr-xengine/menu/main_menu.asm451
-rwxr-xr-xengine/menu/naming_screen.asm30
-rw-r--r--engine/menu/options.asm443
-rwxr-xr-xengine/menu/party_menu.asm22
-rwxr-xr-xengine/menu/players_pc.asm7
-rwxr-xr-xengine/menu/pokedex.asm362
-rwxr-xr-xengine/menu/prize_menu.asm9
-rwxr-xr-xengine/menu/start_menu.asm5
-rwxr-xr-xengine/menu/start_sub_menus.asm39
-rwxr-xr-xengine/menu/status_screen.asm28
-rw-r--r--engine/menu/text_box.asm36
-rwxr-xr-xengine/menu/vending_machine.asm3
-rwxr-xr-xengine/mon_party_sprites.asm30
-rwxr-xr-xengine/multiply_divide.asm65
-rwxr-xr-xengine/oak_speech.asm43
-rwxr-xr-xengine/oak_speech2.asm43
-rw-r--r--engine/overworld/advance_player_sprite.asm241
-rwxr-xr-xengine/overworld/cable_club_npc.asm59
-rwxr-xr-xengine/overworld/card_key.asm11
-rwxr-xr-xengine/overworld/cut.asm7
-rwxr-xr-xengine/overworld/cut2.asm2
-rwxr-xr-xengine/overworld/doors.asm4
-rw-r--r--engine/overworld/dungeon_warps.asm15
-rwxr-xr-xengine/overworld/elevator.asm6
-rwxr-xr-xengine/overworld/emotion_bubbles.asm18
-rw-r--r--engine/overworld/field_move_messages.asm4
-rwxr-xr-xengine/overworld/healing_machine.asm27
-rwxr-xr-xengine/overworld/hidden_items.asm17
-rwxr-xr-xengine/overworld/hidden_objects.asm42
-rwxr-xr-xengine/overworld/ledges.asm18
-rw-r--r--engine/overworld/map_sprite_functions1.asm48
-rwxr-xr-xengine/overworld/map_sprites.asm595
-rw-r--r--engine/overworld/missable_objects.asm19
-rw-r--r--engine/overworld/movement.asm401
-rwxr-xr-xengine/overworld/npc_movement.asm52
-rwxr-xr-xengine/overworld/npc_movement_2.asm24
-rw-r--r--engine/overworld/oam.asm163
-rwxr-xr-xengine/overworld/player_animations.asm26
-rw-r--r--engine/overworld/player_state.asm29
-rw-r--r--engine/overworld/poison.asm41
-rwxr-xr-xengine/overworld/pokecenter.asm101
-rw-r--r--engine/overworld/push_boulder.asm4
-rwxr-xr-xengine/overworld/ssanne.asm4
-rw-r--r--engine/overworld/tileset_header.asm21
-rwxr-xr-xengine/palettes.asm583
-rw-r--r--engine/pathfinding.asm8
-rwxr-xr-xengine/pikachu_emotions.asm421
-rwxr-xr-xengine/pikachu_follow.asm1578
-rwxr-xr-xengine/pikachu_movement.asm1048
-rwxr-xr-xengine/pikachu_pcm.asm154
-rwxr-xr-xengine/pikachu_pic_animation.asm851
-rwxr-xr-xengine/pikachu_status.asm258
-rwxr-xr-xengine/play_time.asm61
-rwxr-xr-xengine/pokedex_rating.asm102
-rwxr-xr-xengine/predefs.asm28
-rwxr-xr-xengine/predefs7.asm6
-rw-r--r--[-rwxr-xr-x]engine/predefsA.asm (renamed from engine/predefs12.asm)10
-rw-r--r--engine/print_waiting_text.asm11
-rw-r--r--engine/printer.asm999
-rwxr-xr-xengine/printer/serial.asm621
-rw-r--r--engine/remove_pokemon.asm66
-rwxr-xr-xengine/save.asm172
-rwxr-xr-xengine/slot_machine.asm21
-rwxr-xr-xengine/surfing_minigame.asm2862
-rwxr-xr-xengine/titlescreen.asm455
-rwxr-xr-xengine/titlescreen2.asm4
-rwxr-xr-xengine/town_map.asm23
-rwxr-xr-xengine/trade.asm28
-rwxr-xr-xengine/turn_sprite.asm25
-rwxr-xr-xengine/unknown_ea3ea.asm973
-rwxr-xr-xengine/vermilion_gym_trash_cans.asm108
-rwxr-xr-xengine/yellow_intro.asm1081
133 files changed, 19080 insertions, 3925 deletions
diff --git a/engine/HoF_room_pc.asm b/engine/HoF_room_pc.asm
index 7e08631c..c070e8c8 100755
--- a/engine/HoF_room_pc.asm
+++ b/engine/HoF_room_pc.asm
@@ -1,140 +1,130 @@
HallOfFamePC:
- callba AnimateHallOfFame
+ callab FallingStarEnd
call ClearScreen
ld c, 100
call DelayFrames
+
call DisableLCD
- ld hl, vFont
- ld bc, $800 / 2
- call ZeroMemory
- ld hl, vChars2 + $600
- ld bc, $200 / 2
- call ZeroMemory
- ld hl, vChars2 + $7e0
- ld bc, $10
- ld a, $ff
- call FillMemory
+ ld a, $a7
+ ld [rWX], a
+ xor a
+ ld [rSCX], a
+ ld [rSCY], a
+ ld [hSCX], a
+ ld [hSCY], a
+ ld [hWY], a
+ ld [rWY], a
+ call CreditsLoadFont
coord hl, 0, 0
call FillFourRowsWithBlack
coord hl, 0, 14
call FillFourRowsWithBlack
ld a, %11000000
ld [rBGP], a
+ call UpdateGBCPal_BGP
call EnableLCD
- ld a, $ff
- 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 [wUnusedCD3D], a ; not read
+ ld [wHoFMonSpecies], a
ld [wNumCreditsMonsDisplayed], a
jp Credits
FadeInCreditsText:
+ ld a, 1
+ ld [H_AUTOBGTRANSFERENABLED], a
ld hl, HoFGBPalettes
ld b, 4
.loop
ld a, [hli]
ld [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 5
call DelayFrames
dec b
jr nz, .loop
ret
+HoFGBPalettes:
+ db %11000000
+ db %11010000
+ db %11100000
+ db %11110000
+
DisplayCreditsMon:
+ ld hl, vBGMap1
+ call CreditsCopyTileMapToVRAM
xor a
ld [H_AUTOBGTRANSFERENABLED], a
- call SaveScreenTilesToBuffer1
+ ld hl, rLCDC
+ set 3, [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 [wcf91], a
- ld [wd0b5], a
- coord hl, 8, 6
- call GetMonHeader
- call LoadFrontSpriteByMonIndex
- ld hl, vBGMap0 + $c
+ call GetNextCreditsMon
+ ld hl, vBGMap0 + 12
call CreditsCopyTileMapToVRAM
xor a
ld [H_AUTOBGTRANSFERENABLED], a
- call LoadScreenTilesFromBuffer1
+ call LoadScreenTilesFromBuffer2DisableBGTransfer
ld hl, vBGMap0
call CreditsCopyTileMapToVRAM
- ld a, $A7
- ld [rWX], a
- ld hl, vBGMap1
- call CreditsCopyTileMapToVRAM
- call FillMiddleOfScreenWithWhite
ld a, %11111100 ; make the mon a black silhouette
ld [rBGP], a
-
-; scroll the mon left by one tile 7 times
- ld bc, 7
-.scrollLoop1
+ call UpdateGBCPal_BGP
+ ld hl, rLCDC
+ res 3, [hl]
+ ld a, 1
+ ld [H_AUTOBGTRANSFERENABLED], 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
- ld a, [rWX]
- sub 8
- ld [rWX], a
- dec c
- jr nz, .scrollLoop2
-
- xor a
- ld [hWY], a
ld a, %11000000
ld [rBGP], a
+ call UpdateGBCPal_BGP
+ xor a
+ ld [hSCX], a
ret
-INCLUDE "data/credit_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
+ ld [hSCX], a
+ add 8
ld b, a
+ call DelayFrame
+ dec c
+ jr nz, ScrollCreditsMonLeft
ret
-ScrollCreditsMonLeft_SetSCX:
- ld a, [rLY]
- cp l
- jr nz, ScrollCreditsMonLeft_SetSCX
- ld a, h
- ld [rSCX], a
-.loop
- ld 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 [wcf91], a
+ ld [wd0b5], a
+ coord hl, 8, 6
+ call GetMonHeader
+ call LoadFrontSpriteByMonIndex
ret
-HoFGBPalettes:
- db %11000000
- db %11010000
- db %11100000
- db %11110000
+INCLUDE "data/credit_mons.asm"
CreditsCopyTileMapToVRAM:
ld a, l
@@ -145,6 +135,23 @@ CreditsCopyTileMapToVRAM:
ld [H_AUTOBGTRANSFERENABLED], a
jp Delay3
+CreditsLoadFont:
+ call LoadFontTilePatterns
+ ld hl, vChars1
+ ld bc, $40 * $10
+ call ZeroMemory
+
+ call LoadTextBoxTilePatterns
+ ld hl, vChars2 + $60 * $10
+ ld bc, $10 * $10
+ call ZeroMemory
+
+ ld hl, vChars2 + $7e * $10
+ ld bc, $1 * $10
+ ld a, $ff
+ call FillMemory
+ ret
+
ZeroMemory:
; zero bc bytes at hl
ld [hl], 0
@@ -167,7 +174,40 @@ FillMiddleOfScreenWithWhite:
ld a, " "
jp FillMemory
-Credits:
+FillLeftHalfOfScreenWithWhite:
+ coord hl, 0, 4
+ push bc
+ call FillHalfOfScreenWithWhite
+ pop bc
+ ret
+
+FillRightHalfOfScreenWithWhite:
+ coord hl, 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
@@ -192,58 +232,48 @@ Credits:
jr z, .showCopyrightText
cp $fa
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, $ff
- pop hl
- add hl, bc
- call PlaceString
- pop hl
- ld bc, SCREEN_WIDTH * 2
- add hl, bc
+ call PlaceCreditsText
+ pop de
+ jr .nextCreditsCommand
+
+.showCopyrightText
+ callba LoadCopyrightTiles
pop de
jr .nextCreditsCommand
+
+
.fadeInTextAndShowMon
call FadeInCreditsText
- ld c, 90
+ ld c, 102
jr .next1
+
.showTextAndShowMon
- ld c, 110
+ ld c, 122
.next1
call DelayFrames
call DisplayCreditsMon
jr .nextCreditsScreen
+
.fadeInText
call FadeInCreditsText
- ld c, 120
+ ld c, 132
jr .next2
+
.showText
- ld c, 140
+ ld c, 152
.next2
call DelayFrames
jr .nextCreditsScreen
-.showCopyrightText
- push de
- callba 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 + $600
lb bc, BANK(TheEndGfx), (TheEndGfxEnd - TheEndGfx) / $10
@@ -258,8 +288,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, $ff
+ add hl, bc
+ call PlaceString
+ pop hl
+ ld bc, SCREEN_WIDTH * 2
+ add hl, bc
+ ret
INCLUDE "data/credits_order.asm"
diff --git a/engine/add_mon.asm b/engine/add_mon.asm
index b2feeb12..40b776d4 100644
--- a/engine/add_mon.asm
+++ b/engine/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, [wcf91]
+ cp KADABRA
+ jr nz, .skipGivingTwistedSpoon
+ ld a, $60 ; twistedspoon in gen 2
+ ld [de], a
+.skipGivingTwistedSpoon
ld hl, wMonHMoves
ld a, [hli]
inc de
diff --git a/engine/animated_objects_3e.asm b/engine/animated_objects_3e.asm
new file mode 100755
index 00000000..2373e19e
--- /dev/null
+++ b/engine/animated_objects_3e.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, wOAMBuffer / $100
+.deinit_unused_oam_loop
+ ld a, l
+ cp wOAMBufferEnd % $100
+ 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, wOAMBuffer / $100
+ 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 wOAMBufferEnd % $100
+ 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 6, [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 5, [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 $e0
+ ld b, a
+ ld a, [hl]
+ and $10
+ or b
+ bit 4, a
+ ret z
+ or $4
+ 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/bank30.bin b/engine/bank30.bin
new file mode 100644
index 00000000..6309c149
--- /dev/null
+++ b/engine/bank30.bin
Binary files differ
diff --git a/engine/bank3c.asm b/engine/bank3c.asm
new file mode 100644
index 00000000..9c0e281f
--- /dev/null
+++ b/engine/bank3c.asm
@@ -0,0 +1,189 @@
+INCLUDE "engine/pikachu_pcm.asm"
+INCLUDE "engine/overworld/advance_player_sprite.asm"
+
+INCLUDE "engine/black_out.asm"
+
+SetMapSpecificScriptFlagsOnMapReload:
+ ld a, [wCurMap]
+ cp VERMILION_GYM ; ??? new thing about verm gym?
+ jr z, .verm_gym
+ ld c, a
+ ld hl, .MapList
+.search_loop
+ ld a, [hli]
+ cp c
+ jr z, .in_list
+ cp a, $ff
+ jr nz, .search_loop
+ ret
+
+.verm_gym
+ ld hl, wCurrentMapScriptFlags
+ set 6, [hl]
+ ret
+
+.in_list
+ ld hl, wCurrentMapScriptFlags
+ set 5, [hl]
+ ret
+
+.MapList
+ db SILPH_CO_2F
+ db SILPH_CO_3F
+ db SILPH_CO_4F
+ db SILPH_CO_5F
+ db SILPH_CO_6F
+ db SILPH_CO_7F
+ db SILPH_CO_8F
+ db SILPH_CO_9F
+ db SILPH_CO_10F
+ db SILPH_CO_11F
+ db POKEMON_MANSION_2F
+ db POKEMON_MANSION_3F
+ db POKEMON_MANSION_B1F
+ db POKEMON_MANSION_1F
+ db CINNABAR_GYM
+ db GAME_CORNER
+ db ROCKET_HIDEOUT_B1F
+ db ROCKET_HIDEOUT_B4F
+ db VICTORY_ROAD_3F
+ db VICTORY_ROAD_1F
+ db VICTORY_ROAD_2F
+ db LANCES_ROOM
+ db LORELEIS_ROOM
+ db BRUNOS_ROOM
+ db AGATHAS_ROOM
+ db $ff
+
+BeachHouse_GFX:
+ INCBIN "gfx/tilesets/beachhouse.2bpp"
+ ds 384
+
+BeachHouse_Block:
+ INCBIN "gfx/blocksets/beachhouse.bst"
+
+Func_f0a54:
+ ret
+
+LoadUnusedBluesHouseMissableObjectData:
+; referenced in an unused function
+ ld hl, .MissableObjectsMaps
+.loop
+ ld a, [hli]
+ cp a, $ff
+ 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, wMissableObjectList
+ call CopyData
+ ret
+
+.MissableObjectsMaps:
+ dbbw BLUES_HOUSE, .End - .Start, .Start
+ db $ff
+
+.Start:
+ db 1, HS_DAISY_SITTING_COPY
+ db 2, HS_DAISY_WALKING_COPY
+ db 3, HS_TOWN_MAP_COPY
+ db $ff
+.End:
+
+TryApplyPikachuMovementData:
+ ld a, [wd472]
+ bit 7, a
+ ret z
+ ld a, [wWalkBikeSurfState]
+ and a
+ ret nz
+ push hl
+ push bc
+ callab 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
+ callab LoadPikachuShadowIntoVRAM
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ pop hl
+ call ApplyPikachuMovementData
+ callab RefreshPikachuFollow
+ ret
+
+Pic_f0abf:
+INCBIN "gfx/pikachu/unknown_f0abf.pic"
+GFX_f0b64:
+INCBIN "gfx/pikachu/unknown_f0b64.2bpp"
+Pic_f0cf4:
+INCBIN "gfx/pikachu/unknown_f0cf4.pic"
+GFX_f0d82:
+INCBIN "gfx/pikachu/unknown_f0d82.2bpp"
+
+PokecenterChanseyText:
+ ld hl, NurseChanseyText
+ call PrintText
+ ld a, CHANSEY
+ call PlayCry
+ call WaitForSoundToFinish
+ ret
+
+NurseChanseyText:
+ TX_FAR _NurseChanseyText
+ db "@"
+
+INCLUDE "engine/HoF_room_pc.asm"
+INCLUDE "scripts/ViridianCity2.asm"
+INCLUDE "scripts/VermilionCity2.asm"
+INCLUDE "scripts/CeladonCity2.asm"
+INCLUDE "scripts/Route1_2.asm"
+INCLUDE "scripts/Route22_2.asm"
+INCLUDE "scripts/RedsHouse1F2.asm"
+INCLUDE "scripts/OaksLab2.asm"
+INCLUDE "scripts/ViridianSchoolHouse2.asm"
+INCLUDE "scripts/Museum1F2.asm"
+INCLUDE "scripts/PewterPokecenter2.asm"
+INCLUDE "scripts/PokemonTower2F_2.asm"
+INCLUDE "scripts/CeladonMart3F_2.asm"
+INCLUDE "scripts/CeladonMansion1F_2.asm"
+INCLUDE "scripts/CeladonMansion3F_2.asm"
+INCLUDE "scripts/GameCorner2.asm"
+INCLUDE "scripts/CeladonDiner2.asm"
+INCLUDE "scripts/SafariZoneGate2.asm"
+INCLUDE "scripts/CinnabarGym3.asm"
+INCLUDE "scripts/MtMoonPokecenter2.asm"
+
+INCLUDE "data/mapHeaders/BeachHouse.asm"
+INCLUDE "scripts/BeachHouse.asm"
+BeachHouse_Blocks:
+INCBIN "maps/BeachHouse.blk"
+INCLUDE "data/mapObjects/BeachHouse.asm"
+
+INCLUDE "scripts/BeachHouse2.asm"
+INCLUDE "scripts/BillsHouse2.asm"
+INCLUDE "scripts/ViridianForest2.asm"
+INCLUDE "scripts/SSAnne2FRooms_2.asm"
+INCLUDE "scripts/SilphCo11F_2.asm"
+
+INCLUDE "engine/overworld/hidden_objects.asm"
+INCLUDE "engine/vermilion_gym_trash_cans.asm"
diff --git a/engine/bank3d.asm b/engine/bank3d.asm
new file mode 100644
index 00000000..0cfdea08
--- /dev/null
+++ b/engine/bank3d.asm
@@ -0,0 +1,495 @@
+INCLUDE "engine/battle/common_text.asm"
+INCLUDE "engine/battle/link_battle_versus_text.asm"
+INCLUDE "engine/battle/unused_stats_functions.asm"
+INCLUDE "engine/battle/scroll_draw_trainer_pic.asm"
+
+StarterPikachuBattleEntranceAnimation:
+ coord hl, 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
+
+INCLUDE "engine/battle/decrement_pp.asm"
+
+ModifyPikachuHappiness::
+ ld a, d
+ cp PIKAHAPPY_GYMLEADER
+ jr z, .checkanywhereinparty
+ cp PIKAHAPPY_WALKING
+ jr z, .checkanywhereinparty
+ push de
+ callab IsThisPartymonStarterPikachu_Party
+ pop de
+ ret nc
+ jr .proceed
+
+.checkanywhereinparty
+ push de
+ callab IsStarterPikachuInOurParty
+ 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, [wd49c]
+ 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 ; Unknown (d = 10)
+ db -10, -10, -20 ; Unknown (d = 11)
+
+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)
+
+RedPicBack: INCBIN "pic/trainer/redb.pic"
+OldManPic: INCBIN "pic/trainer/oldman.pic"
+ProfOakPicBack: INCBIN "pic/ytrainer/prof.oakb.pic"
+
+LoadYellowTitleScreenGFX:
+ ld hl, PokemonLogoGraphics
+ ld de, vChars2
+ ld bc, 115 * $10
+ ld a, BANK(PokemonLogoGraphics) ; redundant because this function is in bank3d
+ call FarCopyData
+ ld hl, YellowLogoGraphics + 35 * $10
+ ld de, vChars0 + 253 * $10
+ ld bc, 3 * $10
+ ld a, BANK(YellowLogoGraphics)
+ call FarCopyData
+ ld hl, YellowLogoGraphics + 38 * $10
+ ld de, vChars1
+ ld bc, 64 * $10
+ ld a, BANK(YellowLogoGraphics)
+ call FarCopyData
+ ld hl, YellowLogoGraphics + 102 * $10
+ ld de, vChars0 + 240 * $10
+ ld bc, 12 * $10
+ ld a, BANK(YellowLogoGraphics)
+ call FarCopyData
+ ret
+
+TitleScreen_PlacePokemonLogo:
+ coord hl, 2, 1
+ ld de, TitleScreenPokemonLogoTilemap
+ lb bc, 7, 16
+ call Bank3D_CopyBox
+ ret
+
+TitleScreen_PlacePikaSpeechBubble:
+ coord hl, 6, 4
+ ld de, TitleScreenPikaBubbleTilemap
+ lb bc, 4, 7
+ call Bank3D_CopyBox
+ coord hl, 9, 8
+ ld [hl], $64
+ inc hl
+ ld [hl], $65
+ ret
+
+TitleScreen_PlacePikachu:
+ coord hl, 4, 8
+ ld de, TitleScreenPikachuTilemap
+ lb bc, 9, 12
+ call Bank3D_CopyBox
+ coord hl, 16, 10
+ ld [hl], $96
+ coord hl, 16, 11
+ ld [hl], $9d
+ coord hl, 16, 12
+ ld [hl], $a7
+ coord hl, 16, 13
+ ld [hl], $b1
+ ld hl, TitleScreenPikachuEyesOAMData
+ ld de, wOAMBuffer
+ 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 (xy)
+ db $f4, $f4, $f4, $f4, $f4, $f4, $49, $f4, $72, $30, $f4, $f4, $f4, $f4, $f4, $f4
+ db $fd, $01, $02, $03, $04, $05, $06, $07, $08, $09, $0a, $0b, $f4, $0d, $0e, $0f
+ db $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $1a, $1b, $1c, $1d, $1e, $1f
+ db $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $2a, $2b, $2c, $2d, $2e, $2f
+ db $f4, $31, $32, $33, $34, $35, $36, $37, $38, $39, $3a, $3b, $3c, $3d, $3e, $3f
+ db $f4, $41, $42, $43, $44, $45, $46, $47, $48, $f4, $4a, $4b, $4c, $4d, $4e, $4f
+ db $f4, $6a, $6b, $6c, $6d, $f4, $f4, $f4, $f4, $f4, $f4, $6e, $6f, $70, $71, $f4
+
+Pointer_f4669:
+; Unreferenced
+ db $47, $48, $49, $4a, $4b, $4c, $4d, $4e, $4f, $5f
+
+TitleScreenPikaBubbleTilemap:
+; 7x4 (xy)
+ db $24, $25, $66, $67, $68, $69, $2a
+ db $50, $51, $52, $53, $54, $55, $56
+ db $57, $58, $59, $5a, $5b, $5c, $5d
+ db $6d, $5e, $5f, $60, $61, $62, $63
+
+TitleScreenPikachuTilemap:
+; 12x9 (xy)
+ db $80, $81, $82, $83, $00, $00, $00, $00, $84, $85, $86, $87
+ db $88, $89, $8a, $8b, $8c, $8d, $8d, $8e, $8f, $8a, $90, $91
+ db $00, $92, $93, $8a, $8a, $8a, $8a, $8a, $8a, $94, $95, $00
+ db $00, $00, $97, $8a, $8a, $98, $99, $8a, $8a, $9a, $9b, $9c
+ db $00, $00, $9e, $9f, $a0, $a1, $a2, $a3, $a4, $a5, $a6, $8a
+ db $00, $a8, $a9, $aa, $8a, $ab, $ac, $8a, $ad, $ae, $af, $b0
+ db $00, $b2, $b3, $b4, $8a, $8a, $8a, $8a, $b5, $b6, $b7, $b8
+ db $00, $b9, $ba, $8a, $8a, $8a, $8a, $8a, $8a, $bb, $bc, $00
+ db $00, $00, $bd, $8a, $8a, $8a, $8a, $8a, $8a, $be, $bf, $00
+
+PokemonLogoGraphics: INCBIN "gfx/pokemon_logo.2bpp"
+PokemonLogoGraphicsEnd:
+YellowLogoGraphics: INCBIN "gfx/yellow_titlescreen.2bpp"
+YellowLogoGraphicsEnd:
+
+INCLUDE "engine/menu/link_menu.asm"
+
+HandleMenuInputDouble:
+ xor a
+ ld [wPartyMenuAnimMonEnabled], a
+
+HandleMenuInputPokemonSelectionDouble:
+ ld a, [H_DOWNARROWBLINKCNT1]
+ push af
+ ld a, [H_DOWNARROWBLINKCNT2]
+ push af ; save existing values on stack
+ xor a
+ ld [H_DOWNARROWBLINKCNT1], a ; blinking down arrow timing value 1
+ ld a, $06
+ ld [H_DOWNARROWBLINKCNT2], a ; blinking down arrow timing value 2
+.loop1
+ xor a
+ ld [wAnimCounter], a ; counter for pokemon shaking animation
+ call .UpdateCursorTile
+ call JoypadLowSensitivity
+ ld a, [hJoy5]
+ and a ; was a key pressed?
+ jr nz, .keyPressed
+ pop af
+ ld [H_DOWNARROWBLINKCNT2], a
+ pop af
+ ld [H_DOWNARROWBLINKCNT1], a ; restore previous values
+ xor a
+ ld [wMenuWrappingEnabled], a ; disable menu wrapping
+ ret
+.keyPressed
+ xor a
+ ld [wCheckFor180DegreeTurn], a
+ ld a, [hJoy5]
+ ld b, a
+ bit 6, a ; pressed Up key?
+ 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 7, 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
+ ld a, [hJoy5]
+ and A_BUTTON | B_BUTTON
+ jr z, .skipPlayingSound
+.AButtonOrBButtonPressed
+ ld a, SFX_PRESS_AB
+ call PlaySound ; play sound
+.skipPlayingSound
+ pop af
+ ld [H_DOWNARROWBLINKCNT2], a
+ pop af
+ ld [H_DOWNARROWBLINKCNT1], a ; restore previous values
+ ld a, [hJoy5]
+ ret
+
+.UpdateCursorTile:
+ ld a, [wTopMenuItemY]
+ and a
+ jr z, .asm_f5ac0
+ coord hl, 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
+
+INCLUDE "engine/overworld/field_move_messages.asm"
+
+INCLUDE "engine/items/inventory.asm"
+
+TrainerInfoTextBoxTileGraphics: INCBIN "gfx/trainer_info.2bpp"
+TrainerInfoTextBoxTileGraphicsEnd:
+BlankLeaderNames: INCBIN "gfx/blank_leader_names.2bpp"
+CircleTile: INCBIN "gfx/circle_tile.2bpp"
+BadgeNumbersTileGraphics: INCBIN "gfx/badge_numbers.2bpp"
+
+ReadSuperRodData:
+ ld a, [wCurMap]
+ ld c, a
+ ld hl, FishingSlots
+.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/super_rod.asm"
+INCLUDE "engine/battle/bank3d_battle.asm"
+INCLUDE "engine/items/tm_prices.asm"
+INCLUDE "engine/multiply_divide.asm"
+INCLUDE "engine/give_pokemon.asm"
+INCLUDE "engine/battle/get_trainer_name.asm"
+INCLUDE "engine/random.asm"
+INCLUDE "engine/predefs.asm"
diff --git a/engine/bank3e.asm b/engine/bank3e.asm
new file mode 100644
index 00000000..32f5ebfd
--- /dev/null
+++ b/engine/bank3e.asm
@@ -0,0 +1,5 @@
+INCLUDE "engine/surfing_minigame.asm"
+INCLUDE "engine/yellow_intro.asm"
+INCLUDE "data/animated_objects_3e_2.asm"
+YellowIntroGraphics: INCBIN "gfx/yellow_intro.2bpp"
+INCLUDE "engine/animated_objects_3e.asm"
diff --git a/engine/bank3f.asm b/engine/bank3f.asm
new file mode 100644
index 00000000..23eadbb1
--- /dev/null
+++ b/engine/bank3f.asm
@@ -0,0 +1,23 @@
+INCLUDE "data/map_songs.asm"
+INCLUDE "data/map_header_pointers.asm"
+INCLUDE "data/map_header_banks.asm"
+INCLUDE "engine/pikachu_follow.asm"
+INCLUDE "engine/pikachu_status.asm"
+INCLUDE "engine/pikachu_emotions.asm"
+INCLUDE "engine/pikachu_movement.asm"
+INCLUDE "engine/pikachu_pic_animation.asm"
+
+Func_fe66e:
+ ret
+
+OfficerJennySprite: INCBIN "gfx/sprites/officer_jenny.2bpp"
+PikachuSprite: INCBIN "gfx/sprites/pikachu.2bpp"
+SandshrewSprite: INCBIN "gfx/sprites/sandshrew.2bpp"
+OddishSprite: INCBIN "gfx/sprites/oddish.2bpp"
+BulbasaurSprite: INCBIN "gfx/sprites/bulbasaur.2bpp"
+JigglypuffSprite: INCBIN "gfx/sprites/jigglypuff.2bpp"
+Clefairy2Sprite: INCBIN "gfx/sprites/clefairy2.2bpp"
+ChanseySprite: INCBIN "gfx/sprites/chansey.2bpp"
+SurfingPikachuSprite: INCBIN "gfx/sprites/surfing_pikachu.2bpp"
+JessieSprite: INCBIN "gfx/sprites/jessie.2bpp"
+JamesSprite: INCBIN "gfx/sprites/james.2bpp"
diff --git a/engine/battle/animations.asm b/engine/battle/animations.asm
index 74e48535..de1e67b9 100755
--- 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 [wdef5], a
ld a, [wSubAnimTransform]
dec a
jr z, .flipHorizontalAndVertical ; 1
@@ -46,13 +48,22 @@ DrawFrameBlock:
.finishCopying ; finish copying values to OAM (when [wSubAnimTransform] not 1 or 2)
add [hl] ; X offset
ld [de], a ; store X
+ cp 88
+ jr c, .asm_78056
+ ld a, [wdef5]
+ inc a
+ ld [wdef5], a
+.asm_78056
inc hl
inc de
ld a, [hli]
- add $31 ; base tile ID for battle animations
+ add a, $31 ; base tile ID for battle animations
ld [de], a ; store tile ID
inc de
ld a, [hli]
+ ld b, a
+ ld a, [wdef5]
+ or b
ld [de], a ; store flags
inc de
jp .nextTile
@@ -71,10 +82,16 @@ DrawFrameBlock:
ld a, 168
sub b ; flip X coordinate
ld [de], a ; store X
+ cp 88
+ jr c, .asm_78087
+ ld a, [wdef5]
+ inc a
+ ld [wdef5], a
+.asm_78087
inc hl
inc de
ld a, [hli]
- add $31 ; base tile ID for battle animations
+ add a, $31 ; base tile ID for battle animations
ld [de], a ; store tile ID
inc de
; toggle horizontal and vertical flip
@@ -82,15 +99,16 @@ DrawFrameBlock:
and a
ld b, OAM_VFLIP | OAM_HFLIP
jr z, .storeFlags1
- cp OAM_HFLIP
+ cp a, OAM_HFLIP
ld b, OAM_VFLIP
jr z, .storeFlags1
- cp OAM_VFLIP
+ cp a, OAM_VFLIP
ld b, OAM_HFLIP
jr z, .storeFlags1
ld b, 0
.storeFlags1
- ld a, b
+ ld a, [wdef5]
+ 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, [wdef5]
+ inc a
+ ld [wdef5], a
+.asm_780c8
inc hl
inc de
ld a, [hli]
@@ -122,6 +146,9 @@ DrawFrameBlock:
.disableHorizontalFlip
res 5, a
.storeFlags2
+ ld b, a
+ ld a, [wdef5]
+ or b
ld [de], a
inc de
.nextTile
@@ -245,11 +272,13 @@ PlayAnimation:
push af
ld a, [wAnimPalette]
ld [rOBP0], a
+ call UpdateGBCPal_OBP0
call LoadAnimationTileset
call LoadSubanimation
call PlaySubanimation
pop af
ld [rOBP0], a
+ call UpdateGBCPal_OBP0
.nextAnimationCommand
pop hl
jr .animationLoop
@@ -367,12 +396,7 @@ AnimationTileset2:
INCBIN "gfx/attack_anim_2.2bpp"
SlotMachineTiles2:
-IF DEF(_RED)
- INCBIN "gfx/red/slotmachine2.2bpp"
-ENDC
-IF DEF(_BLUE)
- INCBIN "gfx/blue/slotmachine2.2bpp"
-ENDC
+ INCBIN "gfx/slotmachine2.2bpp"
MoveAnimation:
push hl
@@ -537,6 +561,8 @@ SetAnimationPalette:
ld [rOBP0], a
ld a, $6c
ld [rOBP1], a
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
ret
.notSGB
ld a, $e4
@@ -544,6 +570,28 @@ SetAnimationPalette:
ld [rOBP0], a
ld a, $6c
ld [rOBP1], a
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
+ ret
+
+Func_78e98:
+ call SaveScreenTilesToBuffer2
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call ClearScreen
+ ld h, vBGMap0 / $100
+ call WriteLowerByteOfBGMapAndEnableBGTransfer
+ call Delay3
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call LoadScreenTilesFromBuffer2
+ ld h, vBGMap1 / $100
+
+WriteLowerByteOfBGMapAndEnableBGTransfer:
+ ld l, vBGMap0 & $ff
+ call BattleAnimCopyTileMapToVRAM
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
ret
PlaySubanimation:
@@ -691,7 +739,7 @@ AnimationIdSpecialEffects:
dw DoExplodeSpecialEffects
db SPORE
- dw AnimationFlashScreen
+ dw FlashScreenEveryFourFrameBlocks
db EXPLOSION
dw DoExplodeSpecialEffects
@@ -733,6 +781,7 @@ DoBallTossSpecialEffects:
ld a, [rOBP0]
xor %00111100 ; complement colors 1 and 2
ld [rOBP0], a
+ call UpdateGBCPal_OBP0
.skipFlashingEffect
ld a, [wSubAnimCounter]
cp 11 ; is it the beginning of the subanimation?
@@ -922,7 +971,7 @@ TradeShakePokeball:
jp PlaySound
BallMoveDistances1:
- db -12,-12,-8
+ db -12, -12, -8
db $ff ; terminator
; function to make the pokeball jump up
@@ -963,7 +1012,7 @@ TradeJumpPokeball:
jr .loop
BallMoveDistances2:
- db 11,12,-12,-7,7,12,-8,8
+ db 11, 12, -12, -7, 7, 12, -8, 8
db $ff ; terminator
; this function copies the current musical note graphic
@@ -1102,6 +1151,7 @@ AnimationFlashScreenLong:
cp $01 ; is it the end of the palettes?
jr z, .endOfPalettes
ld [rBGP], a
+ call UpdateGBCPal_BGP
call FlashScreenLongDelay
jr .innerLoop
.endOfPalettes
@@ -1164,14 +1214,17 @@ AnimationFlashScreen:
push af ; save initial palette
ld a, %00011011 ; 0, 1, 2, 3 (inverted colors)
ld [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 2
call DelayFrames
xor a ; white out background
ld [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 2
call DelayFrames
pop af
ld [rBGP], a ; restore initial palette
+ call UpdateGBCPal_BGP
ret
AnimationDarkScreenPalette:
@@ -1217,6 +1270,7 @@ SetAnimationBGPalette:
ld a, c
.next
ld [rBGP], a
+ call UpdateGBCPal_BGP
ret
ld b, $5
@@ -1261,15 +1315,30 @@ AnimationWaterDropletsEverywhere:
_AnimationWaterDroplets:
ld hl, wOAMBuffer
.loop
+ ld a, $1
+ ld [wdef5], a
ld a, [wBaseCoordY]
ld [hli], a ; Y
+ cp 40
+ jr c, .asm_792d7
+ ld a, [wdef5]
+ inc a
+ ld [wdef5], a
+.asm_792d7
ld a, [wBaseCoordX]
add 27
ld [wBaseCoordX], a
ld [hli], a ; X
+ cp 88
+ jr c, .asm_792ee
+ ld a, [wdef5]
+ add $2
+ and $3
+ ld [wdef5], a
+.asm_792ee
ld a, [wDropletTile]
ld [hli], a ; tile
- xor a
+ ld a, [wdef5]
ld [hli], a ; attribute
ld a, [wBaseCoordX]
cp 144
@@ -1412,16 +1481,30 @@ BattleAnimWriteOAMEntry:
; Y coordinate = e (increased by 8 each call, before the write to OAM)
; X coordinate = [wBaseCoordX]
; tile = d
-; attributes = 0
+; attributes = variable (dependant on coords)
+ ld a, $1
+ ld [wdef5], a
ld a, e
add 8
ld e, a
ld [hli], a
+ cp 40
+ jr c, .asm_793d8
+ ld a, [wdef5]
+ inc a
+ ld [wdef5], a
+.asm_793d8
ld a, [wBaseCoordX]
ld [hli], a
+ cp 88
+ jr c, .asm_793e8
+ ld a, [wdef5]
+ add $2
+ ld [wdef5], a
+.asm_793e8
ld a, d
ld [hli], a
- xor a
+ ld a, [wdef5]
ld [hli], a
ret
@@ -1473,7 +1556,7 @@ AdjustOAMBlockYPos2:
ret
AnimationBlinkEnemyMon:
-; Make the enemy mon's sprite blink on and off for a second or two
+ ; Make the enemy mon's sprite blink on and off for a second or two
ld hl, AnimationBlinkMon
jp CallWithTurnFlipped
@@ -1626,6 +1709,8 @@ AnimationSpiralBallsInward:
ld a, [hl]
cp $ff
jr z, .done
+ ld a, $2
+ ld [wdef5], a
ld a, [wSpiralBallsBaseY]
add [hl]
ld [de], a ; Y
@@ -1634,9 +1719,20 @@ AnimationSpiralBallsInward:
ld a, [wSpiralBallsBaseX]
add [hl]
ld [de], a ; X
+ cp 88
+ jr c, .asm_79524
+ ld a, $3
+ ld [wdef5], a
+.asm_79524
inc hl
inc de
inc de
+ ld a, [de]
+ and $f0
+ ld b, a
+ ld a, [wdef5]
+ or b
+ ld [de], a
inc de
dec c
jr nz, .innerLoop
@@ -1938,7 +2034,7 @@ _AnimationSlideMonOff:
jr nz, .slideLoop
ret
-; Since mon pic tile numbers go from top to bottom, left to right in order,
+; Since mon pic tile numbers go from top to bottom, left to right in order,
; adding the height of the mon pic in tiles to a tile number gives the tile
; number of the tile one column to the right (and thus subtracting the height
; gives the reverse). If the next tile would be past the edge of the pic, the 2
@@ -1948,10 +2044,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
@@ -2088,18 +2182,24 @@ AnimationSubstitute:
CopySlowbroSpriteData:
ld bc, $0010
ld a, BANK(SlowbroSprite)
- jp FarCopyData2
+ jp FarCopyData
HideSubstituteShowMonAnim:
ld a, [H_WHOSETURN]
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
@@ -2108,12 +2208,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
+ ld a, [H_WHOSETURN]
+ and a
+ jr nz, .enemy
+ ld a, [wPlayerMonMinimized]
+ and a
+ jr nz, .monIsMinimized
+ ld a, [wBattleMonSpecies]
+ ld [wcf91], a
+ ld [wd0b5], a
+ call GetMonHeader
+ predef LoadMonBackPic
+ ret
+.enemy
+ ld a, [wEnemyMonMinimized]
+ and a
+ jr nz, .monIsMinimized
+ ld a, [wEnemyMonSpecies]
+ ld [wcf91], a
+ ld [wd0b5], 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
@@ -2181,6 +2334,23 @@ AnimationHideEnemyMonPic:
ld [H_AUTOBGTRANSFERENABLED], a
jp Delay3
+Func_79929:
+ ld hl, wPlayerMonMinimized
+ ld a, [H_WHOSETURN]
+ 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.
@@ -2202,6 +2372,8 @@ InitMultipleObjectsOAM:
jr nz, .loop
ret
+ ret ; unreferenced
+
AnimationHideMonPic:
; Hides the mon's sprite.
ld a, [H_WHOSETURN]
@@ -2228,7 +2400,7 @@ ClearMonPicFromTileMap:
ret
; puts the tile map destination address of a mon sprite in hl, given the row count in b
-; The usual row count is 7, but it may be smaller when sliding a mon sprite in/out,
+; The usual row count is 7, but it may be smaller when sliding a mon sprite in/out,
; in order to show only a portion of the mon sprite.
GetMonSpriteTileMapPointerFromRowCount:
push de
@@ -2364,172 +2536,172 @@ IsCryMove:
MoveSoundTable:
; ID, pitch mod, tempo mod
- db SFX_POUND, $00,$80 ; POUND
- db SFX_BATTLE_0C, $10,$80 ; KARATE_CHOP
- db SFX_DOUBLESLAP, $00,$80 ; DOUBLESLAP
- db SFX_BATTLE_0B, $01,$80 ; COMET_PUNCH
- db SFX_BATTLE_0D, $00,$40 ; MEGA_PUNCH
- db SFX_SILPH_SCOPE, $00,$ff ; PAY_DAY
- db SFX_BATTLE_0D, $10,$60 ; FIRE_PUNCH
- db SFX_BATTLE_0D, $20,$80 ; ICE_PUNCH
- db SFX_BATTLE_0D, $00,$a0 ; THUNDERPUNCH
- db SFX_DAMAGE, $00,$80 ; SCRATCH
- db SFX_BATTLE_0F, $20,$40 ; VICEGRIP
- db SFX_BATTLE_0F, $00,$80 ; GUILLOTINE
- db SFX_BATTLE_0E, $00,$a0 ; RAZOR_WIND
- db SFX_NOT_VERY_EFFECTIVE,$10,$c0 ; SWORDS_DANCE
- db SFX_NOT_VERY_EFFECTIVE,$00,$a0 ; CUT
- db SFX_BATTLE_12, $00,$c0 ; GUST
- db SFX_BATTLE_12, $10,$a0 ; WING_ATTACK
- db SFX_BATTLE_13, $00,$e0 ; WHIRLWIND
- db SFX_NOT_VERY_EFFECTIVE,$20,$c0 ; FLY
- db SFX_BATTLE_14, $00,$80 ; BIND
- db SFX_BATTLE_22, $00,$80 ; SLAM
- db SFX_VINE_WHIP, $01,$80 ; VINE_WHIP
- db SFX_BATTLE_20, $00,$80 ; STOMP
- db SFX_BATTLE_17, $f0,$40 ; DOUBLE_KICK
- db SFX_SUPER_EFFECTIVE, $00,$80 ; MEGA_KICK
- db SFX_BATTLE_17, $00,$80 ; JUMP_KICK
- db SFX_BATTLE_21, $10,$80 ; ROLLING_KICK
- db SFX_BATTLE_1B, $01,$a0 ; SAND_ATTACK
- db SFX_BATTLE_18, $00,$80 ; HEADBUTT
- db SFX_BATTLE_1E, $00,$60 ; HORN_ATTACK
- db SFX_BATTLE_1E, $01,$40 ; FURY_ATTACK
- db SFX_HORN_DRILL, $00,$a0 ; HORN_DRILL
- db SFX_SUPER_EFFECTIVE, $10,$a0 ; TACKLE
- db SFX_BATTLE_20, $00,$c0 ; BODY_SLAM
- db SFX_BATTLE_14, $10,$60 ; WRAP
- db SFX_SUPER_EFFECTIVE, $00,$a0 ; TAKE_DOWN
- db SFX_BATTLE_22, $11,$c0 ; THRASH
- db SFX_SUPER_EFFECTIVE, $20,$c0 ; DOUBLE_EDGE
- db SFX_BATTLE_21, $00,$80 ; TAIL_WHIP
- db SFX_BATTLE_1B, $00,$80 ; POISON_STING
- db SFX_BATTLE_1B, $20,$c0 ; TWINEEDLE
- db SFX_BATTLE_19, $00,$80 ; PIN_MISSILE
- db SFX_BATTLE_31, $ff,$40 ; LEER
- db SFX_BATTLE_1E, $00,$80 ; BITE
- db SFX_BATTLE_0B, $00,$c0 ; GROWL
- db SFX_BATTLE_0B, $00,$40 ; ROAR
- db SFX_BATTLE_35, $00,$80 ; SING
- db SFX_BATTLE_27, $40,$60 ; SUPERSONIC
- db SFX_BATTLE_27, $00,$80 ; SONICBOOM
- db SFX_BATTLE_27, $ff,$40 ; DISABLE
- db SFX_BATTLE_2A, $80,$c0 ; ACID
- db SFX_BATTLE_19, $10,$a0 ; EMBER
- db SFX_BATTLE_19, $21,$e0 ; FLAMETHROWER
- db SFX_BATTLE_29, $00,$80 ; MIST
- db SFX_BATTLE_24, $20,$60 ; WATER_GUN
- db SFX_BATTLE_2A, $00,$80 ; HYDRO_PUMP
- db SFX_BATTLE_2C, $00,$80 ; SURF
- db SFX_BATTLE_28, $40,$80 ; ICE_BEAM
- db SFX_BATTLE_29, $f0,$e0 ; BLIZZARD
- db SFX_PSYBEAM, $00,$80 ; PSYBEAM
- db SFX_BATTLE_2A, $f0,$60 ; BUBBLEBEAM
- db SFX_BATTLE_28, $00,$80 ; AURORA_BEAM
- db SFX_BATTLE_36, $00,$80 ; HYPER_BEAM
- db SFX_PECK,$01, $a0 ; PECK
- db SFX_BATTLE_13, $f0,$20 ; DRILL_PECK
- db SFX_BATTLE_23, $01,$c0 ; SUBMISSION
- db SFX_BATTLE_23, $00,$80 ; LOW_KICK
- db SFX_SUPER_EFFECTIVE, $00,$e0 ; COUNTER
- db SFX_BATTLE_26, $01,$60 ; SEISMIC_TOSS
- db SFX_BATTLE_26, $20,$40 ; STRENGTH
- db SFX_BATTLE_24, $00,$80 ; ABSORB
- db SFX_BATTLE_24, $40,$c0 ; MEGA_DRAIN
- db SFX_BATTLE_1B, $03,$60 ; LEECH_SEED
- db SFX_BATTLE_25, $11,$e0 ; GROWTH
- db SFX_BATTLE_12, $20,$e0 ; RAZOR_LEAF
- db SFX_BATTLE_2E, $00,$80 ; SOLARBEAM
- db SFX_BATTLE_1C, $00,$80 ; POISONPOWDER
- db SFX_BATTLE_1C, $11,$a0 ; STUN_SPORE
- db SFX_BATTLE_1C, $01,$c0 ; SLEEP_POWDER
- db SFX_BATTLE_13, $14,$c0 ; PETAL_DANCE
- db SFX_BATTLE_1B, $02,$a0 ; STRING_SHOT
- db SFX_BATTLE_29, $f0,$80 ; DRAGON_RAGE
- db SFX_BATTLE_29, $20,$c0 ; FIRE_SPIN
- db SFX_BATTLE_2F, $00,$20 ; THUNDERSHOCK
- db SFX_BATTLE_2F, $20,$80 ; THUNDERBOLT
- db SFX_BATTLE_2E, $12,$60 ; THUNDER_WAVE
- db SFX_BATTLE_26, $00,$80 ; THUNDER
- db SFX_BATTLE_14, $01,$e0 ; ROCK_THROW
- db SFX_BATTLE_29, $0f,$e0 ; EARTHQUAKE
- db SFX_BATTLE_29, $11,$20 ; FISSURE
- db SFX_DAMAGE, $10,$40 ; DIG
- db SFX_BATTLE_0F, $10,$c0 ; TOXIC
- db SFX_BATTLE_14, $00,$20 ; CONFUSION
- db SFX_PSYCHIC_M, $00,$80 ; PSYCHIC_M
- db SFX_BATTLE_35, $11,$18 ; HYPNOSIS
- db SFX_BATTLE_09, $20,$c0 ; MEDITATE
- db SFX_FAINT_FALL, $20,$c0 ; AGILITY
- db SFX_BATTLE_25, $00,$10 ; QUICK_ATTACK
- db SFX_BATTLE_26, $f0,$20 ; RAGE
- db SFX_BATTLE_33, $f0,$c0 ; TELEPORT
- db SFX_NOT_VERY_EFFECTIVE,$f0,$e0 ; NIGHT_SHADE
- db SFX_BATTLE_09, $f0,$40 ; MIMIC
- db SFX_BATTLE_31, $00,$80 ; SCREECH
- db SFX_BATTLE_33, $80,$40 ; DOUBLE_TEAM
- db SFX_BATTLE_33, $00,$80 ; RECOVER
- db SFX_BATTLE_14, $11,$20 ; HARDEN
- db SFX_BATTLE_14, $22,$10 ; MINIMIZE
- db SFX_BATTLE_1B, $f1,$ff ; SMOKESCREEN
- db SFX_BATTLE_13, $f1,$ff ; CONFUSE_RAY
- db SFX_BATTLE_14, $33,$30 ; WITHDRAW
- db SFX_BATTLE_32, $40,$c0 ; DEFENSE_CURL
- db SFX_BATTLE_0E, $20,$20 ; BARRIER
- db SFX_BATTLE_0E, $f0,$10 ; LIGHT_SCREEN
- db SFX_BATTLE_0F, $f8,$10 ; HAZE
- db SFX_NOT_VERY_EFFECTIVE,$f0,$10 ; REFLECT
- db SFX_BATTLE_25, $00,$80 ; FOCUS_ENERGY
- db SFX_BATTLE_18, $00,$c0 ; BIDE
- db SFX_BATTLE_32, $c0,$ff ; METRONOME
- db SFX_BATTLE_09, $f2,$20 ; MIRROR_MOVE
- db SFX_BATTLE_34, $00,$80 ; SELFDESTRUCT
- db SFX_BATTLE_34, $00,$40 ; EGG_BOMB
- db SFX_BATTLE_09, $00,$40 ; LICK
- db SFX_NOT_VERY_EFFECTIVE,$10,$ff ; SMOG
- db SFX_BATTLE_2A, $20,$20 ; SLUDGE
- db SFX_BATTLE_32, $00,$80 ; BONE_CLUB
- db SFX_BATTLE_29, $1f,$20 ; FIRE_BLAST
- db SFX_BATTLE_25, $2f,$80 ; WATERFALL
- db SFX_BATTLE_0F, $1f,$ff ; CLAMP
- db SFX_BATTLE_2B, $1f,$60 ; SWIFT
- db SFX_BATTLE_26, $1e,$20 ; SKULL_BASH
- db SFX_BATTLE_26, $1f,$18 ; SPIKE_CANNON
- db SFX_BATTLE_14, $0f,$80 ; CONSTRICT
- db SFX_BATTLE_09, $f8,$10 ; AMNESIA
- db SFX_FAINT_FALL, $18,$20 ; KINESIS
- db SFX_BATTLE_32, $08,$40 ; SOFTBOILED
- db SFX_BATTLE_17, $01,$e0 ; HI_JUMP_KICK
- db SFX_NOT_VERY_EFFECTIVE,$09,$ff ; GLARE
- db SFX_BATTLE_35, $42,$01 ; DREAM_EATER
- db SFX_BATTLE_1C, $00,$ff ; POISON_GAS
- db SFX_BATTLE_32, $08,$e0 ; BARRAGE
- db SFX_BATTLE_24, $00,$80 ; LEECH_LIFE
- db SFX_BATTLE_09, $88,$10 ; LOVELY_KISS
- db SFX_BATTLE_25, $48,$ff ; SKY_ATTACK
- db SFX_FAINT_FALL, $ff,$ff ; TRANSFORM
- db SFX_BATTLE_24, $ff,$10 ; BUBBLE
- db SFX_FAINT_FALL, $ff,$04 ; DIZZY_PUNCH
- db SFX_BATTLE_1C, $01,$ff ; SPORE
- db SFX_BATTLE_13, $f8,$ff ; FLASH
- db SFX_BATTLE_0C, $f0,$f0 ; PSYWAVE
- db SFX_BATTLE_0F, $08,$10 ; SPLASH
- db SFX_BATTLE_0D, $f0,$ff ; ACID_ARMOR
- db SFX_SUPER_EFFECTIVE, $f0,$ff ; CRABHAMMER
- db SFX_BATTLE_34, $10,$ff ; EXPLOSION
- db SFX_BATTLE_0E, $f0,$20 ; FURY_SWIPES
- db SFX_BATTLE_2B, $f0,$60 ; BONEMERANG
- db SFX_BATTLE_21, $12,$10 ; REST
- db SFX_BATTLE_36, $f0,$20 ; ROCK_SLIDE
- db SFX_BATTLE_1E, $12,$ff ; HYPER_FANG
- db SFX_BATTLE_31, $80,$04 ; SHARPEN
- db SFX_BATTLE_33, $f0,$10 ; CONVERSION
- db SFX_BATTLE_29, $f8,$ff ; TRI_ATTACK
- db SFX_BATTLE_26, $f0,$ff ; SUPER_FANG
- db SFX_NOT_VERY_EFFECTIVE,$01,$ff ; SLASH
- db SFX_BATTLE_2C, $d8,$04 ; SUBSTITUTE
- db SFX_BATTLE_0B, $00,$80 ; STRUGGLE
- db SFX_BATTLE_0B, $00,$80
+ db SFX_POUND, $00, $80 ; POUND
+ db SFX_BATTLE_0C, $10, $80 ; KARATE_CHOP
+ db SFX_DOUBLESLAP, $00, $80 ; DOUBLESLAP
+ db SFX_BATTLE_0B, $01, $80 ; COMET_PUNCH
+ db SFX_BATTLE_0D, $00, $40 ; MEGA_PUNCH
+ db SFX_SILPH_SCOPE, $00, $ff ; PAY_DAY
+ db SFX_BATTLE_0D, $10, $60 ; FIRE_PUNCH
+ db SFX_BATTLE_0D, $20, $80 ; ICE_PUNCH
+ db SFX_BATTLE_0D, $00, $a0 ; THUNDERPUNCH
+ db SFX_DAMAGE, $00, $80 ; SCRATCH
+ db SFX_BATTLE_0F, $20, $40 ; VICEGRIP
+ db SFX_BATTLE_0F, $00, $80 ; GUILLOTINE
+ db SFX_BATTLE_0E, $00, $a0 ; RAZOR_WIND
+ db SFX_NOT_VERY_EFFECTIVE, $10, $c0 ; SWORDS_DANCE
+ db SFX_NOT_VERY_EFFECTIVE, $00, $a0 ; CUT
+ db SFX_BATTLE_12, $00, $c0 ; GUST
+ db SFX_BATTLE_12, $10, $a0 ; WING_ATTACK
+ db SFX_BATTLE_13, $00, $e0 ; WHIRLWIND
+ db SFX_NOT_VERY_EFFECTIVE, $20, $c0 ; FLY
+ db SFX_BATTLE_14, $00, $80 ; BIND
+ db SFX_BATTLE_22, $00, $80 ; SLAM
+ db SFX_VINE_WHIP, $01, $80 ; VINE_WHIP
+ db SFX_BATTLE_20, $00, $80 ; STOMP
+ db SFX_BATTLE_17, $f0, $40 ; DOUBLE_KICK
+ db SFX_SUPER_EFFECTIVE, $00, $80 ; MEGA_KICK
+ db SFX_BATTLE_17, $00, $80 ; JUMP_KICK
+ db SFX_BATTLE_21, $10, $80 ; ROLLING_KICK
+ db SFX_BATTLE_1B, $01, $a0 ; SAND_ATTACK
+ db SFX_BATTLE_18, $00, $80 ; HEADBUTT
+ db SFX_BATTLE_1E, $00, $60 ; HORN_ATTACK
+ db SFX_BATTLE_1E, $01, $40 ; FURY_ATTACK
+ db SFX_HORN_DRILL, $00, $a0 ; HORN_DRILL
+ db SFX_SUPER_EFFECTIVE, $10, $a0 ; TACKLE
+ db SFX_BATTLE_20, $00, $c0 ; BODY_SLAM
+ db SFX_BATTLE_14, $10, $60 ; WRAP
+ db SFX_SUPER_EFFECTIVE, $00, $a0 ; TAKE_DOWN
+ db SFX_BATTLE_22, $11, $c0 ; THRASH
+ db SFX_SUPER_EFFECTIVE, $20, $c0 ; DOUBLE_EDGE
+ db SFX_BATTLE_21, $00, $80 ; TAIL_WHIP
+ db SFX_BATTLE_1B, $00, $80 ; POISON_STING
+ db SFX_BATTLE_1B, $20, $c0 ; TWINEEDLE
+ db SFX_BATTLE_19, $00, $80 ; PIN_MISSILE
+ db SFX_BATTLE_31, $ff, $40 ; LEER
+ db SFX_BATTLE_1E, $00, $80 ; BITE
+ db SFX_BATTLE_0B, $00, $c0 ; GROWL
+ db SFX_BATTLE_0B, $00, $40 ; ROAR
+ db SFX_BATTLE_35, $00, $80 ; SING
+ db SFX_BATTLE_27, $40, $60 ; SUPERSONIC
+ db SFX_BATTLE_27, $00, $80 ; SONICBOOM
+ db SFX_BATTLE_27, $ff, $40 ; DISABLE
+ db SFX_BATTLE_2A, $80, $c0 ; ACID
+ db SFX_BATTLE_19, $10, $a0 ; EMBER
+ db SFX_BATTLE_19, $21, $e0 ; FLAMETHROWER
+ db SFX_BATTLE_29, $00, $80 ; MIST
+ db SFX_BATTLE_24, $20, $60 ; WATER_GUN
+ db SFX_BATTLE_2A, $00, $80 ; HYDRO_PUMP
+ db SFX_BATTLE_2C, $00, $80 ; SURF
+ db SFX_BATTLE_28, $40, $80 ; ICE_BEAM
+ db SFX_BATTLE_29, $f0, $e0 ; BLIZZARD
+ db SFX_PSYBEAM, $00, $80 ; PSYBEAM
+ db SFX_BATTLE_2A, $f0, $60 ; BUBBLEBEAM
+ db SFX_BATTLE_28, $00, $80 ; AURORA_BEAM
+ db SFX_BATTLE_36, $00, $80 ; HYPER_BEAM
+ db SFX_PECK, $01, $a0 ; PECK
+ db SFX_BATTLE_13, $f0, $20 ; DRILL_PECK
+ db SFX_BATTLE_23, $01, $c0 ; SUBMISSION
+ db SFX_BATTLE_23, $00, $80 ; LOW_KICK
+ db SFX_SUPER_EFFECTIVE, $00, $e0 ; COUNTER
+ db SFX_BATTLE_26, $01, $60 ; SEISMIC_TOSS
+ db SFX_BATTLE_26, $20, $40 ; STRENGTH
+ db SFX_BATTLE_24, $00, $80 ; ABSORB
+ db SFX_BATTLE_24, $40, $c0 ; MEGA_DRAIN
+ db SFX_BATTLE_1B, $03, $60 ; LEECH_SEED
+ db SFX_BATTLE_25, $11, $e0 ; GROWTH
+ db SFX_BATTLE_12, $20, $e0 ; RAZOR_LEAF
+ db SFX_BATTLE_2E, $00, $80 ; SOLARBEAM
+ db SFX_BATTLE_1C, $00, $80 ; POISONPOWDER
+ db SFX_BATTLE_1C, $11, $a0 ; STUN_SPORE
+ db SFX_BATTLE_1C, $01, $c0 ; SLEEP_POWDER
+ db SFX_BATTLE_13, $14, $c0 ; PETAL_DANCE
+ db SFX_BATTLE_1B, $02, $a0 ; STRING_SHOT
+ db SFX_BATTLE_29, $f0, $80 ; DRAGON_RAGE
+ db SFX_BATTLE_29, $20, $c0 ; FIRE_SPIN
+ db SFX_BATTLE_2F, $00, $20 ; THUNDERSHOCK
+ db SFX_BATTLE_2F, $20, $80 ; THUNDERBOLT
+ db SFX_BATTLE_2E, $12, $60 ; THUNDER_WAVE
+ db SFX_BATTLE_26, $00, $80 ; THUNDER
+ db SFX_BATTLE_14, $01, $e0 ; ROCK_THROW
+ db SFX_BATTLE_29, $0f, $e0 ; EARTHQUAKE
+ db SFX_BATTLE_29, $11, $20 ; FISSURE
+ db SFX_DAMAGE, $10, $40 ; DIG
+ db SFX_BATTLE_0F, $10, $c0 ; TOXIC
+ db SFX_BATTLE_14, $00, $20 ; CONFUSION
+ db SFX_PSYCHIC_M, $00, $80 ; PSYCHIC_M
+ db SFX_BATTLE_35, $11, $18 ; HYPNOSIS
+ db SFX_BATTLE_09, $20, $c0 ; MEDITATE
+ db SFX_FAINT_FALL, $20, $c0 ; AGILITY
+ db SFX_BATTLE_25, $00, $10 ; QUICK_ATTACK
+ db SFX_BATTLE_26, $f0, $20 ; RAGE
+ db SFX_BATTLE_33, $f0, $c0 ; TELEPORT
+ db SFX_NOT_VERY_EFFECTIVE, $f0, $e0 ; NIGHT_SHADE
+ db SFX_BATTLE_09, $f0, $40 ; MIMIC
+ db SFX_BATTLE_31, $00, $80 ; SCREECH
+ db SFX_BATTLE_33, $80, $40 ; DOUBLE_TEAM
+ db SFX_BATTLE_33, $00, $80 ; RECOVER
+ db SFX_BATTLE_14, $11, $20 ; HARDEN
+ db SFX_BATTLE_14, $22, $10 ; MINIMIZE
+ db SFX_BATTLE_1B, $f1, $ff ; SMOKESCREEN
+ db SFX_BATTLE_13, $f1, $ff ; CONFUSE_RAY
+ db SFX_BATTLE_14, $33, $30 ; WITHDRAW
+ db SFX_BATTLE_32, $40, $c0 ; DEFENSE_CURL
+ db SFX_BATTLE_0E, $20, $20 ; BARRIER
+ db SFX_BATTLE_0E, $f0, $10 ; LIGHT_SCREEN
+ db SFX_BATTLE_0F, $f8, $10 ; HAZE
+ db SFX_NOT_VERY_EFFECTIVE, $f0, $10 ; REFLECT
+ db SFX_BATTLE_25, $00, $80 ; FOCUS_ENERGY
+ db SFX_BATTLE_18, $00, $c0 ; BIDE
+ db SFX_BATTLE_32, $c0, $ff ; METRONOME
+ db SFX_BATTLE_09, $f2, $20 ; MIRROR_MOVE
+ db SFX_BATTLE_34, $00, $80 ; SELFDESTRUCT
+ db SFX_BATTLE_34, $00, $40 ; EGG_BOMB
+ db SFX_BATTLE_09, $00, $40 ; LICK
+ db SFX_NOT_VERY_EFFECTIVE, $10, $ff ; SMOG
+ db SFX_BATTLE_2A, $20, $20 ; SLUDGE
+ db SFX_BATTLE_32, $00, $80 ; BONE_CLUB
+ db SFX_BATTLE_29, $1f, $20 ; FIRE_BLAST
+ db SFX_BATTLE_25, $2f, $80 ; WATERFALL
+ db SFX_BATTLE_0F, $1f, $ff ; CLAMP
+ db SFX_BATTLE_2B, $1f, $60 ; SWIFT
+ db SFX_BATTLE_26, $1e, $20 ; SKULL_BASH
+ db SFX_BATTLE_26, $1f, $18 ; SPIKE_CANNON
+ db SFX_BATTLE_14, $0f, $80 ; CONSTRICT
+ db SFX_BATTLE_09, $f8, $10 ; AMNESIA
+ db SFX_FAINT_FALL, $18, $20 ; KINESIS
+ db SFX_BATTLE_32, $08, $40 ; SOFTBOILED
+ db SFX_BATTLE_17, $01, $e0 ; HI_JUMP_KICK
+ db SFX_NOT_VERY_EFFECTIVE, $09, $ff ; GLARE
+ db SFX_BATTLE_35, $42, $01 ; DREAM_EATER
+ db SFX_BATTLE_1C, $00, $ff ; POISON_GAS
+ db SFX_BATTLE_32, $08, $e0 ; BARRAGE
+ db SFX_BATTLE_24, $00, $80 ; LEECH_LIFE
+ db SFX_BATTLE_09, $88, $10 ; LOVELY_KISS
+ db SFX_BATTLE_25, $48, $ff ; SKY_ATTACK
+ db SFX_FAINT_FALL, $ff, $ff ; TRANSFORM
+ db SFX_BATTLE_24, $ff, $10 ; BUBBLE
+ db SFX_FAINT_FALL, $ff, $04 ; DIZZY_PUNCH
+ db SFX_BATTLE_1C, $01, $ff ; SPORE
+ db SFX_BATTLE_13, $f8, $ff ; FLASH
+ db SFX_BATTLE_0C, $f0, $f0 ; PSYWAVE
+ db SFX_BATTLE_0F, $08, $10 ; SPLASH
+ db SFX_BATTLE_0D, $f0, $ff ; ACID_ARMOR
+ db SFX_SUPER_EFFECTIVE, $f0, $ff ; CRABHAMMER
+ db SFX_BATTLE_34, $10, $ff ; EXPLOSION
+ db SFX_BATTLE_0E, $f0, $20 ; FURY_SWIPES
+ db SFX_BATTLE_2B, $f0, $60 ; BONEMERANG
+ db SFX_BATTLE_21, $12, $10 ; REST
+ db SFX_BATTLE_36, $f0, $20 ; ROCK_SLIDE
+ db SFX_BATTLE_1E, $12, $ff ; HYPER_FANG
+ db SFX_BATTLE_31, $80, $04 ; SHARPEN
+ db SFX_BATTLE_33, $f0, $10 ; CONVERSION
+ db SFX_BATTLE_29, $f8, $ff ; TRI_ATTACK
+ db SFX_BATTLE_26, $f0, $ff ; SUPER_FANG
+ db SFX_NOT_VERY_EFFECTIVE, $01, $ff ; SLASH
+ db SFX_BATTLE_2C, $d8, $04 ; SUBSTITUTE
+ db SFX_BATTLE_0B, $00, $80 ; STRUGGLE
+ db SFX_BATTLE_0B, $00, $80
CopyPicTiles:
ld a, [H_WHOSETURN]
@@ -2587,112 +2759,108 @@ CopyTileIDs:
ret
TileIDListPointerTable:
- dw Unknown_79b24
- dn 7, 7
- dw Unknown_79b55
- dn 5, 7
- dw Unknown_79b78
- dn 3, 7
+ dw DownscaledMonTiles_7x7
+ dn 7, 7
+ dw DownscaledMonTiles_5x7
+ dn 5, 7
+ dw DownscaledMonTiles_3x7
+ dn 3, 7
dw GengarIntroTiles1
- dn 7, 7
+ dn 7, 7
dw GengarIntroTiles2
- dn 7, 7
+ dn 7, 7
dw GengarIntroTiles3
- dn 7, 7
- dw Unknown_79c20
- dn 8, 6
- dw Unknown_79c50
- dn 3, 12
+ dn 7, 7
+ dw DownscaledMonTiles_79d7c
+ dn 8, 6
+ dw DownscaledMonTiles_79dac
+ dn 3, 12
DownscaledMonTiles_5x5:
- db $31,$38,$46,$54,$5B
- db $32,$39,$47,$55,$5C
- db $34,$3B,$49,$57,$5E
- db $36,$3D,$4B,$59,$60
- db $37,$3E,$4C,$5A,$61
+ db $31, $38, $46, $54, $5B
+ db $32, $39, $47, $55, $5C
+ db $34, $3B, $49, $57, $5E
+ db $36, $3D, $4B, $59, $60
+ db $37, $3E, $4C, $5A, $61
DownscaledMonTiles_3x3:
- db $31,$46,$5B
- db $34,$49,$5E
- db $37,$4C,$61
-
-Unknown_79b24:
- db $00,$07,$0E,$15,$1C,$23,$2A
- db $01,$08,$0F,$16,$1D,$24,$2B
- db $02,$09,$10,$17,$1E,$25,$2C
- db $03,$0A,$11,$18,$1F,$26,$2D
- db $04,$0B,$12,$19,$20,$27,$2E
- db $05,$0C,$13,$1A,$21,$28,$2F
- db $06,$0D,$14,$1B,$22,$29,$30
-
-Unknown_79b55:
- db $00,$07,$0E,$15,$1C,$23,$2A
- db $01,$08,$0F,$16,$1D,$24,$2B
- db $03,$0A,$11,$18,$1F,$26,$2D
- db $04,$0B,$12,$19,$20,$27,$2E
- db $05,$0C,$13,$1A,$21,$28,$2F
-
-Unknown_79b78:
- db $00,$07,$0E,$15,$1C,$23,$2A
- db $02,$09,$10,$17,$1E,$25,$2C
- db $04,$0B,$12,$19,$20,$27,$2E
+ db $31, $46, $5B
+ db $34, $49, $5E
+ db $37, $4C, $61
+
+DownscaledMonTiles_7x7:
+ db $00, $07, $0E, $15, $1C, $23, $2A
+ db $01, $08, $0F, $16, $1D, $24, $2B
+ db $02, $09, $10, $17, $1E, $25, $2C
+ db $03, $0A, $11, $18, $1F, $26, $2D
+ db $04, $0B, $12, $19, $20, $27, $2E
+ db $05, $0C, $13, $1A, $21, $28, $2F
+ db $06, $0D, $14, $1B, $22, $29, $30
+
+DownscaledMonTiles_5x7:
+ db $00, $07, $0E, $15, $1C, $23, $2A
+ db $01, $08, $0F, $16, $1D, $24, $2B
+ db $03, $0A, $11, $18, $1F, $26, $2D
+ db $04, $0B, $12, $19, $20, $27, $2E
+ db $05, $0C, $13, $1A, $21, $28, $2F
+
+DownscaledMonTiles_3x7:
+ db $00, $07, $0E, $15, $1C, $23, $2A
+ db $02, $09, $10, $17, $1E, $25, $2C
+ db $04, $0B, $12, $19, $20, $27, $2E
GengarIntroTiles1:
- db $00,$00,$00,$00,$00,$00,$00
- db $00,$00,$00,$00,$00,$19,$00
- db $02,$06,$0B,$10,$14,$1A,$00
- db $00,$07,$0C,$11,$15,$1B,$00
- db $03,$08,$0D,$12,$16,$1C,$00
- db $04,$09,$0E,$13,$17,$1D,$1F
- db $05,$0A,$0F,$01,$18,$1E,$20
+ db $00, $00, $00, $00, $00, $00, $00
+ db $00, $00, $00, $00, $00, $19, $00
+ db $02, $06, $0B, $10, $14, $1A, $00
+ db $00, $07, $0C, $11, $15, $1B, $00
+ db $03, $08, $0D, $12, $16, $1C, $00
+ db $04, $09, $0E, $13, $17, $1D, $1F
+ db $05, $0A, $0F, $01, $18, $1E, $20
GengarIntroTiles2:
- db $00,$00,$00,$30,$00,$37,$00
- db $00,$00,$2B,$31,$34,$38,$3D
- db $21,$26,$2C,$01,$35,$39,$3E
- db $22,$27,$2D,$32,$36,$01,$00
- db $23,$28,$2E,$33,$01,$3A,$00
- db $24,$29,$2F,$01,$01,$3B,$00
- db $25,$2A,$01,$01,$01,$3C,$00
+ db $00, $00, $00, $30, $00, $37, $00
+ db $00, $00, $2B, $31, $34, $38, $3D
+ db $21, $26, $2C, $01, $35, $39, $3E
+ db $22, $27, $2D, $32, $36, $01, $00
+ db $23, $28, $2E, $33, $01, $3A, $00
+ db $24, $29, $2F, $01, $01, $3B, $00
+ db $25, $2A, $01, $01, $01, $3C, $00
GengarIntroTiles3:
- db $00,$00,$00,$00,$00,$00,$00
- db $00,$00,$47,$4D,$00,$00,$00
- db $00,$00,$48,$4E,$52,$56,$5B
- db $3F,$43,$49,$4F,$53,$57,$5C
- db $40,$44,$4A,$50,$54,$58,$00
- db $41,$45,$4B,$51,$4C,$59,$5D
- db $42,$46,$4C,$4C,$55,$5A,$5E
-
-Unknown_79c20:
- db $31,$32,$32,$32,$32,$33
- db $34,$35,$36,$36,$37,$38
- db $34,$39,$3A,$3A,$3B,$38
- db $3C,$3D,$3E,$3E,$3F,$40
- db $41,$42,$43,$43,$44,$45
- db $46,$47,$43,$48,$49,$4A
- db $41,$43,$4B,$4C,$4D,$4E
- db $4F,$50,$50,$50,$51,$52
-
-Unknown_79c50:
- db $43,$55,$56,$53,$53,$53,$53,$53,$53,$53,$53,$53
- db $43,$57,$58,$54,$54,$54,$54,$54,$54,$54,$54,$54
- db $43,$59,$5A,$43,$43,$43,$43,$43,$43,$43,$43,$43
+ db $00, $00, $00, $00, $00, $00, $00
+ db $00, $00, $47, $4D, $00, $00, $00
+ db $00, $00, $48, $4E, $52, $56, $5B
+ db $3F, $43, $49, $4F, $53, $57, $5C
+ db $40, $44, $4A, $50, $54, $58, $00
+ db $41, $45, $4B, $51, $4C, $59, $5D
+ db $42, $46, $4C, $4C, $55, $5A, $5E
+
+DownscaledMonTiles_79d7c:
+ db $31, $32, $32, $32, $32, $33
+ db $34, $35, $36, $36, $37, $38
+ db $34, $39, $3A, $3A, $3B, $38
+ db $3C, $3D, $3E, $3E, $3F, $40
+ db $41, $42, $43, $43, $44, $45
+ db $46, $47, $43, $48, $49, $4A
+ db $41, $43, $4B, $4C, $4D, $4E
+ db $4F, $50, $50, $50, $51, $52
+
+DownscaledMonTiles_79dac:
+ db $43, $55, $56, $53, $53, $53, $53, $53, $53, $53, $53, $53
+ db $43, $57, $58, $54, $54, $54, $54, $54, $54, $54, $54, $54
+ db $43, $59, $5A, $43, $43, $43, $43, $43, $43, $43, $43, $43
AnimationLeavesFalling:
; Makes leaves float down from the top of the screen. This is used
; in Razor Leaf's animation.
- ld a, [rOBP0]
- push af
ld a, [wAnimPalette]
ld [rOBP0], a
+ call UpdateGBCPal_OBP0
ld d, $37 ; leaf tile
ld a, 3 ; number of leaves
ld [wNumFallingObjects], a
- call AnimationFallingObjects
- pop af
- ld [rOBP0], a
- ret
+ jp AnimationFallingObjects
AnimationPetalsFalling:
; Makes lots of petals fall down from the top of the screen. It's used in
@@ -2747,6 +2915,8 @@ FallingObjects_UpdateOAMEntry:
; movement byte.
ld hl, wOAMBuffer
add hl, de
+ ld a, $1
+ ld [wdef5], a
ld a, [hl]
inc a
inc a
@@ -2755,6 +2925,12 @@ FallingObjects_UpdateOAMEntry:
ld a, 160 ; if Y >= 112, put it off-screen
.next
ld [hli], a ; Y
+ cp 40
+ jr c, .asm_79e51
+ ld a, [wdef5]
+ inc a
+ ld [wdef5], a
+.asm_79e51
ld a, [wFallingObjectMovementByte]
ld b, a
ld de, FallingObjects_DeltaXs
@@ -2771,6 +2947,13 @@ FallingObjects_UpdateOAMEntry:
ld a, [de]
add [hl]
ld [hli], a ; X
+ cp 88
+ jr c, .asm_79e75
+ ld a, [wdef5]
+ add $2
+ and $3
+ ld [wdef5], a
+.asm_79e75
inc hl
xor a ; no horizontal flip
jr .next2
@@ -2780,9 +2963,19 @@ FallingObjects_UpdateOAMEntry:
ld a, [hl]
sub b
ld [hli], a ; X
+ cp 88
+ jr c, .asm_79e5c
+ ld a, [wdef5]
+ add $2
+ and $3
+ ld [wdef5], a
+.asm_79e5c
inc hl
ld a, (1 << OAM_X_FLIP)
.next2
+ ld b, a
+ ld a, [wdef5]
+ or b
ld [hl], a ; attribute
ret
@@ -2822,7 +3015,7 @@ FallingObjects_InitXCoords:
ret
FallingObjects_InitialXCoords:
- db $38,$40,$50,$60,$70,$88,$90,$56,$67,$4A,$77,$84,$98,$32,$22,$5C,$6C,$7D,$8E,$99
+ db $38, $40, $50, $60, $70, $88, $90, $56, $67, $4A, $77, $84, $98, $32, $22, $5C, $6C, $7D, $8E, $99
FallingObjects_InitMovementData:
ld hl, wFallingObjectsMovementData
@@ -2838,7 +3031,7 @@ FallingObjects_InitMovementData:
ret
FallingObjects_InitialMovementData:
- db $00,$84,$06,$81,$02,$88,$01,$83,$05,$89,$09,$80,$07,$87,$03,$82,$04,$85,$08,$86
+ db $00, $84, $06, $81, $02, $88, $01, $83, $05, $89, $09, $80, $07, $87, $03, $82, $04, $85, $08, $86
AnimationShakeEnemyHUD:
; Shakes the enemy HUD.
@@ -2867,6 +3060,14 @@ AnimationShakeEnemyHUD:
ld hl, vBGMap1 - $20 * 7
call BattleAnimCopyTileMapToVRAM
+; update BGMap attributes
+ ld a, [hGBC]
+ and a
+ jr z, .notGBC
+ ld c, 13
+ callba LoadBGMapAttributes
+.notGBC
+
; 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
@@ -2900,13 +3101,18 @@ AnimationShakeEnemyHUD:
ld [hWY], a
ld hl, vBGMap1
call BattleAnimCopyTileMapToVRAM
+; update BGMap attributes
+ ld a, [hGBC]
+ and a
+ jr z, .notGBC2
+ ld c, 11
+ callba LoadBGMapAttributes
+.notGBC2
xor a
ld [hWY], a
call SaveScreenTilesToBuffer1
ld hl, vBGMap0
call BattleAnimCopyTileMapToVRAM
- call ClearScreen
- call Delay3
call LoadScreenTilesFromBuffer1
ld hl, vBGMap1
jp BattleAnimCopyTileMapToVRAM
@@ -2995,7 +3201,7 @@ TossBallAnimation:
.PokeBallAnimations:
; sequence of animations that make up the Poké Ball toss
- db POOF_ANIM,HIDEPIC_ANIM,SHAKE_ANIM,POOF_ANIM,SHOWPIC_ANIM
+ db POOF_ANIM, HIDEPIC_ANIM, SHAKE_ANIM, POOF_ANIM, SHOWPIC_ANIM
.BlockBall
ld a, TOSS_ANIM
diff --git a/engine/battle/bank3d_battle.asm b/engine/battle/bank3d_battle.asm
new file mode 100644
index 00000000..0cf24fe1
--- /dev/null
+++ b/engine/battle/bank3d_battle.asm
@@ -0,0 +1,291 @@
+InitBattle:
+ ld a, [wCurOpponent]
+ and a
+ jr z, asm_f6003
+
+InitOpponent:
+ ld a, [wCurOpponent]
+ ld [wcf91], a
+ ld [wEnemyMonSpecies2], a
+ jr asm_f601d
+asm_f6003:
+ ld a, [wd732]
+ bit 1, a
+ jr z, .asm_f600f
+ ld a, [hJoyHeld]
+ bit 1, a ; B button pressed?
+ ret nz
+.asm_f600f
+ ld a, [wNumberOfNoRandomBattleStepsLeft]
+ and a
+ ret nz
+ callab TryDoWildEncounter
+ ret nz
+asm_f601d:
+ ld a, [wMapPalOffset]
+ push af
+ ld hl, wLetterPrintingDelayFlags
+ ld a, [hl]
+ push af
+ res 1, [hl]
+ call InitBattleVariables
+ ld a, [wEnemyMonSpecies2]
+ sub OPP_ID_OFFSET
+ jp c, InitWildBattle
+ ld [wTrainerClass], a
+ call GetTrainerInformation
+ callab ReadTrainer
+ callab DoBattleTransitionAndInitBattleVariables
+ call _LoadTrainerPic
+ xor a
+ ld [wEnemyMonSpecies2], a
+ ld [$ffe1], a
+ dec a
+ ld [wAICount], a
+ coord hl, 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,InitBattle_Common
+ callabd_ModifyPikachuHappiness PIKAHAPPY_GYMLEADER ; useless since already in bank3d
+ jp InitBattle_Common
+
+InitWildBattle:
+ ld a, $1
+ ld [wIsInBattle], a
+ callab LoadEnemyMonData
+ callab DoBattleTransitionAndInitBattleVariables
+ ld a, [wCurOpponent]
+ cp MAROWAK
+ jr z, .isGhost
+ callab 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 a, "G"
+ ld [hli], a
+ ld a, "H"
+ ld [hli], a
+ ld a, "O"
+ ld [hli], a
+ ld a, "S"
+ ld [hli], a
+ ld a, "T"
+ ld [hli], a
+ ld [hl], "@"
+ ld a, [wcf91]
+ push af
+ ld a, MON_GHOST
+ ld [wcf91], a
+ ld de, vFrontPic
+ call LoadMonFrontSprite ; load ghost sprite
+ pop af
+ ld [wcf91], a
+ jr .spriteLoaded
+.isNoGhost
+ ld de, vFrontPic
+ call LoadMonFrontSprite ; load mon sprite
+.spriteLoaded
+ xor a
+ ld [wTrainerClass], a
+ ld [$ffe1], a
+ coord hl, 12, 0
+ predef CopyUncompressedPicToTilemap
+
+; common code that executes after init battle code specific to trainer or wild battles
+InitBattle_Common:
+ ld b, $0
+ call RunPaletteCommand
+ callab SlidePlayerAndEnemySilhouettesOnScreen
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld hl, .emptyString
+ call PrintText
+ call SaveScreenTilesToBuffer1
+ call ClearScreen
+ ld a, $98
+ ld [$ffbd], a
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Delay3
+ ld a, $9c
+ ld [$ffbd], a
+ call LoadScreenTilesFromBuffer1
+ coord hl, 9, 7
+ ld bc, $50a
+ call ClearScreenArea
+ coord hl, 1, 0
+ ld bc, $40a
+ 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
+ callab StartBattle
+ callab EndOfBattle
+ pop af
+ ld [wLetterPrintingDelayFlags], a
+ pop af
+ ld [wMapPalOffset], a
+ ld a, [wSavedTilesetType]
+ ld [hTilesetType], a
+ scf
+ ret
+.emptyString
+ db "@"
+
+_LoadTrainerPic:
+; wd033-wd034 contain pointer to pic
+ 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(TrainerPics) ; this is where all the trainer pics are (not counting Red's)
+ 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 [wcf91], a
+ coord hl, 1, 5
+ ld bc,$708
+ 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
+ ld a, [H_LOADEDROMBANK]
+ ld b, a
+ jp CopyVideoData
+
+AnimateSendingOutMon:
+ ld a, [wPredefRegisters]
+ ld h, a
+ ld a, [wPredefRegisters + 1]
+ ld l, a
+ ld a, [$ffe1]
+ ld [H_DOWNARROWBLINKCNT1], a
+ ld b, $4c
+ ld a, [wIsInBattle]
+ and a
+ jr z, .asm_f61ef
+ add b
+ ld [hl], a
+ call Delay3
+ ld bc, -41
+ add hl, bc
+ ld a, $1
+ ld [wNumMovesMinusOne], a
+ ld bc, $303
+ predef CopyDownscaledMonTiles
+ ld c, $4
+ call DelayFrames
+ ld bc, -41
+ add hl, bc
+ xor a
+ ld [wNumMovesMinusOne], a
+ ld bc, $505
+ predef CopyDownscaledMonTiles
+ ld c, $5
+ call DelayFrames
+ ld bc, -41
+ jr .asm_f61f2
+.asm_f61ef
+ ld bc, -123
+.asm_f61f2
+ add hl, bc
+ ld a, [H_DOWNARROWBLINKCNT1]
+ add $31
+ jr CopyUncompressedPicToHL
+
+CopyUncompressedPicToTilemap:
+ ld a, [wPredefRegisters]
+ ld h, a
+ ld a, [wPredefRegisters + 1]
+ ld l, a
+ ld a, [$ffe1]
+CopyUncompressedPicToHL:
+ ld bc, $707
+ ld de, $14
+ push af
+ ld a, [wSpriteFlipped]
+ and a
+ jr nz, .asm_f6220
+ pop af
+.asm_f6211
+ push bc
+ push hl
+.asm_f6213
+ ld [hl], a
+ add hl, de
+ inc a
+ dec c
+ jr nz, .asm_f6213
+ pop hl
+ inc hl
+ pop bc
+ dec b
+ jr nz, .asm_f6211
+ ret
+
+.asm_f6220
+ push bc
+ ld b, $0
+ dec c
+ add hl, bc
+ pop bc
+ pop af
+.asm_f6227
+ push bc
+ push hl
+.asm_f6229
+ ld [hl], a
+ add hl, de
+ inc a
+ dec c
+ jr nz, .asm_f6229
+ pop hl
+ dec hl
+ pop bc
+ dec b
+ jr nz, .asm_f6227
+ ret
+
+INCLUDE "engine/battle/init_battle_variables.asm"
+INCLUDE "engine/battle/moveEffects/focus_energy_effect.asm"
+INCLUDE "engine/battle/moveEffects/heal_effect.asm"
+INCLUDE "engine/battle/moveEffects/transform_effect.asm"
+INCLUDE "engine/battle/moveEffects/reflect_light_screen_effect.asm"
+INCLUDE "engine/battle/moveEffects/mist_effect.asm"
+INCLUDE "engine/battle/moveEffects/one_hit_ko_effect.asm"
+INCLUDE "engine/battle/moveEffects/pay_day_effect.asm"
+INCLUDE "engine/battle/moveEffects/paralyze_effect.asm"
diff --git a/engine/battle/bank_e_misc.asm b/engine/battle/bank_e_misc.asm
index 33af6f6f..df9145f2 100755
--- a/engine/battle/bank_e_misc.asm
+++ b/engine/battle/bank_e_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, wEnemyPartyMons
-.getSpecies
- ld d, 0
- add hl, de
- ld a, [hl]
- ld [wcf91], a
- ret
diff --git a/engine/battle/battle_transitions.asm b/engine/battle/battle_transitions.asm
index 436e38b5..e4392a01 100644
--- a/engine/battle/battle_transitions.asm
+++ b/engine/battle/battle_transitions.asm
@@ -196,6 +196,9 @@ BattleTransition_BlackScreen:
ld [rBGP], a
ld [rOBP0], a
ld [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
ret
; for non-dungeon trainer battles
@@ -359,6 +362,7 @@ BattleTransition_FlashScreen_:
cp $1
jr z, .done
ld [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 2
call DelayFrames
jr .loop
@@ -373,7 +377,7 @@ BattleTransition_FlashScreenPalettes:
; used for low level trainer dungeon battles
BattleTransition_Shrink:
- ld c, SCREEN_HEIGHT / 2
+ ld c, 9
.loop
push bc
xor a
@@ -407,7 +411,7 @@ BattleTransition_Shrink:
; used for high level trainer dungeon battles
BattleTransition_Split:
- ld c, SCREEN_HEIGHT / 2
+ ld c, 9
xor a
ld [H_AUTOBGTRANSFERENABLED], a
.loop
diff --git a/engine/battle/common_text.asm b/engine/battle/common_text.asm
index 4a138048..e8f4f002 100644
--- a/engine/battle/common_text.asm
+++ b/engine/battle/common_text.asm
@@ -8,8 +8,20 @@ PrintBeginningBattleText:
cp MR_FUJIS_HOUSE
jr c, .pokemonTower
.notPokemonTower
+ ld a,[wBattleType]
+ cp BATTLE_TYPE_PIKACHU
+ jr nz,.notPikachuBattle
+ callab IsPlayerPikachuAsleepInParty
+ ld e,$24
+ jr c,.asm_f4026
+ ld e,$a
+.asm_f4026
+ callab 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
callab DrawAllPokeballs
pop hl
+.doNotDrawPokeballs
call PrintText
jr .done
.pokemonTower
diff --git a/engine/battle/core.asm b/engine/battle/core.asm
index 2b00a812..60146902 100755
--- a/engine/battle/core.asm
+++ b/engine/battle/core.asm
@@ -157,6 +157,9 @@ SlidePlayerAndEnemySilhouettesOnScreen:
ld [rBGP], a
ld [rOBP0], a
ld [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
.slideSilhouettesLoop ; slide silhouettes of the player's pic and the enemy's pic onto the screen
ld h, b
ld l, $40
@@ -246,10 +249,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?
@@ -983,6 +992,11 @@ ReplaceFaintedEnemyMon:
ld hl, wEnemyHPBarColor
ld e, $30
call GetBattleHealthBarColor
+ setpal SHADE_BLACK, SHADE_DARK, SHADE_LIGHT, SHADE_WHITE
+ ld [rOBP0], a
+ ld [rOBP1], a
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
callab DrawEnemyPokeballs
ld a, [wLinkState]
cp LINK_STATE_BATTLING
@@ -1048,9 +1062,7 @@ TrainerDefeatedText:
PlayBattleVictoryMusic:
push af
- ld a, $ff
- ld [wNewSoundID], a
- call PlaySoundWaitForCurrent
+ call StopAllMusic
ld c, BANK(Music_DefeatedTrainer)
pop af
call PlayMusic
@@ -1104,6 +1116,7 @@ RemoveFaintedPlayerMon:
ld a, $ff
ld [wLowHealthAlarm], a ;disable low health alarm
call WaitForSoundToFinish
+ xor a
.skipWaitForSound
; a is 0, so this zeroes the enemy's accumulated damage.
ld hl, wEnemyBideAccumulatedDamage
@@ -1128,10 +1141,36 @@ RemoveFaintedPlayerMon:
and a ; was this called by HandleEnemyMonFainted?
ret z ; if so, return
+ ld a, [wPlayerMonNumber]
+ ld [wWhichPokemon], a
+ callab IsThisPartymonStarterPikachu_Party
+ jr nc, .notPlayerPikachu
+ ld e, $3
+ callab 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
+ callabd_ModifyPikachuHappiness PIKAHAPPY_FAINTED
+ ret
+.carelessTrainer
+ callabd_ModifyPikachuHappiness PIKAHAPPY_CARELESSTRAINER
+ ret
PlayerMonFaintedText:
TX_FAR _PlayerMonFaintedText
@@ -1188,7 +1227,7 @@ ChooseNextMon:
ld a, [wLinkState]
cp LINK_STATE_BATTLING
jr nz, .notLinkBattle
- inc a
+ ld a, 1
ld [wActionResultOrTookBattleTurn], a
call LinkBattleExchangeData
.notLinkBattle
@@ -1588,6 +1627,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
@@ -1843,19 +1884,46 @@ SendOutMon:
call RunPaletteCommand
ld hl, wEnemyBattleStatus1
res USING_TRAPPING_MOVE, [hl]
+ callab IsThisPartymonStarterPikachu
+ jr c, .starterPikachu
ld a, $1
ld [H_WHOSETURN], a
ld a, POOF_ANIM
call PlayMoveAnimation
coord hl, 4, 11
predef AnimateSendingOutMon
+ jr .playRegularCry
+.starterPikachu
+ xor a
+ ld [H_WHOSETURN], a
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ callab StarterPikachuBattleEntranceAnimation
+ callab IsPlayerPikachuAsleepInParty
+ ld e, $24
+ jr c, .asm_3cd81
+ ld e, $a
+.asm_3cd81
+ callab PlayPikachuSoundClip
+ jr .done
+.playRegularCry
ld a, [wcf91]
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
+ callab IsThisPartymonStarterPikachu
+ pop bc
+ ld a, b
+ ld [wWhichPokemon], a
+ jr c, .starterPikachu
coord hl, 1, 5
lb bc, 7, 7
call ClearScreenArea
@@ -1879,10 +1947,17 @@ AnimateRetreatingPlayerMon:
call .clearScreenArea
ld a, $4c
Coorda 5, 11
+ jr .clearScreenArea
+.starterPikachu
+ xor a
+ ld [H_WHOSETURN], a
+ callab AnimationSlideMonOff
+ ret
.clearScreenArea
coord hl, 1, 5
lb bc, 7, 7
- jp ClearScreenArea
+ call ClearScreenArea
+ ret
; reads player's current mon's HP into wBattleMonHP
ReadPlayerMonCurHPAndStatus:
@@ -2104,36 +2179,49 @@ DisplayBattleMenu:
ld [wTextBoxID], a
call DisplayTextBoxID
ld a, [wBattleType]
- dec a
- jp nz, .handleBattleMenuInput ; handle menu input if it's not the old man tutorial
-; the following happens for the old man tutorial
+ cp BATTLE_TYPE_OLD_MAN
+ jr z, .doSimulatedMenuInput ; simulate menu input if it's the old man or prof. oak pikachu battle
+ cp BATTLE_TYPE_PIKACHU
+ jr z, .doSimulatedMenuInput
+ jp .handleBattleMenuInput
+; the following happens for the old man tutorial and prof. oak pikachu battle
+.doSimulatedMenuInput
ld hl, wPlayerName
ld de, wGrassRate
ld bc, NAME_LENGTH
call CopyData ; temporarily save the player name in unused space,
; which is supposed to get overwritten when entering a
- ; map with wild Pokémon. Due to an oversight, the data
+ ; map with wild Pokémon.
+ ; In Red/Blue, due to an oversight, the data
; may not get overwritten (cinnabar) and the infamous
- ; Missingno. glitch can show up.
+ ; Missingno. glitch can show up. However,
+ ; this has been fixed in yellow
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
coord hl, 9, 14
ld [hl], "▶"
- ld c, 80
+ ld c, 20
call DelayFrames
ld [hl], " "
coord hl, 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
@@ -2216,6 +2304,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
@@ -2247,7 +2338,18 @@ DisplayBattleMenu:
.throwSafariBallWasSelected
ld a, SAFARI_BALL
ld [wcf91], a
- jr UseBagItem
+ jp UseBagItem
+.handleUnusedBattle
+ ld a, [wCurrentMenuItem]
+ cp $3
+ jp z, BattleMenu_RunWasSelected
+ ld hl, .RunAwayText
+ call PrintText
+ jp DisplayBattleMenu
+
+.RunAwayText
+ TX_FAR _RunAwayText
+ db "@"
.upperLeftMenuItemWasNotSelected ; a menu item other than the upper left item was selected
cp $2
@@ -2284,19 +2386,23 @@ 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:
- db 1 ; # items
- db POKE_BALL, 50
- db -1
+SimulatedInputBattleItemList:
+ db 1 ; # of items
+ db POKE_BALL, 1
+ db $ff
DisplayPlayerBag:
; get the pointer to player's bag when in a normal battle
@@ -2455,6 +2561,8 @@ PartyMenuOrRockOrRun:
predef StatusScreen
predef StatusScreen2
; now we need to reload the enemy mon pic
+ ld a, 1
+ ld [H_WHOSETURN], a
ld a, [wEnemyBattleStatus2]
bit HAS_SUBSTITUTE_UP, a ; does the enemy mon have a substitute?
ld hl, AnimationSubstitute
@@ -2559,13 +2667,13 @@ MoveSelectionMenu:
.writemoves
ld de, wMovesString
- ld a, [hFlags_0xFFF6]
+ ld a, [hFlags_0xFFFA]
set 2, a
- ld [hFlags_0xFFF6], a
+ ld [hFlags_0xFFFA], a
call PlaceString
- ld a, [hFlags_0xFFF6]
+ ld a, [hFlags_0xFFFA]
res 2, a
- ld [hFlags_0xFFF6], a
+ ld [hFlags_0xFFFA], a
ret
.regularmenu
@@ -2574,9 +2682,8 @@ MoveSelectionMenu:
ld hl, wBattleMonMoves
call .loadmoves
coord hl, 4, 12
- ld b, 4
- ld c, 14
- di ; out of pure coincidence, it is possible for vblank to occur between the di and ei
+ 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
coord hl, 4, 12
@@ -2593,8 +2700,7 @@ MoveSelectionMenu:
ld hl, wEnemyMonMoves
call .loadmoves
coord hl, 0, 7
- ld b, 4
- ld c, 14
+ lb bc, 4, 14
call TextBoxBorder
coord hl, 2, 8
call .writemoves
@@ -2608,8 +2714,7 @@ MoveSelectionMenu:
call AddNTimes
call .loadmoves
coord hl, 4, 7
- ld b, 4
- ld c, 14
+ lb bc, 4, 14
call TextBoxBorder
coord hl, 6, 8
call .writemoves
@@ -2623,8 +2728,6 @@ MoveSelectionMenu:
ld a, [wMoveMenuType]
cp $1
jr z, .selectedmoveknown
- ld a, $1
- jr nc, .selectedmoveknown
ld a, [wPlayerMoveListIndex]
inc a
.selectedmoveknown
@@ -2685,10 +2788,10 @@ SelectMenuItem:
call AddNTimes
ld [hl], "▷"
.select
- ld hl, hFlags_0xFFF6
+ ld hl, hFlags_0xFFFA
set 1, [hl]
call HandleMenuInput
- ld hl, hFlags_0xFFF6
+ ld hl, hFlags_0xFFFA
res 1, [hl]
bit 6, a
jp nz, SelectMenuItem_CursorUp ; up
@@ -2790,6 +2893,55 @@ SelectMenuItem_CursorDown:
ld [wCurrentMenuItem], a
jp SelectMenuItem
+Func_3d4f5:
+ bit 3, a
+ ld a, $0
+ jr nz, .asm_3d4fd
+ ld a, $1
+.asm_3d4fd
+ ld [H_WHOSETURN], a
+ call LoadScreenTilesFromBuffer1
+ call Func_3d536
+ ld a, [wTestBattlePlayerSelectedMove]
+ and a
+ jp z, MoveSelectionMenu
+ ld [wAnimationID], a
+ xor a
+ ld [wAnimationType], a
+ predef MoveAnimation
+ callab 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:
+ coord hl, 10, 16
+ lb bc, 2, 10
+ call ClearScreenArea
+ coord hl, 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 [wd11e], a
+ call GetMoveName
+ coord hl, 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
@@ -2823,7 +2975,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
@@ -2838,6 +2993,9 @@ NoMovesLeftText:
db "@"
SwapMovesInMenu:
+ ld a, [wPlayerBattleStatus3]
+ bit TRANSFORMED, a
+ jp nz, MoveSelectionMenu
ld a, [wMenuItemToSwap]
and a
jr z, .noMenuItemSelected
@@ -2917,8 +3075,7 @@ PrintMenuItem:
xor a
ld [H_AUTOBGTRANSFERENABLED], a
coord hl, 0, 8
- ld b, 3
- ld c, 9
+ lb bc, 3, 9
call TextBoxBorder
ld a, [wPlayerDisabledMove]
and a
@@ -2985,7 +3142,7 @@ PrintMenuItem:
jp Delay3
DisabledText:
- db "disabled!@"
+ db "Disabled!@"
TypeText:
db "TYPE@"
@@ -3905,11 +4062,13 @@ DetermineExclamationPointTextNum:
ret
ExclamationPointMoveSets:
+; a grammar mistake was fixed (only concerning japanese)
+; BIDE is in category 3, moved from category 2
db SWORDS_DANCE, GROWTH
db $00
- db RECOVER, BIDE, SELFDESTRUCT, AMNESIA
+ db RECOVER, SELFDESTRUCT, AMNESIA
db $00
- db MEDITATE, AGILITY, TELEPORT, MIMIC, DOUBLE_TEAM, BARRAGE
+ db MEDITATE, AGILITY, TELEPORT, MIMIC, DOUBLE_TEAM, BIDE, BARRAGE
db $00
db POUND, SCRATCH, VICEGRIP, WING_ATTACK, FLY, BIND, SLAM, HORN_ATTACK, BODY_SLAM
db WRAP, THRASH, TAIL_WHIP, LEER, BITE, GROWL, ROAR, SING, PECK, COUNTER
@@ -4593,31 +4752,31 @@ CalculateDamage:
ld a, [H_QUOTIENT + 3]
add b
ld [H_QUOTIENT + 3], a
- jr nc, .asm_3dfd0
+ jr nc, .asm_3e142
ld a, [H_QUOTIENT + 2]
inc a
ld [H_QUOTIENT + 2], a
and a
- jr z, .asm_3e004
+ jr z, .asm_3e176
-.asm_3dfd0
+.asm_3e142
ld a, [H_QUOTIENT]
ld b, a
ld a, [H_QUOTIENT + 1]
or a
- jr nz, .asm_3e004
+ jr nz, .asm_3e176
ld a, [H_QUOTIENT + 2]
cp 998 / $100
- jr c, .asm_3dfe8
+ jr c, .asm_3e15a
cp 998 / $100 + 1
- jr nc, .asm_3e004
+ jr nc, .asm_3e176
ld a, [H_QUOTIENT + 3]
cp 998 % $100
- jr nc, .asm_3e004
+ jr nc, .asm_3e176
-.asm_3dfe8
+.asm_3e15a
inc hl
ld a, [H_QUOTIENT + 3]
ld b, [hl]
@@ -4628,26 +4787,26 @@ CalculateDamage:
ld b, [hl]
adc b
ld [hl], a
- jr c, .asm_3e004
+ jr c, .asm_3e176
ld a, [hl]
cp 998 / $100
- jr c, .asm_3e00a
+ jr c, .asm_3e17c
cp 998 / $100 + 1
- jr nc, .asm_3e004
+ jr nc, .asm_3e176
inc hl
ld a, [hld]
cp 998 % $100
- jr c, .asm_3e00a
+ jr c, .asm_3e17c
-.asm_3e004
+.asm_3e176
; cap at 997
ld a, 997 / $100
ld [hli], a
ld a, 997 % $100
ld [hld], a
-.asm_3e00a
+.asm_3e17c
; add 2
inc hl
ld a, [hl]
@@ -4677,7 +4836,7 @@ UnusedHighCriticalMoves:
db $FF
; determines if attack is a critical hit
-; azure heights claims "the fastest pokémon (who are,not coincidentally,
+; azure heights claims "the fastest pokémon (who are, not coincidentally,
; among the most popular) tend to CH about 20 to 25% of the time."
CriticalHitTest:
xor a
@@ -5098,7 +5257,7 @@ AttackSubstitute:
ld a, [H_WHOSETURN]
xor $01
ld [H_WHOSETURN], a
- callab HideSubstituteShowMonAnim ; animate the substitute breaking
+ callab Func_79929 ; animate the substitute breaking
; flip the turn back to the way it was
ld a, [H_WHOSETURN]
xor $01
@@ -5395,32 +5554,26 @@ AdjustDamageForMoveType:
.done
ret
-; function to tell how effective the type of an enemy attack is on the player's current pokemon
-; this doesn't take into account the effects that dual types can have
-; (e.g. 4x weakness / resistance, weaknesses and resistances canceling)
-; the result is stored in [wTypeEffectiveness]
-; ($05 is not very effective, $10 is neutral, $14 is super effective)
-; as far is can tell, this is only used once in some AI code to help decide which move to use
AIGetTypeEffectiveness:
ld a, [wEnemyMoveType]
- ld d, a ; d = type of enemy move
+ ld d, a ; d = type of enemy move
ld hl, wBattleMonType
- ld b, [hl] ; b = type 1 of player's pokemon
+ ld b, [hl] ; b = type 1 of player's pokemon
inc hl
- ld c, [hl] ; c = type 2 of player's pokemon
+ ld c, [hl] ; c = type 2 of player's pokemon
ld a, $10
- ld [wTypeEffectiveness], a ; initialize to neutral effectiveness
+ ld [wd11e], a ; initialize [wd11e] to neutral effectiveness
ld hl, TypeEffects
.loop
ld a, [hli]
cp $ff
ret z
- cp d ; match the type of the move
+ cp d ; match the type of the move
jr nz, .nextTypePair1
ld a, [hli]
- cp b ; match with type 1 of pokemon
+ cp b ; match with type 1 of pokemon
jr z, .done
- cp c ; or match with type 2 of pokemon
+ cp c ; or match with type 2 of pokemon
jr z, .done
jr .nextTypePair2
.nextTypePair1
@@ -5428,9 +5581,21 @@ AIGetTypeEffectiveness:
.nextTypePair2
inc hl
jr .loop
+
.done
+ 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
+ ld [wd11e], a ; store damage multiplier
ret
INCLUDE "data/type_effects.asm"
@@ -6409,10 +6574,13 @@ 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, OldManPic
+ 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)
call UncompressSpriteFromDE
@@ -6437,6 +6605,8 @@ LoadPlayerBackPic:
ld [hli], a ; OAM tile number
inc a ; increment tile number
ld [hOAMTile], a
+ ld a, $2
+ ld [hl], a
inc hl
dec c
jr nz, .innerLoop
@@ -6450,18 +6620,15 @@ LoadPlayerBackPic:
jr nz, .loop
ld de, vBackPic
call InterlaceMergeSpriteBuffers
- ld a, $a
- ld [$0], a
- xor a
- ld [$4000], a
+ ld a, $0
+ call SwitchSRAMBankAndLatchClockData
ld hl, vSprites
ld de, sSpriteBuffer1
ld a, [H_LOADEDROMBANK]
ld b, a
ld c, 7 * 7
call CopyVideoData
- xor a
- ld [$0], a
+ call PrepareRTCDataAndDisableSRAM
ld a, $31
ld [hStartTileID], a
coord hl, 1, 5
@@ -6832,292 +6999,10 @@ HandleExplodingAnimation:
PlayMoveAnimation:
ld [wAnimationID], a
call Delay3
- predef_jump MoveAnimation
-
-InitBattle:
- ld a, [wCurOpponent]
- and a
- jr z, DetermineWildOpponent
-
-InitOpponent:
- ld a, [wCurOpponent]
- ld [wcf91], a
- ld [wEnemyMonSpecies2], a
- jr InitBattleCommon
-
-DetermineWildOpponent:
- ld a, [wd732]
- bit 1, a
- jr z, .asm_3ef2f
- ld a, [hJoyHeld]
- bit 1, a ; B button pressed?
- ret nz
-.asm_3ef2f
- ld a, [wNumberOfNoRandomBattleStepsLeft]
- and a
- ret nz
- callab TryDoWildEncounter
- ret nz
-InitBattleCommon:
- ld a, [wMapPalOffset]
- push af
- ld hl, wLetterPrintingDelayFlags
- ld a, [hl]
- push af
- res 1, [hl]
- callab InitBattleVariables
- ld a, [wEnemyMonSpecies2]
- sub OPP_ID_OFFSET
- jp c, InitWildBattle
- ld [wTrainerClass], a
- call GetTrainerInformation
- callab ReadTrainer
- call DoBattleTransitionAndInitBattleVariables
- call _LoadTrainerPic
- xor a
- ld [wEnemyMonSpecies2], a
- ld [hStartTileID], a
- dec a
- ld [wAICount], a
- coord hl, 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 MAROWAK
- 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 a, "G"
- ld [hli], a
- ld a, "H"
- ld [hli], a
- ld a, "O"
- ld [hli], a
- ld a, "S"
- ld [hli], a
- ld a, "T"
- ld [hli], a
- ld [hl], "@"
- ld a, [wcf91]
- push af
- ld a, MON_GHOST
- ld [wcf91], a
- ld de, vFrontPic
- call LoadMonFrontSprite ; load ghost sprite
- pop af
- ld [wcf91], a
- jr .spriteLoaded
-.isNoGhost
- ld de, vFrontPic
- call LoadMonFrontSprite ; load mon sprite
-.spriteLoaded
- xor a
- ld [wTrainerClass], a
- ld [hStartTileID], a
- coord hl, 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
- ld [H_AUTOBGTRANSFERENABLED], a
- ld hl, .emptyString
- call PrintText
- call SaveScreenTilesToBuffer1
- call ClearScreen
- ld a, $98
- ld [H_AUTOBGTRANSFERDEST + 1], a
- ld a, $1
- ld [H_AUTOBGTRANSFERENABLED], a
- call Delay3
- ld a, $9c
- ld [H_AUTOBGTRANSFERDEST + 1], a
- call LoadScreenTilesFromBuffer1
- coord hl, 9, 7
- lb bc, 5, 10
- call ClearScreenArea
- coord hl, 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
- callab EndOfBattle
- pop af
- ld [wLetterPrintingDelayFlags], a
- pop af
- ld [wMapPalOffset], a
- ld a, [wSavedTilesetType]
- ld [hTilesetType], a
- scf
- ret
-.emptyString
- db "@"
-
-_LoadTrainerPic:
-; wd033-wd034 contain pointer to pic
- 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(TrainerPics) ; this is where all the trainer pics are (not counting Red's)
- 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, [wPredefRegisters]
- ld h, a
- ld a, [wPredefRegisters + 1]
- ld l, a
- ld a, [hStartTileID]
- ld [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
- ld a, [hBaseTileID]
- add $31
- jr CopyUncompressedPicToHL
-
-CopyUncompressedPicToTilemap:
- ld a, [wPredefRegisters]
- ld h, a
- ld a, [wPredefRegisters + 1]
- ld l, a
- ld 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
+ predef MoveAnimation
+ callab Func_78e98
ret
-LoadMonBackPic:
-; Assumes the monster's attributes have
-; been loaded with GetMonHeader.
- ld a, [wBattleMonSpecies2]
- ld [wcf91], a
- coord hl, 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)/16 ; count of 16-byte chunks to be copied
- ld a, [H_LOADEDROMBANK]
- ld b, a
- jp CopyVideoData
-
JumpMoveEffect:
call _JumpMoveEffect
ld b, $1
@@ -7266,6 +7151,16 @@ SleepEffect:
call BattleRandom
and $7
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
@@ -7404,7 +7299,7 @@ FreezeBurnParalyzeEffect:
ret nz ; return if they have a substitute, can't effect them
ld a, [H_WHOSETURN]
and a
- jp nz, opponentAttacker
+ jp nz, .opponentAttacker
ld a, [wEnemyMonStatus]
and a
jp nz, CheckDefrost ; can't inflict status if opponent is already statused
@@ -7417,7 +7312,17 @@ FreezeBurnParalyzeEffect:
cp b ; do target type 2 and move type match?
ret z ; return if they match
ld a, [wPlayerMoveEffect]
- cp PARALYZE_SIDE_EFFECT1 + 1 ; 10% status effects are 04, 05, 06 so 07 will set carry for those
+ cp UNUSED_EFFECT_23 ; more stadium stuff
+ jr nz, .asm_3f2c7
+ ld a, [wUnknownSerialFlag_d499]
+ and a
+ ld a, FREEZE_SIDE_EFFECT
+ ld b, $4d ; else use 0x4D/0x100 or 77/256 = 30.1%~ chance
+ jr z, .next1
+ ld b, $1a ; 0x1A/0x100 or 26/256 = 10.2%~ chance
+ jr .next1
+.asm_3f2c7
+ cp a, PARALYZE_SIDE_EFFECT1 + 1 ; 10% status effects are 04, 05, 06 so 07 will set carry for those
ld b, $1a ; 0x1A/0x100 or 26/256 = 10.2%~ chance
jr c, .next1 ; branch ahead if this is a 10% chance effect..
ld b, $4d ; else use 0x4D/0x100 or 77/256 = 30.1%~ chance
@@ -7430,9 +7335,9 @@ FreezeBurnParalyzeEffect:
ret nc ; do nothing if random value is >= 1A or 4D [no status applied]
ld a, b ; what type of effect is this?
cp BURN_SIDE_EFFECT1
- jr z, .burn
+ jr z, .burn1
cp FREEZE_SIDE_EFFECT
- jr z, .freeze
+ jr z, .freeze1
; .paralyze
ld a, 1 << PAR
ld [wEnemyMonStatus], a
@@ -7440,7 +7345,7 @@ FreezeBurnParalyzeEffect:
ld a, ANIM_A9
call PlayBattleAnimation
jp PrintMayNotAttackText ; print paralysis text
-.burn
+.burn1
ld a, 1 << BRN
ld [wEnemyMonStatus], a
call HalveAttackDueToBurn ; halve attack of affected mon
@@ -7448,7 +7353,7 @@ FreezeBurnParalyzeEffect:
call PlayBattleAnimation
ld hl, BurnedText
jp PrintText
-.freeze
+.freeze1
call ClearHyperBeam ; resets hyper beam (recharge) condition from target
ld a, 1 << FRZ
ld [wEnemyMonStatus], a
@@ -7456,7 +7361,7 @@ FreezeBurnParalyzeEffect:
call PlayBattleAnimation
ld hl, FrozenText
jp PrintText
-opponentAttacker:
+.opponentAttacker
ld a, [wBattleMonStatus] ; mostly same as above with addresses swapped for opponent
and a
jp nz, CheckDefrost
@@ -7469,12 +7374,22 @@ opponentAttacker:
cp b
ret z
ld a, [wEnemyMoveEffect]
- cp PARALYZE_SIDE_EFFECT1 + 1
+ cp UNUSED_EFFECT_23 ; more stadium stuff
+ jr nz, .asm_3f341
+ ld a, [wUnknownSerialFlag_d499]
+ and a
+ ld a, FREEZE_SIDE_EFFECT
+ ld b, $4d ; else use 0x4D/0x100 or 77/256 = 30.1%~ chance
+ jr z, .next2
+ ld b, $1a ; 0x1A/0x100 or 26/256 = 10.2%~ chance
+ jr .next2
+.asm_3f341
+ cp a, PARALYZE_SIDE_EFFECT1 + 1
ld b, $1a
- jr c, .next1
+ jr c, .next2
ld b, $4d
sub $1e
-.next1
+.next2
push af
call BattleRandom
cp b
@@ -7482,23 +7397,29 @@ opponentAttacker:
ret nc
ld a, b
cp BURN_SIDE_EFFECT1
- jr z, .burn
+ jr z, .burn2
cp FREEZE_SIDE_EFFECT
- jr z, .freeze
+ jr z, .freeze2
ld a, 1 << PAR
ld [wBattleMonStatus], a
call QuarterSpeedDueToParalysis
+ ld a, ANIM_C7
+ call PlayBattleAnimation2
jp PrintMayNotAttackText
-.burn
+.burn2
ld a, 1 << BRN
ld [wBattleMonStatus], a
call HalveAttackDueToBurn
+ ld a, ANIM_C7
+ call PlayBattleAnimation2
ld hl, BurnedText
jp PrintText
-.freeze
+.freeze2
; hyper beam bits aren't reseted for opponent's side
ld a, 1 << FRZ
ld [wBattleMonStatus], a
+ ld a, ANIM_C7
+ call PlayBattleAnimation2
ld hl, FrozenText
jp PrintText
@@ -7663,25 +7584,25 @@ UpdateStatDone:
ld bc, wPlayerMonMinimized
ld a, [H_WHOSETURN]
and a
- jr z, .asm_3f4e6
+ jr z, .playerTurn
ld hl, wEnemyBattleStatus2
ld de, wEnemyMoveNum
ld bc, wEnemyMonMinimized
-.asm_3f4e6
+.playerTurn
ld a, [de]
cp MINIMIZE
- jr nz, .asm_3f4f9
+ jr nz, .notMinimize
; if a substitute is up, slide off the substitute and show the mon pic before
; playing the minimize animation
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
-.asm_3f4f9
+.notMinimize
call PlayCurrentMoveAnimation
ld a, [de]
cp MINIMIZE
@@ -8199,6 +8120,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, $1a ; ~10% chance of flinch
@@ -8240,10 +8164,27 @@ ChargeEffect:
set INVULNERABLE, [hl] ; mon is now invulnerable to typical attacks (fly/dig)
ld b, ANIM_C0
.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
@@ -8713,6 +8654,7 @@ PlayBattleAnimationGotID:
push de
push bc
predef MoveAnimation
+ callab Func_78e98
pop bc
pop de
pop hl
diff --git a/engine/battle/draw_hud_pokeball_gfx.asm b/engine/battle/draw_hud_pokeball_gfx.asm
index 323dd167..96294774 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 [wdef5], a
ld hl, wOAMBuffer
jp WritePokeballOAMData
@@ -41,6 +43,8 @@ SetupEnemyPartyPokeballs:
ld [hl], $20
ld a, -8
ld [wHUDPokeballGfxOffsetX], a
+ ld a, $1
+ ld [wdef5], a
ld hl, wOAMBuffer + PARTY_LENGTH * 4
jp WritePokeballOAMData
@@ -104,7 +108,7 @@ WritePokeballOAMData:
ld [hli], a
ld a, [de]
ld [hli], a
- xor a
+ ld a, [wdef5]
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 [wdef5], a
ld hl, wOAMBuffer
call WritePokeballOAMData
ld hl, wEnemyMons
@@ -183,6 +189,8 @@ SetupPlayerAndEnemyPokeballs:
ld a, $50
ld [hli], a
ld [hl], $68
+ ld a, $1
+ ld [wdef5], a
ld hl, wOAMBuffer + $18
jp WritePokeballOAMData
diff --git a/engine/battle/end_of_battle.asm b/engine/battle/end_of_battle.asm
index 830a23a1..5c0c3991 100755
--- 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
callab DisplayLinkBattleVersusTextBox
ld a, [wBattleResult]
cp $1
@@ -43,6 +45,8 @@ EndOfBattle:
xor a
ld [wForceEvolution], a
predef EvolutionAfterBattle
+ ld d, $82
+ callab UpdatePikachuMoodAfterBattle
.resetVariables
xor a
ld [wLowHealthAlarm], a ;disable low health alarm
diff --git a/engine/battle/experience.asm b/engine/battle/experience.asm
index 24748338..722685c2 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 ; 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
- callab CalculateModifiedStats
- callab ApplyBurnAndParalysisPenaltiesToPlayer
- callab ApplyBadgeStatBoosts
- callab DrawPlayerHUDAndHPBar
- callab PrintEmptyString
+ ld hl, CalculateModifiedStats
+ call Bankswitch15ToF
+ ld hl, ApplyBurnAndParalysisPenaltiesToPlayer
+ call Bankswitch15ToF
+ ld hl, ApplyBadgeStatBoosts
+ call Bankswitch15ToF
+ ld hl, DrawPlayerHUDAndHPBar
+ call Bankswitch15ToF
+ ld hl, PrintEmptyString
+ call Bankswitch15ToF
call SaveScreenTilesToBuffer1
.printGrewLevelText
+ callabd_ModifyPikachuHappiness PIKAHAPPY_LEVELUP
ld hl, GrewLevelText
call PrintText
xor a ; PLAYER_PARTY_DATA
@@ -339,6 +345,10 @@ BoostExp:
ld [H_QUOTIENT + 2], a
ret
+Bankswitch15ToF:
+ ld b, BANK(BattleCore)
+ jp Bankswitch
+
GainedText:
TX_FAR _GainedText
TX_ASM
diff --git a/engine/battle/ghost_marowak_anim.asm b/engine/battle/ghost_marowak_anim.asm
index 7adb20d8..5bb3e308 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
ld [rOBP1], a
+ call UpdateGBCPal_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
coord hl, 12, 0
@@ -27,6 +28,7 @@ MarowakAnim:
sla a
sla a
ld [rOBP1], a
+ call UpdateGBCPal_OBP1
jr nz, .fadeOutGhostLoop
call ClearSprites
call CopyMonPicFromBGToSpriteVRAM ; copy Marowak pic from BG to sprite VRAM
@@ -40,6 +42,7 @@ MarowakAnim:
srl b
rra
ld [rOBP1], a
+ call UpdateGBCPal_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, $10 ; use OBP1
+ ld a, $14 ; use OBP1
ld [hli], a
inc d
dec c
diff --git a/engine/battle/link_battle_versus_text.asm b/engine/battle/link_battle_versus_text.asm
index 76559117..63142ba6 100644
--- a/engine/battle/link_battle_versus_text.asm
+++ b/engine/battle/link_battle_versus_text.asm
@@ -2,8 +2,7 @@
DisplayLinkBattleVersusTextBox:
call LoadTextBoxTilePatterns
coord hl, 3, 4
- ld b, 7
- ld c, 12
+ lb bc, 7, 12
call TextBoxBorder
coord hl, 4, 5
ld de, wPlayerName
diff --git a/engine/battle/moveEffects/heal_effect.asm b/engine/battle/moveEffects/heal_effect.asm
index 2e68acc0..97afa394 100644
--- a/engine/battle/moveEffects/heal_effect.asm
+++ b/engine/battle/moveEffects/heal_effect.asm
@@ -86,7 +86,7 @@ HealEffect_:
ld [wHPBarNewHP], a
.playAnim
ld hl, PlayCurrentMoveAnimation
- call BankswitchEtoF
+ call Bankswitch3DtoF
ld a, [H_WHOSETURN]
and a
coord hl, 10, 9
@@ -98,14 +98,14 @@ HealEffect_:
ld [wHPBarType], a
predef UpdateHPBar2
ld hl, DrawHUDsAndHPBars
- call BankswitchEtoF
+ call Bankswitch3DtoF
ld hl, RegainedHealthText
jp PrintText
.failed
ld c, 50
call DelayFrames
ld hl, PrintButItFailedText_
- jp BankswitchEtoF
+ jp Bankswitch3DtoF
StartedSleepingEffect:
TX_FAR _StartedSleepingEffect
diff --git a/engine/battle/moveEffects/reflect_light_screen_effect.asm b/engine/battle/moveEffects/reflect_light_screen_effect.asm
index 2805a969..e5748b19 100644
--- a/engine/battle/moveEffects/reflect_light_screen_effect.asm
+++ b/engine/battle/moveEffects/reflect_light_screen_effect.asm
@@ -23,14 +23,14 @@ ReflectLightScreenEffect_:
.playAnim
push hl
ld hl, PlayCurrentMoveAnimation
- call BankswitchEtoF
+ call Bankswitch3DtoF
pop hl
jp PrintText
.moveFailed
ld c, 50
call DelayFrames
ld hl, PrintButItFailedText_
- jp BankswitchEtoF
+ jp Bankswitch3DtoF
LightScreenProtectedText:
TX_FAR _LightScreenProtectedText
@@ -40,6 +40,6 @@ ReflectGainedArmorText:
TX_FAR _ReflectGainedArmorText
db "@"
-BankswitchEtoF:
+Bankswitch3DtoF:
ld b, BANK(BattleCore)
jp Bankswitch
diff --git a/engine/battle/moveEffects/transform_effect.asm b/engine/battle/moveEffects/transform_effect.asm
index 9a5de9cc..ec07b303 100644
--- a/engine/battle/moveEffects/transform_effect.asm
+++ b/engine/battle/moveEffects/transform_effect.asm
@@ -100,18 +100,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
@@ -141,7 +134,7 @@ TransformEffect_:
.failed
ld hl, PrintButItFailedText_
- jp BankswitchEtoF
+ jp Bankswitch3DtoF
TransformedText:
TX_FAR _TransformedText
diff --git a/engine/battle/read_trainer_party.asm b/engine/battle/read_trainer_party.asm
index ba4f6f8e..b4ee46a0 100755
--- 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 $C9 ; 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 [wcf91], a ; write species somewhere (XXX why?)
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 [wCurEnemyLVL], a
ld a, [hli]
ld [wcf91], 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
- and a
- jr z, .AddTeamMove
- dec a
- add a
+.AddAdditionalMoveData
+; does the trainer have additional move data?
+ ld a, [wTrainerClass]
+ ld b, a
+ ld a, [wTrainerNo]
ld c, a
- ld b, 0
- ld hl, LoneMoves
- add hl, bc
+ ld hl, SpecialTrainerMoves
+.loopAdditionalMoveData
+ ld a, [hli]
+ cp $ff
+ jr z, .FinishUp
+ cp b
+ jr nz, .asm_39c46
ld a, [hli]
- ld d, [hl]
- ld hl, wEnemyMon1Moves + 2
+ cp c
+ jr nz, .asm_39c46
+ ld d, h
+ ld e, l
+.writeAdditionalMoveDataLoop
+ ld a, [de]
+ inc de
+ and a
+ jp z, .FinishUp
+ dec a
+ ld hl, wEnemyMon1Moves
ld bc, wEnemyMon2 - wEnemyMon1
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, [de]
+ inc de
+ dec a
+ ld c, a
+ ld b, 0
+ add hl,bc
+ ld a, [de]
+ inc de
+ ld [hl], a
+ jr .writeAdditionalMoveDataLoop
+.asm_39c46
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 SONY3
- 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, .asm_39c46
+ jr .loopAdditionalMoveData
.FinishUp
; clear wAmountMoneyWon addresses
xor a
diff --git a/engine/battle/safari_zone.asm b/engine/battle/safari_zone.asm
index 4672892d..88064f9a 100755
--- a/engine/battle/safari_zone.asm
+++ b/engine/battle/safari_zone.asm
@@ -2,18 +2,18 @@ PrintSafariZoneBattleText:
ld hl, wSafariBaitFactor
ld a, [hl]
and a
- jr z, .asm_4284
+ jr z, .asm_411e
dec [hl]
ld hl, SafariZoneEatingText
- jr .asm_429f
-.asm_4284
+ jr .asm_4138
+.asm_411e
dec hl
ld a, [hl]
and a
ret z
dec [hl]
ld hl, SafariZoneAngryText
- jr nz, .asm_429f
+ jr nz, .asm_4138
push hl
ld a, [wEnemyMonSpecies]
ld [wd0b5], a
@@ -21,7 +21,7 @@ PrintSafariZoneBattleText:
ld a, [wMonHCatchRate]
ld [wEnemyMonActualCatchRate], a
pop hl
-.asm_429f
+.asm_4138
push hl
call LoadScreenTilesFromBuffer1
pop hl
diff --git a/engine/battle/scale_sprites.asm b/engine/battle/scale_sprites.asm
index 98521528..c614d638 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, $0
+ call SwitchSRAMBankAndLatchClockData
+ call ScaleSpriteByTwo_
+ call PrepareRTCDataAndDisableSRAM
+ 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 ac6c1a72..c8fdfb29 100644
--- a/engine/battle/trainer_ai.asm
+++ b/engine/battle/trainer_ai.asm
@@ -295,7 +295,7 @@ TrainerClassMoveChoiceModifications:
db 1,0 ; GAMBLER
db 1,3,0 ; BEAUTY
db 1,2,0 ; PSYCHIC_TR
- db 1,3,0 ; ROCKER
+ db 1,0 ; ROCKER
db 1,0 ; JUGGLER
db 1,0 ; TAMER
db 1,0 ; BIRD_KEEPER
@@ -311,11 +311,11 @@ TrainerClassMoveChoiceModifications:
db 1,0 ; BRUNO
db 1,0 ; BROCK
db 1,3,0 ; MISTY
- db 1,3,0 ; LT_SURGE
+ db 1,0 ; LT_SURGE
db 1,3,0 ; ERIKA
db 1,3,0 ; KOGA
- db 1,3,0 ; BLAINE
- db 1,3,0 ; SABRINA
+ db 1,0 ; BLAINE
+ db 1,0 ; SABRINA
db 1,2,0 ; GENTLEMAN
db 1,3,0 ; SONY2
db 1,3,0 ; SONY3
@@ -337,14 +337,20 @@ INCLUDE "data/trainer_moves.asm"
INCLUDE "data/trainer_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
- ld a, [wTrainerClass] ; what trainer class is this?
+ 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 ; %10011
+ jr nz, .done ; don't follow trainer ai if opponent is in a locked state
+ ld a, [wEnemyBattleStatus2]
+ and 1 << USING_RAGE ; %1000000
+ 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
ld b, 0
@@ -354,7 +360,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
@@ -367,6 +373,9 @@ TrainerAI:
ld l, a
call Random
jp hl
+.done
+ and a
+ ret
TrainerAIPointers:
; one entry per trainer class
@@ -476,22 +485,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
Sony2AI:
cp 13 percent - 1
diff --git a/engine/battle/wild_encounters.asm b/engine/battle/wild_encounters.asm
index 231c46e7..0285346e 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?
- coord hl, 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
+ coord hl, 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/bcd.asm b/engine/bcd.asm
index 2d0b43df..d84e504b 100644
--- a/engine/bcd.asm
+++ b/engine/bcd.asm
@@ -1,14 +1,17 @@
+; divide hMoney by hDivideBCDDivisor
+; return output in hDivideBCDQuotient (same as hDivideBCDDivisor)
+; used only to halve player money upon losing a fight
DivideBCDPredef::
DivideBCDPredef2::
-DivideBCDPredef3::
+DivideBCDPredef3:: ; only used function
DivideBCDPredef4::
call GetPredefRegisters
DivideBCD::
xor a
ld [hDivideBCDBuffer], a
- ld [hDivideBCDBuffer+1], a
- ld [hDivideBCDBuffer+2], a
+ ld [hDivideBCDBuffer + 1], a
+ ld [hDivideBCDBuffer + 2], a
ld d, $1
.mulBy10Loop
; multiply the divisor by 10 until the leading digit is nonzero
@@ -21,25 +24,26 @@ DivideBCD::
swap a
and $f0
ld b, a
- ld a, [hDivideBCDDivisor+1]
+ ld a, [hDivideBCDDivisor + 1]
swap a
- ld [hDivideBCDDivisor+1], a
+ ld [hDivideBCDDivisor + 1], a
and $f
or b
ld [hDivideBCDDivisor], a
- ld a, [hDivideBCDDivisor+1]
+ ld a, [hDivideBCDDivisor + 1]
and $f0
ld b, a
- ld a, [hDivideBCDDivisor+2]
+ ld a, [hDivideBCDDivisor + 2]
swap a
- ld [hDivideBCDDivisor+2], a
+ ld [hDivideBCDDivisor + 2], a
and $f
or b
- ld [hDivideBCDDivisor+1], a
- ld a, [hDivideBCDDivisor+2]
+ ld [hDivideBCDDivisor + 1], a
+ ld a, [hDivideBCDDivisor + 2]
and $f0
- ld [hDivideBCDDivisor+2], a
+ ld [hDivideBCDDivisor + 2], a
jr .mulBy10Loop
+
.next
push de
push de
@@ -67,16 +71,16 @@ DivideBCD::
ld a, b
swap a
and $f0
- ld [hDivideBCDBuffer+1], a
+ ld [hDivideBCDBuffer + 1], a
dec d
jr z, .next2
push de
call DivideBCD_divDivisorBy10
call DivideBCD_getNextDigit
pop de
- ld a, [hDivideBCDBuffer+1]
+ ld a, [hDivideBCDBuffer + 1]
or b
- ld [hDivideBCDBuffer+1], a
+ ld [hDivideBCDBuffer + 1], a
dec d
jr z, .next2
push de
@@ -86,23 +90,23 @@ DivideBCD::
ld a, b
swap a
and $f0
- ld [hDivideBCDBuffer+2], a
+ ld [hDivideBCDBuffer + 2], a
dec d
jr z, .next2
push de
call DivideBCD_divDivisorBy10
call DivideBCD_getNextDigit
pop de
- ld a, [hDivideBCDBuffer+2]
+ ld a, [hDivideBCDBuffer + 2]
or b
- ld [hDivideBCDBuffer+2], a
+ ld [hDivideBCDBuffer + 2], a
.next2
ld a, [hDivideBCDBuffer]
ld [hDivideBCDQuotient], a ; the same memory location as hDivideBCDDivisor
- ld a, [hDivideBCDBuffer+1]
- ld [hDivideBCDQuotient+1], a
- ld a, [hDivideBCDBuffer+2]
- ld [hDivideBCDQuotient+2], a
+ ld a, [hDivideBCDBuffer + 1]
+ ld [hDivideBCDQuotient + 1], a
+ ld a, [hDivideBCDBuffer + 2]
+ ld [hDivideBCDQuotient + 2], a
pop de
ld a, $6
sub d
@@ -117,17 +121,17 @@ DivideBCD::
ret
DivideBCD_divDivisorBy10:
- ld a, [hDivideBCDDivisor+2]
+ ld a, [hDivideBCDDivisor + 2]
swap a
and $f
ld b, a
- ld a, [hDivideBCDDivisor+1]
+ ld a, [hDivideBCDDivisor + 1]
swap a
- ld [hDivideBCDDivisor+1], a
+ ld [hDivideBCDDivisor + 1], a
and $f0
or b
- ld [hDivideBCDDivisor+2], a
- ld a, [hDivideBCDDivisor+1]
+ ld [hDivideBCDDivisor + 2], a
+ ld a, [hDivideBCDDivisor + 1]
and $f
ld b, a
ld a, [hDivideBCDDivisor]
@@ -135,7 +139,7 @@ DivideBCD_divDivisorBy10:
ld [hDivideBCDDivisor], a
and $f0
or b
- ld [hDivideBCDDivisor+1], a
+ ld [hDivideBCDDivisor + 1], a
ld a, [hDivideBCDDivisor]
and $f
ld [hDivideBCDDivisor], a
@@ -151,8 +155,8 @@ DivideBCD_getNextDigit:
pop bc
ret c
inc b
- ld de, hMoney+2 ; since SubBCD works starting from the least significant digit
- ld hl, hDivideBCDDivisor+2
+ ld de, hMoney + 2 ; since SubBCD works starting from the least significant digit
+ ld hl, hDivideBCDDivisor + 2
push bc
call SubBCD
pop bc
diff --git a/engine/bg_map_attributes.asm b/engine/bg_map_attributes.asm
new file mode 100644
index 00000000..90df9e27
--- /dev/null
+++ b/engine/bg_map_attributes.asm
@@ -0,0 +1,219 @@
+INCLUDE "data/bg_map_attributes.asm"
+
+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
+ ld [rVBK], a
+ push hl
+ ld a, [hl]
+ ld c, a ; save attribute count for later
+ ld de, $10
+ add hl, de
+ ld a, h
+ ld [rHDMA1], a
+ ld a, l
+ ld [rHDMA2], a
+ ld de, vBGMap0
+ ld a, d
+ ld [rHDMA3], a
+ ld a, e
+ ld [rHDMA4], a
+
+ ld a, [rLCDC]
+ and rLCDC_ENABLE_MASK ; is LCD off?
+ jr z, .lcdOff ; if off, transfer immediately
+; wait for VBlank if LCD is on
+.waitForVBlankLoop1
+ ld a, [rLY]
+ cp $90
+ jr nz, .waitForVBlankLoop1
+.waitForAccessibleVRAMLoop1
+ ld 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
+ ld [rHDMA5], 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
+ ld [rHDMA1], a
+ ld a, l
+ ld [rHDMA2], a
+ ld de, vBGMap1 ; copy to vBGMap1
+ ld a, d
+ ld [rHDMA3], a
+ ld a, e
+ ld [rHDMA4], a
+; LCD check again
+ ld a, [rLCDC]
+ and rLCDC_ENABLE_MASK ; is LCD off?
+ jr z, .lcdOff2 ; if off, transfer immediately
+; wait for VBlank if LCD is on
+.waitForVBlankLoop2
+ ld a, [rLY]
+ cp $90
+ jr nz, .waitForVBlankLoop2
+.waitForAccessibleVRAMLoop2
+ ld 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
+ ld [rHDMA5], 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
+ ld a, [rIF]
+ res VBLANK, a
+ ld [rIF], a
+ xor a
+ ld [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/black_out.asm b/engine/black_out.asm
index 6c358ce3..0daa084b 100644
--- a/engine/black_out.asm
+++ b/engine/black_out.asm
@@ -1,6 +1,8 @@
ResetStatusAndHalveMoneyOnBlackout::
; Reset player status on blackout.
xor a
+ ld [wd435], a
+ xor a ; gamefreak copypasting functions (double xor a)
ld [wBattleResult], a
ld [wWalkBikeSurfState], a
ld [wIsInBattle], a
diff --git a/engine/cable_club.asm b/engine/cable_club.asm
index 3e72daa9..a8dc5d8d 100755
--- a/engine/cable_club.asm
+++ b/engine/cable_club.asm
@@ -10,8 +10,7 @@ CableClub_DoBattleOrTrade:
call LoadHpBarAndStatusTilePatterns
call LoadTrainerInfoTextBoxTiles
coord hl, 3, 8
- ld b, 2
- ld c, 12
+ lb bc, 2, 12
call CableClub_TextBoxBorder
coord hl, 4, 10
ld de, PleaseWaitString
@@ -119,6 +118,7 @@ CableClub_DoBattleOrTradeAgain:
ld [rSC], a
.skipSendingTwoZeroBytes
call Delay3
+ call StopAllMusic
ld a, (1 << SERIAL)
ld [rIE], a
ld hl, wSerialRandomNumberListBlock
@@ -139,8 +139,6 @@ CableClub_DoBattleOrTradeAgain:
call Serial_ExchangeBytes
ld a, (1 << SERIAL) | (1 << TIMER) | (1 << VBLANK)
ld [rIE], a
- ld a, $ff
- call PlaySound
ld a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr z, .skipCopyingRandomNumberList ; the list generated by the gameboy clocking the connection is used by both gameboys
@@ -261,8 +259,7 @@ CableClub_DoBattleOrTradeAgain:
ld [wUnusedCF8D + 1], a
xor a
ld [wTradeCenterPointerTableIndex], a
- ld a, $ff
- call PlaySound
+ call StopAllMusic
ld a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
ld c, 66
@@ -278,9 +275,17 @@ CableClub_DoBattleOrTradeAgain:
ld [wCurOpponent], a
call ClearScreen
call Delay3
+ ld b, $9
+ call RunPaletteCommand
ld hl, wOptions
res 7, [hl]
+ ld a, [wLetterPrintingDelayFlags]
+ push af
+ xor a
+ ld [wLetterPrintingDelayFlags], a
predef InitOpponent
+ pop af
+ ld [wLetterPrintingDelayFlags], a
predef HealParty
jp ReturnToCableClubRoom
.trading
@@ -308,6 +313,9 @@ CallCurrentTradeCenterFunction:
TradeCenter_SelectMon:
call ClearScreen
+ call Delay3
+ ld b, $9
+ call RunPaletteCommand
call LoadTrainerInfoTextBoxTiles
call TradeCenter_DrawPartyLists
call TradeCenter_DrawCancelBox
@@ -338,10 +346,10 @@ TradeCenter_SelectMon:
ld a, 1
ld [wTopMenuItemX], a
.enemyMonMenu_HandleInput
- ld hl, hFlags_0xFFF6
+ ld hl, hFlags_0xFFFA
set 1, [hl]
call HandleMenuInput
- ld hl, hFlags_0xFFF6
+ ld hl, hFlags_0xFFFA
res 1, [hl]
and a
jp z, .getNewInput
@@ -403,10 +411,10 @@ TradeCenter_SelectMon:
lb bc, 6, 1
call ClearScreenArea
.playerMonMenu_HandleInput
- ld hl, hFlags_0xFFF6
+ ld hl, hFlags_0xFFFA
set 1, [hl]
call HandleMenuInput
- ld hl, hFlags_0xFFF6
+ ld hl, hFlags_0xFFFA
res 1, [hl]
and a ; was anything pressed?
jr nz, .playerMonMenu_SomethingPressed
@@ -465,8 +473,7 @@ TradeCenter_SelectMon:
.displayStatsTradeMenu
push af
coord hl, 0, 14
- ld b, 2
- ld c, 18
+ lb bc, 2, 18
call CableClub_TextBoxBorder
coord hl, 2, 16
ld de, .statsTrade
@@ -601,8 +608,7 @@ TradeCenter_DrawCancelBox:
ld bc, 2 * SCREEN_WIDTH + 9
call FillMemory
coord hl, 0, 15
- ld b, 1
- ld c, 9
+ lb bc, 1, 9
call CableClub_TextBoxBorder
coord hl, 2, 16
ld de, CancelTextString
@@ -624,6 +630,9 @@ TradeCenter_DisplayStats:
ld [wWhichPokemon], a
predef StatusScreen
predef StatusScreen2
+ call Delay3
+ ld b, $9
+ call RunPaletteCommand
call GBPalNormal
call LoadTrainerInfoTextBoxTiles
call TradeCenter_DrawPartyLists
@@ -631,12 +640,10 @@ TradeCenter_DisplayStats:
TradeCenter_DrawPartyLists:
coord hl, 0, 0
- ld b, 6
- ld c, 18
+ lb bc, 6, 18
call CableClub_TextBoxBorder
coord hl, 0, 8
- ld b, 6
- ld c, 18
+ lb bc, 6, 18
call CableClub_TextBoxBorder
coord hl, 5, 0
ld de, wPlayerName
@@ -685,8 +692,7 @@ TradeCenter_Trade:
ld [wMenuWatchMovingOutOfBounds], a
ld [wMenuJoypadPollCount], a
coord hl, 0, 12
- ld b, 4
- ld c, 18
+ lb bc, 4, 18
call CableClub_TextBoxBorder
ld a, [wTradingWhichPlayerMon]
ld hl, wPartySpecies
@@ -727,8 +733,7 @@ TradeCenter_Trade:
ld a, $1
ld [wSerialExchangeNybbleSendData], a
coord hl, 0, 12
- ld b, 4
- ld c, 18
+ lb bc, 4, 18
call CableClub_TextBoxBorder
coord hl, 1, 14
ld de, TradeCanceled
@@ -744,8 +749,7 @@ TradeCenter_Trade:
jr nz, .doTrade
; if the other person cancelled
coord hl, 0, 12
- ld b, 4
- ld c, 18
+ lb bc, 4, 18
call CableClub_TextBoxBorder
coord hl, 1, 14
ld de, TradeCanceled
@@ -792,6 +796,7 @@ TradeCenter_Trade:
add hl, bc
ld a, [hl]
ld [wTradedPlayerMonSpecies], a
+ callabd_ModifyPikachuHappiness PIKAHAPPY_TRADE
xor a
ld [wRemoveMonFromBox], a
call RemovePokemon
@@ -826,7 +831,7 @@ TradeCenter_Trade:
ld [wTradedEnemyMonSpecies], a
ld a, 10
ld [wAudioFadeOutControl], a
- ld a, $2
+ ld a, BANK(Music_SafariZone)
ld [wAudioSavedROMBank], a
ld a, MUSIC_SAFARI_ZONE
ld [wNewSoundID], a
@@ -851,9 +856,11 @@ TradeCenter_Trade:
call Serial_PrintWaitingTextAndSyncAndExchangeNybble
ld c, 40
call DelayFrames
+ call Delay3
+ ld b, $9
+ call RunPaletteCommand
coord hl, 0, 12
- ld b, 4
- ld c, 18
+ lb bc, 4, 18
call CableClub_TextBoxBorder
coord hl, 1, 14
ld de, TradeCompleted
diff --git a/engine/clear_save.asm b/engine/clear_save.asm
index b47cd6c4..f2acbf32 100755
--- a/engine/clear_save.asm
+++ b/engine/clear_save.asm
@@ -5,6 +5,8 @@ DoClearSaveDialogue:
call LoadTextBoxTilePatterns
ld hl, ClearSaveDataText
call PrintText
+ ld a, B_BUTTON
+ ld [wJoyIgnore], a
coord hl, 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/debug1.asm b/engine/debug1.asm
index a5eb7dde..a39e8cac 100644
--- a/engine/debug1.asm
+++ b/engine/debug1.asm
@@ -1,14 +1,6 @@
-; This function appears to never be used.
-; It is likely a debugging feature to give the player Tsunekazu Ishihara's
-; favorite Pokemon. This is indicated by the overpowered Exeggutor, which
-; Ishihara (president of Creatures Inc.) said was his favorite Pokemon in an ABC
-; interview on February 8, 2000.
-; "Exeggutor is my favorite. That's because I was always using this character
-; while I was debugging the program."
-; http://www.ign.com/articles/2000/02/09/abc-news-pokamon-chat-transcript
-
-SetIshiharaTeam:
- ld de, IshiharaTeam
+; not IshiharaTeam
+SetDebugTeam:
+ ld de, DebugTeam
.loop
ld a, [de]
cp $ff
@@ -21,12 +13,11 @@ SetIshiharaTeam:
call AddPartyMon
jr .loop
-IshiharaTeam:
- db EXEGGUTOR,90
- db MEW,20
- db JOLTEON,56
- db DUGTRIO,56
- db ARTICUNO,57
+DebugTeam:
+ db SNORLAX,80
+ db PERSIAN,80
+ db JIGGLYPUFF,15
+ db PIKACHU,5
db $FF
EmptyFunc:
diff --git a/engine/diploma_3a.asm b/engine/diploma_3a.asm
new file mode 100755
index 00000000..f4504ad7
--- /dev/null
+++ b/engine/diploma_3a.asm
@@ -0,0 +1,166 @@
+_DisplayDiploma:
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ ld de, SurfingPikachu3Graphics
+ ld hl, vChars2
+ lb bc, BANK(SurfingPikachu3Graphics), (SurfingPikachu3GraphicsEnd - SurfingPikachu3Graphics) / $10
+ call CopyVideoData
+
+ coord hl, 0, 0
+ call Func_e9bdf
+
+ coord hl, 0, 0
+ call Func_e9beb
+
+ coord hl, 19, 0
+ call Func_e9beb
+
+ ld a, $00
+ coord hl, 0, 0
+ ld [hl], a
+ coord hl, 19, 0
+ ld [hl], a
+
+ ld de, String_e9a73
+ coord hl, 5, 2
+ call PlaceString
+
+ ld de, String_e9a7d
+ coord hl, 3, 4
+ call PlaceString
+
+ ld de, wPlayerName
+ coord hl, 10, 4
+ call PlaceString
+
+ ld de, String_e9a84
+ coord hl, 2, 6
+ call PlaceString
+
+ ld de, String_e9ac8
+ coord hl, 9, 16
+ call PlaceString
+
+ ld b, SET_PAL_GENERIC
+ call RunPaletteCommand
+ ld a, $01
+ ld [$ffba], a
+ call Delay3
+ call GBPalNormal
+ ret
+
+String_e9a73:
+ db $10, "Diploma", $10, "@"
+
+String_e9a7d:
+ db "Player@"
+
+String_e9a84:
+ db "Congrats! This"
+ next "diploma certifies"
+ next "that you have"
+ next "completed your"
+ next "#DEX.@"
+
+String_e9ac8:
+ db "GAME FREAK@"
+
+Func_e9ad3:
+ call ClearScreen
+ coord hl, 0, 17
+ call Func_e9bdf
+ coord hl, 0, 0
+ call Func_e9beb
+ coord hl, 19, 0
+ call Func_e9beb
+ ld a, $00
+ coord hl, 0, 17
+ ld [hl], a
+ coord hl, 19, 17
+ ld [hl], a
+ ld de, Tilemap_e9b3e
+ coord hl, 6, 2
+ lb bc, 10, 12
+ call Diploma_Surfing_CopyBox
+ ld de, Tilemap_e9bb6
+ coord hl, 5, 13
+ lb bc, 1, 11
+ call Diploma_Surfing_CopyBox
+ ld de, String_e9bd5
+ coord hl, 2, 15
+ call PlaceString
+ coord hl, 12, 15
+ ld de, wPlayTimeHours
+ lb bc, $40 | 1, 3
+ call PrintNumber
+ ld [hl], $16
+ inc hl
+ ld de, wPlayTimeMinutes
+ lb bc, $80 | 1, 2
+ call PrintNumber
+ ld a, [wNumSetBits]
+ cp 151
+ ret nz
+ ld de, TileMap_e9bc1
+ coord hl, 2, 0
+ lb bc, 4, 5
+ call Diploma_Surfing_CopyBox
+ ret
+
+Tilemap_e9b3e:
+ db $7f, $7f, $7f, $1a, $1b, $7f, $7f, $7f, $7f, $7f
+ db $7f, $7f, $7f, $7f, $7f, $1c, $1d, $1e, $1f, $20
+ db $7f, $21, $22, $23, $7f, $24, $25, $26, $27, $28
+ db $29, $2a, $2b, $2c, $2d, $2e, $2f, $30, $31, $32
+ db $33, $34, $35, $36, $37, $38, $39, $3a, $3b, $3c
+ db $7f, $3d, $3e, $3f, $40, $41, $42, $43, $29, $44
+ db $45, $46, $47, $48, $49, $4a, $4b, $29, $29, $4c
+ db $4d, $4e, $4f, $50, $51, $52, $53, $54, $55, $56
+ db $57, $58, $59, $7f, $7f, $7f, $5a, $5b, $5c, $5d
+ db $5e, $5f, $60, $61, $62, $7f, $7f, $7f, $7f, $63
+ db $64, $65, $66, $67, $68, $7f, $7f, $7f, $7f, $7f
+ db $7f, $69, $6a, $6b, $6c, $6d, $6e, $7f, $7f, $7f
+
+Tilemap_e9bb6:
+ db $05
+ db $06
+ db $07
+ db $08
+ db $09
+ db $0a
+ db $0b
+ db $0c
+ db $0d
+ db $0e
+ db $0f
+
+TileMap_e9bc1:
+ db $70, $71, $7f, $72, $7f
+ db $73, $74, $75, $76, $77
+ db $7f, $78, $11, $12, $13
+ db $7f, $7f, $14, $15, $7f
+
+String_e9bd5: db "PLAY TIME@"
+
+Func_e9bdf:
+ ld c, 10
+.asm_e9be1
+ ld [hl], $02
+ inc hl
+ ld [hl], $01
+ inc hl
+ dec c
+ jr nz, .asm_e9be1
+ ret
+
+Func_e9beb:
+ ld c, 9
+ ld de, SCREEN_WIDTH
+.asm_e9bed
+ ld [hl], $04
+ add hl, de
+ ld [hl], $03
+ add hl, de
+ dec c
+ jr nz, .asm_e9bed
+ ret
diff --git a/engine/display_text_id_init.asm b/engine/display_text_id_init.asm
index 59b3a5f8..0ef37370 100644
--- a/engine/display_text_id_init.asm
+++ b/engine/display_text_id_init.asm
@@ -14,19 +14,16 @@ DisplayTextIDInit:
CheckEvent EVENT_GOT_POKEDEX
; start menu with pokedex
coord hl, 10, 0
- ld b, $0e
- ld c, $08
+ lb bc, 14, 8
jr nz, .drawTextBoxBorder
; start menu without pokedex
coord hl, 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
coord hl, 0, 12
- ld b, $04
- ld c, $12
+ lb bc, 4, 18
.drawTextBoxBorder
call TextBoxBorder
.skipDrawingTextBoxBorder
diff --git a/engine/evolution.asm b/engine/evolution.asm
index 731735c5..7277e991 100755
--- a/engine/evolution.asm
+++ b/engine/evolution.asm
@@ -9,9 +9,7 @@ EvolveMon:
xor a
ld [wLowHealthAlarm], a
ld [wChannelSoundIDs + Ch5], a
- dec a
- ld [wNewSoundID], a
- call PlaySound
+ call StopAllMusic
ld a, $1
ld [H_AUTOBGTRANSFERENABLED], a
ld a, SFX_TINK
@@ -67,9 +65,7 @@ EvolveMon:
ld a, [wEvoNewSpecies]
.done
ld [wWholeScreenPaletteMonSpecies], a
- ld a, $ff
- ld [wNewSoundID], a
- call PlaySound
+ call StopAllMusic
ld a, [wWholeScreenPaletteMonSpecies]
call PlayCry
ld c, 0
diff --git a/engine/evolve_trade.asm b/engine/evolve_trade.asm
deleted file mode 100755
index e17fc05c..00000000
--- a/engine/evolve_trade.asm
+++ /dev/null
@@ -1,44 +0,0 @@
-EvolveTradeMon:
-; Verify the TradeMon's species name before
-; attempting to initiate a trade evolution.
-
-; The names of the trade evolutions in Blue (JP)
-; are checked. In that version, TradeMons that
-; can evolve are Graveler and Haunter.
-
-; In localization, this check was translated
-; before monster names were finalized.
-; Then, Haunter's name was "Spectre".
-; Since its name no longer starts with
-; "SP", it is prevented from evolving.
-
-; This may have been why Red/Green's trades
-; were used instead, where none can evolve.
-
-; This was fixed in Yellow.
-
- ld a, [wInGameTradeReceiveMonName]
-
- ; GRAVELER
- cp "G"
- jr z, .ok
-
- ; "SPECTRE" (HAUNTER)
- cp "S"
- ret nz
- ld a, [wInGameTradeReceiveMonName + 1]
- cp "P"
- ret nz
-
-.ok
- ld a, [wPartyCount]
- dec a
- ld [wWhichPokemon], a
- ld a, $1
- ld [wForceEvolution], a
- ld a, LINK_STATE_TRADING
- ld [wLinkState], a
- callab TryEvolvingMon
- xor a ; LINK_STATE_NONE
- ld [wLinkState], a
- jp PlayDefaultMusic
diff --git a/engine/evos_moves.asm b/engine/evos_moves.asm
index f50f8081..8ec2c4c7 100755
--- a/engine/evos_moves.asm
+++ b/engine/evos_moves.asm
@@ -1,5 +1,6 @@
; try to evolve the mon in [wWhichPokemon]
TryEvolvingMon:
+EvolveTradeMon:
ld hl, wCanEvolveFlags
xor a
ld [hl], a
@@ -93,9 +94,13 @@ 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]
+ jp nz, .nextEvoEntry1 ; don't evolve if we're in a battle as wcf91 could be holding the last mon sent out
+
ld b, a ; evolution item
- ld a, [wcf91] ; this is supposed to be the last item used, but it is also used to hold species numbers
+ ld a, [wcf91] ; last item used
cp b ; was the evolution item in this entry used?
jp nz, .nextEvoEntry1 ; if not, go to the next evolution entry
.checkLevel
@@ -140,7 +145,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
@@ -318,23 +323,9 @@ Evolution_ReloadTilesetTilePatterns:
jp ReloadTilesetTilePatterns
LearnMoveFromLevelUp:
- ld hl, EvosMovesPointerTable
ld a, [wd11e] ; species
ld [wcf91], 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?
@@ -370,33 +361,180 @@ LearnMoveFromLevelUp:
call GetMoveName
call CopyStringToCF4B
predef LearnMove
+ ld a, b
+ and a
+ jr z, .done
+ callab IsThisPartymonStarterPikachu_Party
+ jr nc, .done
+ ld a, [wMoveNum]
+ cp THUNDERBOLT
+ jr z, .foundThunderOrThunderbolt
+ cp THUNDER
+ jr nz, .done
+.foundThunderOrThunderbolt
+ ld a, $5
+ ld [wd49c], a
+ ld a, $85
+ ld [wPikachuMood], a
.done
ld a, [wcf91]
ld [wd11e], a
ret
-; writes the moves a mon has at level [wCurEnemyLVL] 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
+Func_3b079:
+ ld a, [wcf91]
+ 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 [wcf91], a
+ and a
+ ret
+.asm_3b09c
+ pop af
+ ld [wcf91], a
+ scf
+ ret
+
+Func_3b0a2:
+; XXX what is wcf91 entering this function?
+ ld a, [wd11e]
+ ld [wMoveNum], a
+ predef CanLearnTM
+ ld a, c
+ and a
+ jr nz, .asm_3b0ec
+ ld hl, Pointer_3b0ee
+ ld a, [wcf91]
+ ld de, $1
+ call IsInArray
+ jr c, .asm_3b0d2
+ ld a, $ff
+ ld [wMonHGrowthRate], a
+ ld a, [wd11e]
+ ld hl, wMonHMoves
+ ld de, $1
+ call IsInArray
+ jr c, .asm_3b0ec
+.asm_3b0d2
+ ld a, [wd11e]
+ ld d, a
+ call GetMonLearnset
+.loop
+ ld a, [hli]
+ and a
+ jr z, .asm_3b0ea
+ ld b, a
+ ld a, [wCurEnemyLVL]
+ 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
+
+Pointer_3b0ee:
+ db NIDOKING
+ db IVYSAUR
+ db EXEGGUTOR
+ db GENGAR
+ db NIDOQUEEN
+ db ARCANINE
+ db GYARADOS
+ db BLASTOISE
+ db GOLEM
+ db DRAGONITE
+ db NINETALES
+ db DRAGONAIR
+ db KABUTOPS
+ db OMASTAR
+ db JIGGLYPUFF
+ db FLAREON
+ db JOLTEON
+ db VAPOREON
+ db BEEDRILL
+ db BUTTERFREE
+ db MACHAMP
+ db CLOYSTER
+ db CLEFABLE
+ db ALAKAZAM
+ db STARMIE
+ db VENUSAUR
+ db TENTACRUEL
+ db CHARMELEON
+ db WARTORTLE
+ db CHARIZARD
+ db VILEPLUME
+ db VICTREEBEL
+ db $ff
+
+Func_3b10f:
+ ld c, $0
+.asm_3b111
ld hl, EvosMovesPointerTable
- ld b, 0
- ld a, [wcf91] ; cur mon ID
- dec a
- add a
- rl b
- ld c, a
+ 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, [wcf91]
+ 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 [wcf91], a
+ scf
+ ret
+
+; writes the moves a mon has at level [wCurEnemyLVL] 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
@@ -510,4 +648,21 @@ WriteMonMoves_ShiftMoveData:
Evolution_FlagAction:
predef_jump FlagActionPredef
+GetMonLearnset:
+ ld hl, EvosMovesPointerTable
+ ld b, 0
+ ld a, [wcf91]
+ 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/evos_moves.asm"
diff --git a/engine/gamefreak.asm b/engine/gamefreak.asm
index 5226072b..5472a56e 100755
--- a/engine/gamefreak.asm
+++ b/engine/gamefreak.asm
@@ -3,6 +3,8 @@ LoadShootingStarGraphics:
ld [rOBP0], a
ld a, $a4
ld [rOBP1], a
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
ld de, AnimationTileset2 + $30 ; star tile (top left quadrant)
ld hl, vChars1 + $200
lb bc, BANK(AnimationTileset2), $01
@@ -75,6 +77,7 @@ AnimateShootingStar:
ld hl, rOBP0
rrc [hl]
rrc [hl]
+ call UpdateGBCPal_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,27 +174,35 @@ 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 $FF
@@ -204,7 +224,7 @@ MoveDownSmallStars:
ld a, [rOBP1]
xor %10100000
ld [rOBP1], a
-
+ call UpdateGBCPal_OBP1
ld c, 3
call CheckForUserInterruption
ret c
@@ -232,10 +252,10 @@ GameFreakLogoOAMData:
GameFreakLogoOAMDataEnd:
GameFreakShootingStarOAMData:
- db $00,$A0,$A0,$10
- db $00,$A8,$A0,$30
- db $08,$A0,$A1,$10
- db $08,$A8,$A1,$30
+ db $00,$A0,$A0,$14
+ db $00,$A8,$A0,$34
+ db $08,$A0,$A1,$14
+ db $08,$A8,$A1,$34
GameFreakShootingStarOAMDataEnd:
FallingStar:
diff --git a/engine/give_pokemon.asm b/engine/give_pokemon.asm
index 49596782..6fdca2ef 100755
--- a/engine/give_pokemon.asm
+++ b/engine/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:
+ db "@"
+
GotMonText:
TX_FAR _GotMonText
TX_SFX_ITEM_1
diff --git a/engine/hall_of_fame.asm b/engine/hall_of_fame.asm
index 3c9b1723..39a7a2e3 100755
--- a/engine/hall_of_fame.asm
+++ b/engine/hall_of_fame.asm
@@ -58,8 +58,7 @@ AnimateHallOfFame:
ld c, 80
call DelayFrames
coord hl, 2, 13
- ld b, 3
- ld c, 14
+ lb bc, 3, 14
call TextBoxBorder
coord hl, 4, 15
ld de, HallOfFameText
@@ -77,7 +76,7 @@ AnimateHallOfFame:
ld bc, HOF_MON
call AddNTimes
ld [hl], $ff
- call SaveHallOfFameTeams
+ callab SaveHallOfFameTeams ; useless since in same bank
xor a
ld [wHoFMonSpecies], a
inc a
@@ -122,6 +121,7 @@ HoFShowMonOrPlayer:
call RunPaletteCommand
ld a, %11100100
ld [rBGP], a
+ call UpdateGBCPal_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
+ callab IsThisPartymonStarterPikachu_Party
+ jr nc, .asm_70336
+ ld e, $22
+ callab 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:
coord hl, 0, 2
- ld b, 9
- ld c, 10
+ lb bc, 9, 10
call TextBoxBorder
coord hl, 2, 6
ld de, HoFMonInfoText
@@ -174,8 +189,7 @@ HoFDisplayMonInfo:
ld [wd0b5], a
coord hl, 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,$0
+ call SwitchSRAMBankAndLatchClockData
ld hl, sSpriteBuffer1
ld de, sSpriteBuffer0
ld bc, $310
call CopyData
+ call PrepareRTCDataAndDisableSRAM
ld de, vFrontPic
call InterlaceMergeSpriteBuffers
ld de, RedPicBack
@@ -210,12 +227,10 @@ HoFDisplayPlayerStats:
SetEvent EVENT_HALL_OF_FAME_DEX_RATING
predef DisplayDexRating
coord hl, 0, 4
- ld b, 6
- ld c, 10
+ lb bc, 6, 10
call TextBoxBorder
coord hl, 5, 0
- ld b, 2
- ld c, 9
+ lb bc, 2, 9
call TextBoxBorder
coord hl, 7, 2
ld de, wPlayerName
diff --git a/engine/hidden_object_functions14.asm b/engine/hidden_object_functions14.asm
index f8cdf44e..04f9cb35 100755
--- a/engine/hidden_object_functions14.asm
+++ b/engine/hidden_object_functions14.asm
@@ -89,7 +89,7 @@ FightingDojoText:
db "@"
PrintIndigoPlateauHQText:
- ld a, [wSpriteStateData1 + 9]
+ ld a, [wSpritePlayerStateData1FacingDirection]
cp SPRITE_FACING_UP
ret nz
call EnableAutoTextBoxDrawing
diff --git a/engine/hidden_object_functions17.asm b/engine/hidden_object_functions17.asm
index c1fa5aa4..8775fd39 100755
--- a/engine/hidden_object_functions17.asm
+++ b/engine/hidden_object_functions17.asm
@@ -14,7 +14,7 @@ RedBedroomPCText:
TX_PLAYERS_PC
Route15GateLeftBinoculars:
- ld a, [wSpriteStateData1 + 9]
+ ld a, [wSpritePlayerStateData1FacingDirection]
cp SPRITE_FACING_UP
ret nz
call EnableAutoTextBoxDrawing
@@ -22,7 +22,10 @@ Route15GateLeftBinoculars:
ld a, ARTICUNO
ld [wcf91], a
call PlayCry
- jp DisplayMonFrontSpriteInBox
+ call DisplayMonFrontSpriteInBox
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ret
Route15UpstairsBinocularsText:
TX_FAR _Route15UpstairsBinocularsText
@@ -52,6 +55,30 @@ KabutopsFossilText:
TX_FAR _KabutopsFossilText
db "@"
+FanClubPicture1:
+ ld a, RAPIDASH
+ ld [wcf91], a
+ call DisplayMonFrontSpriteInBox
+ call EnableAutoTextBoxDrawing
+ tx_pre FanClubPicture1Text
+ ret
+
+FanClubPicture1Text:
+ TX_FAR _FanClubPicture1Text
+ db "@"
+
+FanClubPicture2:
+ ld a, FEAROW
+ ld [wcf91], a
+ call DisplayMonFrontSpriteInBox
+ call EnableAutoTextBoxDrawing
+ tx_pre FanClubPicture2Text
+ ret
+
+FanClubPicture2Text:
+ TX_FAR _FanClubPicture2Text
+ db "@"
+
DisplayMonFrontSpriteInBox:
; Displays a pokemon's front sprite in a pop-up window.
; [wcf91] = pokemon internal id number
@@ -110,8 +137,7 @@ LinkCableHelp:
ld hl, wd730
set 6, [hl]
coord hl, 0, 0
- ld b, 8
- ld c, 13
+ lb bc, 8, 13
call TextBoxBorder
coord hl, 2, 2
ld de, HowToLinkText
@@ -339,53 +365,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]
-
-; There is a bug in this code. It 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.
-
- ld [hGymTrashCanRandNumMask], a
- push hl
- call Random
- swap a
- ld b, a
- ld 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
-
+ callab 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
@@ -413,25 +403,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:
TX_FAR _VermilionGymTrashSuccessText1
diff --git a/engine/hidden_object_functions18.asm b/engine/hidden_object_functions18.asm
index c6fb3109..3fd5dd47 100755
--- a/engine/hidden_object_functions18.asm
+++ b/engine/hidden_object_functions18.asm
@@ -3,7 +3,7 @@ GymStatues:
; if in a gym and don’t have the corresponding badge, a = GymStatueText1_id and jp PrintPredefTextID
; else ret
call EnableAutoTextBoxDrawing
- ld a, [wSpriteStateData1 + 9]
+ ld a, [wSpritePlayerStateData1FacingDirection]
cp SPRITE_FACING_UP
ret nz
ld hl, .BadgeFlags
@@ -29,14 +29,14 @@ GymStatues:
jp PrintPredefTextID
.BadgeFlags:
- db PEWTER_GYM, %00000001
- db CERULEAN_GYM, %00000010
- db VERMILION_GYM,%00000100
- db CELADON_GYM, %00001000
- db FUCHSIA_GYM, %00010000
- db SAFFRON_GYM, %00100000
- db CINNABAR_GYM, %01000000
- db VIRIDIAN_GYM, %10000000
+ db PEWTER_GYM, %00000001
+ db CERULEAN_GYM, %00000010
+ db VERMILION_GYM, %00000100
+ db CELADON_GYM, %00001000
+ db FUCHSIA_GYM, %00010000
+ db SAFFRON_GYM, %00100000
+ db CINNABAR_GYM, %01000000
+ db VIRIDIAN_GYM, %10000000
db $ff
GymStatueText1:
@@ -64,7 +64,7 @@ PrintBenchGuyText:
.match
ld a, [hli]
ld b, a
- ld a, [wSpriteStateData1 + 9]
+ ld a, [wSpritePlayerStateData1FacingDirection]
cp b
jr nz, .loop ; player isn't facing left at the bench guy
ld a, [hl]
@@ -72,30 +72,36 @@ PrintBenchGuyText:
; format: db map id, player sprite facing direction, text id of PredefTextIDPointerTable
BenchGuyTextPointers:
- db VIRIDIAN_POKECENTER, SPRITE_FACING_LEFT
+ db VIRIDIAN_POKECENTER, SPRITE_FACING_LEFT
db_tx_pre ViridianCityPokecenterBenchGuyText
- db PEWTER_POKECENTER, SPRITE_FACING_LEFT
+ db PEWTER_POKECENTER, SPRITE_FACING_LEFT
db_tx_pre PewterCityPokecenterBenchGuyText
- db CERULEAN_POKECENTER, SPRITE_FACING_LEFT
+ db CERULEAN_POKECENTER, SPRITE_FACING_LEFT
db_tx_pre CeruleanCityPokecenterBenchGuyText
- db LAVENDER_POKECENTER, SPRITE_FACING_LEFT
+ db LAVENDER_POKECENTER, SPRITE_FACING_LEFT
db_tx_pre LavenderCityPokecenterBenchGuyText
- db VERMILION_POKECENTER, SPRITE_FACING_LEFT
+ db VERMILION_POKECENTER, SPRITE_FACING_LEFT
db_tx_pre VermilionCityPokecenterBenchGuyText
- db CELADON_POKECENTER, SPRITE_FACING_LEFT
+ db CELADON_POKECENTER, SPRITE_FACING_LEFT
db_tx_pre CeladonCityPokecenterBenchGuyText
- db CELADON_HOTEL, SPRITE_FACING_LEFT
+ db CELADON_HOTEL, SPRITE_FACING_LEFT
db_tx_pre CeladonCityHotelText
- db FUCHSIA_POKECENTER, SPRITE_FACING_LEFT
+ db FUCHSIA_POKECENTER, SPRITE_FACING_LEFT
db_tx_pre FuchsiaCityPokecenterBenchGuyText
- db CINNABAR_POKECENTER, SPRITE_FACING_LEFT
+ db CINNABAR_POKECENTER, SPRITE_FACING_LEFT
db_tx_pre CinnabarIslandPokecenterBenchGuyText
- db SAFFRON_POKECENTER, SPRITE_FACING_LEFT
+ db SAFFRON_POKECENTER, SPRITE_FACING_LEFT
db_tx_pre SaffronCityPokecenterBenchGuyText
- db MT_MOON_POKECENTER, SPRITE_FACING_LEFT
+ db MT_MOON_POKECENTER, SPRITE_FACING_LEFT
db_tx_pre MtMoonPokecenterBenchGuyText
- db ROCK_TUNNEL_POKECENTER,SPRITE_FACING_LEFT
+ db ROCK_TUNNEL_POKECENTER, SPRITE_FACING_LEFT
db_tx_pre RockTunnelPokecenterBenchGuyText
+ db SAFARI_ZONE_WEST_REST_HOUSE,SPRITE_FACING_LEFT
+ db_tx_pre UnusedBenchGuyText1
+ db SAFARI_ZONE_EAST_REST_HOUSE,SPRITE_FACING_LEFT
+ db_tx_pre UnusedBenchGuyText2
+ db SAFARI_ZONE_NORTH_REST_HOUSE,SPRITE_FACING_LEFT
+ db_tx_pre UnusedBenchGuyText3
db $FF
ViridianCityPokecenterBenchGuyText:
@@ -186,7 +192,7 @@ BookcaseText:
db "@"
OpenPokemonCenterPC:
- ld a, [wSpriteStateData1 + 9]
+ ld a, [wSpritePlayerStateData1FacingDirection]
cp SPRITE_FACING_UP ; check to see if player is facing up
ret nz
call EnableAutoTextBoxDrawing
diff --git a/engine/hidden_object_functions3.asm b/engine/hidden_object_functions3.asm
index aaedcbca..11aecd5b 100755
--- a/engine/hidden_object_functions3.asm
+++ b/engine/hidden_object_functions3.asm
@@ -1,6 +1,6 @@
; prints text for bookshelves in buildings without sign events
PrintBookshelfText:
- ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+ ld a, [wSpritePlayerStateData1FacingDirection] ; player's sprite facing direction
cp SPRITE_FACING_UP
jr nz, .noMatch
; facing up
diff --git a/engine/hidden_object_functions7.asm b/engine/hidden_object_functions7.asm
index 89be94fc..2498c167 100755
--- a/engine/hidden_object_functions7.asm
+++ b/engine/hidden_object_functions7.asm
@@ -65,8 +65,7 @@ SafariZoneGameOver:
call EnableAutoTextBoxDrawing
xor a
ld [wAudioFadeOutControl], a
- dec a
- call PlaySound
+ call StopAllMusic
ld c, BANK(SFX_Safari_Zone_PA)
ld a, SFX_SAFARI_ZONE_PA
call PlayMusic
@@ -117,7 +116,7 @@ GameOverText:
db "@"
PrintCinnabarQuiz:
- ld a, [wSpriteStateData1 + 9]
+ ld a, [wSpritePlayerStateData1FacingDirection]
cp SPRITE_FACING_UP
ret nz
call EnableAutoTextBoxDrawing
@@ -127,6 +126,8 @@ CinnabarGymQuiz:
TX_ASM
xor a
ld [wOpponentAfterWrongAnswer], a
+ ld hl, wd475
+ res 7, [hl]
ld a, [wHiddenObjectFunctionArgument]
push af
and $f
@@ -135,7 +136,12 @@ CinnabarGymQuiz:
and $f0
swap a
ld [$ffdc], a
+ ld a, [hGymGateIndex]
ld hl, CinnabarGymQuizIntroText
+ cp 1
+ jr z, .onFirstQuestion
+ ld hl, CinnabarGymQuizShortIntroText
+.onFirstQuestion
call PrintText
ld a, [hGymGateIndex]
dec a
@@ -153,10 +159,18 @@ CinnabarGymQuiz:
call CinnabarGymQuiz_1ea92
jp TextScriptEnd
+CinnabarGymQuizDummyIntroText:
+ TX_FAR _CinnabarGymQuizDummyIntroText
+ db "@"
+
CinnabarGymQuizIntroText:
TX_FAR _CinnabarGymQuizIntroText
db "@"
+CinnabarGymQuizShortIntroText:
+ TX_FAR _CinnabarGymQuizShortIntroText
+ db "@"
+
CinnabarQuizQuestions:
dw CinnabarQuizQuestionsText1
dw CinnabarQuizQuestionsText2
@@ -189,10 +203,6 @@ CinnabarQuizQuestionsText6:
TX_FAR _CinnabarQuizQuestionsText6
db "@"
-CinnabarGymGateFlagAction:
- EventFlagAddress hl, EVENT_CINNABAR_GYM_GATE0_UNLOCKED
- predef_jump FlagActionPredef
-
CinnabarGymQuiz_1ea92:
call YesNoChoice
ld a, [$ffdc]
@@ -232,6 +242,8 @@ CinnabarGymQuiz_1ea92:
ld a, [hGymGateIndex]
add $2
ld [wOpponentAfterWrongAnswer], a
+ ld hl, wd475
+ set 7, [hl]
ret
CinnabarGymQuizCorrectText:
@@ -258,6 +270,10 @@ CinnabarGymQuizIncorrectText:
TX_FAR _CinnabarGymQuizIncorrectText
db "@"
+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.
@@ -295,10 +311,11 @@ UpdateCinnabarGymGateTileBlocks_:
.next
pop bc
ld [wNewTileBlockID], a
- predef ReplaceTileBlock
+ call CinnabarGym_ReplaceTileBlock
ld hl, hGymGateIndex
dec [hl]
jr nz, .loop
+ callab RedrawMapView
ret
CinnabarGymGateCoords:
@@ -311,6 +328,34 @@ CinnabarGymGateCoords:
db $02,$06,$54,$00
db $02,$03,$54,$00
+
+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
+
PrintMagazinesText:
call EnableAutoTextBoxDrawing
tx_pre MagazinesText
@@ -322,7 +367,7 @@ MagazinesText:
BillsHousePC:
call EnableAutoTextBoxDrawing
- ld a, [wSpriteStateData1 + 9]
+ ld a, [wSpritePlayerStateData1FacingDirection]
cp SPRITE_FACING_UP
ret nz
CheckEvent EVENT_LEFT_BILLS_HOUSE_AFTER_HELPING
@@ -374,9 +419,7 @@ BillsHouseInitiatedText:
TX_FAR _BillsHouseInitiatedText
TX_BLINK
TX_ASM
- ld a, $ff
- ld [wNewSoundID], a
- call PlaySound
+ call StopAllMusic
ld c, 16
call DelayFrames
ld a, SFX_SWITCH
@@ -407,8 +450,7 @@ BillsHousePokemonList:
ld hl, wd730
set 6, [hl]
coord hl, 0, 0
- ld b, 10
- ld c, 9
+ lb bc, 10, 9
call TextBoxBorder
coord hl, 2, 2
ld de, BillsMonListText
@@ -456,11 +498,12 @@ BillsHousePokemonListText2:
db "@"
DisplayOakLabEmailText:
- ld a, [wSpriteStateData1 + 9]
+ ld a, [wSpritePlayerStateData1FacingDirection]
cp SPRITE_FACING_UP
ret nz
call EnableAutoTextBoxDrawing
- tx_pre_jump OakLabEmailText
+ tx_pre OakLabEmailText
+ ret
OakLabEmailText:
TX_FAR _OakLabEmailText
diff --git a/engine/hp_bar.asm b/engine/hp_bar.asm
index 221bd7a9..566a7b61 100755
--- a/engine/hp_bar.asm
+++ b/engine/hp_bar.asm
@@ -213,13 +213,11 @@ UpdateHPBar_PrintHPNumber:
ld a, [wHPBarOldHP + 1]
ld [wHPBarTempHP], a
push hl
- ld a, [hFlags_0xFFF6]
+ ld de, $15
+ ld a, [hFlags_0xFFFA]
bit 0, a
- jr z, .asm_fb15
+ jr z, .next
ld de, $9
- jr .next
-.asm_fb15
- ld de, $15
.next
add hl, de
push hl
diff --git a/engine/in_game_trades.asm b/engine/in_game_trades.asm
index c01bc3c3..720920df 100755
--- a/engine/in_game_trades.asm
+++ b/engine/in_game_trades.asm
@@ -3,13 +3,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]
@@ -35,18 +30,15 @@ DoInGameTradeDialogue:
ld a, [wInGameTradeReceiveMonSpecies]
ld de, wInGameTradeReceiveMonName
call InGameTrade_GetMonName
- ld hl, wCompletedInGameTradeFlags
- ld a, [wWhichTrade]
- ld c, a
+ ld a, $4
+ ld [wInGameTradeTextPointerTableIndex], a
ld b, FLAG_TEST
- predef FlagActionPredef
+ call InGameTrade_FlagActionPredef
ld a, c
and a
- ld a, $4
- ld [wInGameTradeTextPointerTableIndex], a
jr nz, .printText
; if the trade hasn't been done yet
- xor a
+ ld a, $0
ld [wInGameTradeTextPointerTableIndex], a
call .printText
ld a, $1
@@ -109,11 +101,8 @@ InGameTrade_DoTrade:
call AddNTimes
ld a, [hl]
ld [wCurEnemyLVL], 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]
@@ -137,7 +126,7 @@ InGameTrade_DoTrade:
ld [wMonDataLocation], a
call AddPartyMon
call InGameTrade_CopyDataToReceivedMon
- callab EvolveTradeMon
+ call InGameTrade_CheckForTradeEvo
call ClearScreen
call InGameTrade_RestoreScreen
callba RedrawMapView
@@ -229,6 +218,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
+ callab EvolveTradeMon
+ xor a ; LINK_STATE_NONE
+ ld [wLinkState],a
+ jp PlayDefaultMusic
+
InGameTrade_TrainerString:
; "TRAINER@@@@@@@@@@"
db $5d, "@@@@@@@@@@"
diff --git a/engine/init_player_data.asm b/engine/init_player_data.asm
index c576e65a..5883547c 100644
--- a/engine/init_player_data.asm
+++ b/engine/init_player_data.asm
@@ -12,6 +12,11 @@ InitPlayerData2:
ld a, $ff
ld [wUnusedD71B], 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, wNumInBox
diff --git a/engine/intro.asm b/engine/intro.asm
index a016b365..00e892da 100755
--- a/engine/intro.asm
+++ b/engine/intro.asm
@@ -16,8 +16,7 @@ PlayIntro:
inc a
ld [H_AUTOBGTRANSFERENABLED], a
call PlayShootingStar
- call PlayIntroScene
- call GBFadeOutToWhite
+ callab PlayIntroScene
xor a
ld [hSCX], a
ld [H_AUTOBGTRANSFERENABLED], a
@@ -25,162 +24,6 @@ PlayIntro:
call DelayFrame
ret
-PlayIntroScene:
- ld b, SET_PAL_NIDORINO_INTRO
- call RunPaletteCommand
- ldPal a, BLACK, DARK_GRAY, LIGHT_GRAY, WHITE
- ld [rBGP], a
- ld [rOBP0], a
- ld [rOBP1], a
- xor a
- ld [hSCX], a
- ld b, GENGAR_INTRO_TILES1
- 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, GENGAR_INTRO_TILES2
- 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, GENGAR_INTRO_TILES3
- 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) / BYTES_PER_TILE
- 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, GENGAR_INTRO_TILES1
- 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) / BYTES_PER_TILE
- 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) / BYTES_PER_TILE
- 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, wOAMBuffer
- 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, wOAMBuffer
ld d, 0
@@ -237,83 +80,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
- ld 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
- ld a, [hSCX]
- inc a
- inc a
-.next
- ld [hSCX], a
- push de
- ld c, 2
- call CheckForUserInterruption
- pop de
- ret c
- dec d
- jr nz, IntroMoveMon
- ret
-
-IntroCopyTiles:
- coord hl, 13, 7
-
CopyTileIDsFromList_ZeroBaseTileID:
ld c, 0
predef_jump CopyTileIDsFromList
-PlayMoveSoundB:
-; unused
- predef GetMoveSoundB
- 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
callba LoadCopyrightAndTextBoxTiles
ldPal a, BLACK, DARK_GRAY, LIGHT_GRAY, WHITE
ld [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 180
call DelayFrames
call ClearScreen
@@ -321,7 +98,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 5, [hl]
@@ -335,12 +132,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
@@ -364,79 +155,6 @@ IntroDrawBlackBars:
EmptyFunc4:
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/gamefreak_intro.2bpp"
INCBIN "gfx/gamefreak_logo.2bpp"
@@ -444,29 +162,3 @@ GameFreakIntro:
db $00 ; blank tile
endr
GameFreakIntroEnd:
-
-FightIntroBackMon:
- INCBIN "gfx/intro_fight.2bpp"
-FightIntroBackMonEnd:
-
-FightIntroFrontMon:
-
-IF DEF(_RED)
- INCBIN "gfx/red/intro_nido_1.2bpp"
-FightIntroFrontMon2:
- INCBIN "gfx/red/intro_nido_2.2bpp"
-FightIntroFrontMon3:
- INCBIN "gfx/red/intro_nido_3.2bpp"
-ENDC
-
-IF DEF(_BLUE)
- INCBIN "gfx/blue/intro_purin_1.2bpp"
-FightIntroFrontMon2:
- INCBIN "gfx/blue/intro_purin_2.2bpp"
-FightIntroFrontMon3:
- INCBIN "gfx/blue/intro_purin_3.2bpp"
-ENDC
-
-FightIntroFrontMonEnd:
-
- ds $10 ; blank tile
diff --git a/engine/items/inventory.asm b/engine/items/inventory.asm
index d07f64eb..58bcf7e9 100644
--- a/engine/items/inventory.asm
+++ b/engine/items/inventory.asm
@@ -27,16 +27,17 @@ AddItemToInventory_:
ld a, [hli]
and a
jr z, .addNewItem
-.loop
+.notAtEndOfInventory
ld a, [hli]
ld b, a ; b = ID of current item in table
ld a, [wcf91] ; a = ID of item being added
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
+.loop
ld a, [hl]
- cp $ff ; is it the end of the table?
- jr nz, .loop
+ cp a, $ff ; is it the end of the table?
+ jr nz, .notAtEndOfInventory
.addNewItem ; add an item not yet in the inventory
pop hl
ld a, d
@@ -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/items.asm b/engine/items/items.asm
index ec51a0d4..15c7c24f 100755
--- a/engine/items/items.asm
+++ b/engine/items/items.asm
@@ -113,7 +113,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?
@@ -152,16 +154,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
.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_02F
+ 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.
@@ -280,6 +292,7 @@ ItemUseBall:
inc a
.skip2
+
; Let W = ((MaxHP * 255) / BallFactor) / max(HP / 4, 1). Calculate W.
ld [H_DIVISOR], a
ld b, 4
@@ -347,6 +360,7 @@ ItemUseBall:
jr z, .skip4
.skip4
+
; Let Y = (CatchRate * 100) / BallFactor2. Calculate Y.
ld a, b
ld [H_DIVISOR], a
@@ -371,7 +385,7 @@ ItemUseBall:
ld [H_DIVISOR], a
ld b, 4
call Divide
-
+
; Determine Status2.
; no status ailment: Status2 = 0
; Burn/Paralysis/Poison: Status2 = 5
@@ -511,9 +525,10 @@ ItemUseBall:
ld [wcf91], a
ld [wd11e], 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
@@ -545,12 +560,18 @@ ItemUseBall:
predef ShowPokedexData
.skipShowingPokedexData
+ ld a, $1
+ ld [wd49c], 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
@@ -583,6 +604,9 @@ ItemUseBall:
ld [wItemQuantity], a
jp RemoveItemFromInventory
+.emptyString
+ db "@"
+
ItemUseBallText00:
;"It dodged the thrown ball!"
;"This pokemon can't be caught"
@@ -648,21 +672,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
ld [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
; used for Surf out-of-battle effect
ItemUseSurfboard:
@@ -672,7 +703,7 @@ ItemUseSurfboard:
jr z, .tryToStopSurfing
.tryToSurf
call IsNextTileShoreOrWater
- jp c, SurfingAttemptFailed
+ jp nc, SurfingAttemptFailed
ld hl, TilePairCollisionsWater
call CheckForTilePairCollisions
jp c, SurfingAttemptFailed
@@ -685,6 +716,7 @@ ItemUseSurfboard:
call PlayDefaultMusic ; play surfing music
ld hl, SurfingGotOnText
jp PrintText
+
.tryToStopSurfing
xor a
ld [hSpriteIndexOrTextID], a
@@ -697,23 +729,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, wd730
set 7, [hl]
xor a
@@ -721,7 +750,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
@@ -769,25 +800,43 @@ ItemUseEvoStone:
ld a, $ff
ld [wUpdateSpritesEnabled], a
call DisplayPartyMenu
+ ld a, [wcf91]
+ ld [wLoadedMon], a
pop bc
jr c, .canceledItemUse
ld a, b
ld [wcf91], a
- ld a, $01
- ld [wForceEvolution], a
+ call Func_d85d
+ jr nc, .noEffect
+ callab IsThisPartymonStarterPikachu_Party
+ jr nc, .notPlayerPikachu
+ ld e, $1b
+ callab PlayPikachuSoundClip
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMonNicks
+ call GetPartyMonName
+ ld hl, RefusingText
+ call PrintText
+ ld a, $4
+ ld [wd49c], a
+ ld a, $82
+ ld [wPikachuMood], a
+ jr .canceledItemUse
+
+.notPlayerPikachu
ld a, SFX_HEAL_AILMENT
call PlaySoundWaitForCurrent
call WaitForSoundToFinish
+ ld a, $01
+ ld [wForceEvolution], a
callab 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
@@ -796,6 +845,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, wcd6d
+ ld a, BANK(TryEvolvingMon)
+ ld bc, $2
+ call FarCopyData
+ ld hl, wcd6d
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, wcd6d
+ ld a, BANK(TryEvolvingMon)
+ ld bc, 13
+ call FarCopyData
+ ld hl, wcd6d
+.loop
+ ld a, [hli]
+ and a
+ jr z, .cannotEvolveWithUsedStone
+ inc hl
+ inc hl
+ cp EV_ITEM
+ jr nz, .loop
+ dec hl
+ dec hl
+ ld b, [hl]
+ ld a, [wcf91]
+ inc hl
+ inc hl
+ inc hl
+ cp b
+ jr nz, .loop
+ scf
+ ret
+
+.cannotEvolveWithUsedStone
+ and a
+ ret
+
+RefusingText:
+ TX_FAR _RefusingText
+ db "@"
+
ItemUseVitamin:
ld a, [wIsInBattle]
and a
@@ -804,7 +902,7 @@ ItemUseVitamin:
ItemUseMedicine:
ld a, [wPartyCount]
and a
- jp z, .emptyParty
+ jp z, Func_e4bf
ld a, [wWhichPokemon]
push af
ld a, [wcf91]
@@ -819,15 +917,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
@@ -843,6 +932,16 @@ ItemUseMedicine:
ld e, a
ld [wd0b5], a
pop af
+ push af
+ cp $28
+ jr nc, .asm_d906
+ push hl
+ push de
+ callabd_ModifyPikachuHappiness PIKAHAPPY_USEDITEM
+ pop de
+ pop hl
+.asm_d906
+ pop af
ld [wcf91], a
pop af
ld [wWhichPokemon], a
@@ -910,6 +1009,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]
@@ -927,7 +1027,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
+ callab Func_2fd6a
+ pop bc
+ pop de
+ pop hl
+ pop af
+ ld [wWhichPokemon], a
+
ld a, [wIsInBattle]
and a
jr z, .compareCurrentHPToMaxHP
@@ -952,6 +1067,7 @@ ItemUseMedicine:
pop de
pop hl
jr .compareCurrentHPToMaxHP
+
.notFainted
ld a, [wcf91]
cp REVIVE
@@ -987,6 +1103,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
@@ -1050,15 +1167,15 @@ ItemUseMedicine:
call AddNTimes ; calculate coordinates of HP bar of pokemon that used Softboiled
ld a, SFX_HEAL_HP
call PlaySoundWaitForCurrent
- ld a, [hFlags_0xFFF6]
+ ld a, [hFlags_0xFFFA]
set 0, a
- ld [hFlags_0xFFF6], a
+ ld [hFlags_0xFFFA], a
ld a, $02
ld [wHPBarType], a
predef UpdateHPBar2 ; animate HP bar decrease of pokemon that used Softboiled
- ld a, [hFlags_0xFFF6]
+ ld a, [hFlags_0xFFFA]
res 0, a
- ld [hFlags_0xFFF6], a
+ ld [hFlags_0xFFFA], a
pop af
ld b, a ; store heal amount (1/5 of max HP)
ld hl, wHPBarOldHP + 1
@@ -1071,6 +1188,7 @@ ItemUseMedicine:
pop af
ld [hl], a
jr .addHealAmount
+
.notUsingSoftboiled2
ld a, [wcf91]
cp SODA_POP
@@ -1125,6 +1243,7 @@ ItemUseMedicine:
cp MAX_REVIVE
jr z, .setCurrentHPToMaxHp ; if using a Max Revive
jr .updateInBattleData
+
.setCurrentHPToHalfMaxHP
dec hl
dec de
@@ -1139,6 +1258,7 @@ ItemUseMedicine:
ld [wHPBarNewHP], a
dec de
jr .doneHealingPartyHP
+
.setCurrentHPToMaxHp
ld a, [hli]
ld [de], a
@@ -1182,9 +1302,11 @@ ItemUseMedicine:
dec d
jr nz, .calculateHPBarCoordsLoop
jr .doneHealing
+
.healingItemNoEffect
call ItemUseNoEffect
jp .done
+
.doneHealing
ld a, [wPseudoItemID]
and a ; using Softboiled?
@@ -1200,15 +1322,15 @@ ItemUseMedicine:
jr z, .playStatusAilmentCuringSound
ld a, SFX_HEAL_HP
call PlaySoundWaitForCurrent
- ld a, [hFlags_0xFFF6]
+ ld a, [hFlags_0xFFFA]
set 0, a
- ld [hFlags_0xFFF6], a
+ ld [hFlags_0xFFFA], a
ld a, $02
ld [wHPBarType], a
predef UpdateHPBar2 ; animate the HP bar lengthening
- ld a, [hFlags_0xFFF6]
+ ld a, [hFlags_0xFFFA]
res 0, a
- ld [hFlags_0xFFF6], a
+ ld [hFlags_0xFFFA], a
ld a, REVIVE_MSG
ld [wPartyMenuTypeOrMessageID], a
ld a, [wcf91]
@@ -1219,6 +1341,7 @@ ItemUseMedicine:
ld a, POTION_MSG
ld [wPartyMenuTypeOrMessageID], a
jr .showHealingItemMessage
+
.playStatusAilmentCuringSound
ld a, SFX_HEAL_AILMENT
call PlaySoundWaitForCurrent
@@ -1235,6 +1358,7 @@ ItemUseMedicine:
call DelayFrames
call WaitForTextScrollButtonPress
jr .done
+
.canceledItemUse
xor a
ld [wActionResultOrTookBattleTurn], a ; item use failed
@@ -1250,6 +1374,7 @@ ItemUseMedicine:
and a
ret nz
jp ReloadMapData
+
.useVitamin
push hl
ld a, [hl]
@@ -1305,6 +1430,7 @@ ItemUseMedicine:
cp b
jr nz, .statNameInnerLoop
jr .statNameLoop
+
.gotStatName
ld de, wcf4b
ld bc, 10
@@ -1314,11 +1440,13 @@ ItemUseMedicine:
ld hl, VitaminStatRoseText
call PrintText
jp RemoveUsedItem
+
.vitaminNoEffect
pop hl
ld hl, VitaminNoEffectText
call PrintText
jp GBPalWhiteOut
+
.recalculateStats
ld bc, wPartyMon1Stats - wPartyMon1
add hl, bc
@@ -1405,9 +1533,19 @@ ItemUseMedicine:
xor a ; PLAYER_PARTY_DATA
ld [wMonDataLocation], a
predef LearnMoveFromLevelUp ; learn level up move, if any
+
xor a
ld [wForceEvolution], a
- callab TryEvolvingMon ; evolve pokemon, if appropriate
+ callabd_ModifyPikachuHappiness PIKAHAPPY_LEVELUP
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wUsedItemOnWhichPokemon]
+ ld [wWhichPokemon], a
+ callab Func_2fd6a ; evolve pokemon, if appropriate
+ pop af
+ ld [wWhichPokemon], a
+
+ callab TryEvolvingMon
ld a, $01
ld [wUpdateSpritesEnabled], a
pop af
@@ -1494,6 +1632,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
@@ -1506,6 +1648,7 @@ ItemUseEscapeRope:
ld hl, wd732
set 3, [hl]
set 6, [hl]
+ call Func_1510
ld hl, wd72e
res 4, [hl]
ResetEvent EVENT_IN_SAFARI_ZONE
@@ -1522,6 +1665,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
+ callabd_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 [wUnusedD71F], a
jr .done
+
.nextEntry1
inc hl
.nextEntry2
@@ -1594,6 +1742,7 @@ ItemUseCardKey:
.nextEntry3
inc hl
jr .loop
+
.done
ld hl, ItemUseText00
call PrintText
@@ -1612,34 +1761,34 @@ ItemUseCardKey:
; 03: ID?
CardKeyTable1:
- db SILPH_CO_2F,$04,$04,$00
- db SILPH_CO_2F,$04,$05,$01
- db SILPH_CO_4F,$0C,$04,$02
- db SILPH_CO_4F,$0C,$05,$03
- db SILPH_CO_7F,$06,$0A,$04
- db SILPH_CO_7F,$06,$0B,$05
- db SILPH_CO_9F,$04,$12,$06
- db SILPH_CO_9F,$04,$13,$07
- db SILPH_CO_10F,$08,$0A,$08
- db SILPH_CO_10F,$08,$0B,$09
+ db SILPH_CO_2F, $04, $04, $00
+ db SILPH_CO_2F, $04, $05, $01
+ db SILPH_CO_4F, $0C, $04, $02
+ db SILPH_CO_4F, $0C, $05, $03
+ db SILPH_CO_7F, $06, $0A, $04
+ db SILPH_CO_7F, $06, $0B, $05
+ db SILPH_CO_9F, $04, $12, $06
+ db SILPH_CO_9F, $04, $13, $07
+ db SILPH_CO_10F, $08, $0A, $08
+ db SILPH_CO_10F, $08, $0B, $09
db $ff
CardKeyTable2:
- db SILPH_CO_3F,$08,$09,$0A
- db SILPH_CO_3F,$09,$09,$0B
- db SILPH_CO_5F,$04,$07,$0C
- db SILPH_CO_5F,$05,$07,$0D
- db SILPH_CO_6F,$0C,$05,$0E
- db SILPH_CO_6F,$0D,$05,$0F
- db SILPH_CO_8F,$08,$07,$10
- db SILPH_CO_8F,$09,$07,$11
- db SILPH_CO_9F,$08,$03,$12
- db SILPH_CO_9F,$09,$03,$13
+ db SILPH_CO_3F, $08, $09, $0A
+ db SILPH_CO_3F, $09, $09, $0B
+ db SILPH_CO_5F, $04, $07, $0C
+ db SILPH_CO_5F, $05, $07, $0D
+ db SILPH_CO_6F, $0C, $05, $0E
+ db SILPH_CO_6F, $0D, $05, $0F
+ db SILPH_CO_8F, $08, $07, $10
+ db SILPH_CO_8F, $09, $07, $11
+ db SILPH_CO_9F, $08, $03, $12
+ db SILPH_CO_9F, $09, $03, $13
db $ff
CardKeyTable3:
- db SILPH_CO_11F,$08,$09,$14
- db SILPH_CO_11F,$09,$09,$15
+ db SILPH_CO_11F, $08, $09, $14
+ db SILPH_CO_11F, $09, $09, $15
db $ff
ItemUsePokedoll:
@@ -1654,6 +1803,15 @@ ItemUseGuardSpec:
ld a, [wIsInBattle]
and a
jp z, ItemUseNotTime
+
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wPlayerMonNumber]
+ ld [wWhichPokemon], a
+ callabd_ModifyPikachuHappiness PIKAHAPPY_USEDXITEM
+ pop af
+ ld [wWhichPokemon], a
+
ld hl, wPlayerBattleStatus2
set PROTECTED_BY_MIST, [hl] ; Mist bit
jp PrintItemUseTextAndRemoveItem
@@ -1670,6 +1828,15 @@ ItemUseDireHit:
ld a, [wIsInBattle]
and a
jp z, ItemUseNotTime
+
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wPlayerMonNumber]
+ ld [wWhichPokemon], a
+ callabd_ModifyPikachuHappiness PIKAHAPPY_USEDXITEM
+ pop af
+ ld [wWhichPokemon], a
+
ld hl, wPlayerBattleStatus2
set GETTING_PUMPED, [hl] ; Focus Energy bit
jp PrintItemUseTextAndRemoveItem
@@ -1682,6 +1849,7 @@ ItemUseXStat:
ld a, 2
ld [wActionResultOrTookBattleTurn], a ; item not used
ret
+
.inBattle
ld hl, wPlayerMoveNum
ld a, [hli]
@@ -1700,6 +1868,15 @@ ItemUseXStat:
xor a
ld [H_WHOSETURN], a ; set turn to player's turn
callba StatModifierUpEffect ; do stat increase move
+
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wPlayerMonNumber]
+ ld [wWhichPokemon], a
+ callabd_ModifyPikachuHappiness PIKAHAPPY_USEDXITEM
+ pop af
+ ld [wWhichPokemon], a
+
pop hl
pop af
ld [hld], a ; restore [wPlayerMoveEffect]
@@ -1717,31 +1894,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
+ callab IsPikachuRightNextToPlayer
+ jr nc, .noSnorlaxOrPikachuToWakeUp
+ ld hl, PlayedFluteHadEffectText
+ call PrintText
+ call ItemUseReloadOverworldData
+ ldpikaemotion e, PikachuEmotion26
+ callab PlaySpecificPikachuEmotion
+ ret
+
+.noSnorlaxOrPikachuToWakeUp
ld hl, PlayedFluteNoEffectText
jp PrintText
+
.inBattle
xor a
ld [wWereAnyMonsAsleep], a
@@ -1761,8 +1955,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
+ 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?
@@ -1814,18 +2015,18 @@ WakeUpEntireParty:
; 00: Y
; 01: X
Route12SnorlaxFluteCoords:
- db 62,9 ; one space West of Snorlax
- db 61,10 ; one space North of Snorlax
- db 63,10 ; one space South of Snorlax
- db 62,11 ; one space East of Snorlax
+ db 62, 9 ; one space West of Snorlax
+ db 61, 10 ; one space North of Snorlax
+ db 63, 10 ; one space South of Snorlax
+ db 62, 11 ; one space East of Snorlax
db $ff ; terminator
; Format:
; 00: Y
; 01: X
Route16SnorlaxFluteCoords:
- db 10,27 ; one space East of Snorlax
- db 10,25 ; one space West of Snorlax
+ db 10, 27 ; one space East of Snorlax
+ db 10, 25 ; one space West of Snorlax
db $ff ; terminator
PlayedFluteNoEffectText:
@@ -1844,8 +2045,7 @@ PlayedFluteHadEffectText:
and a
jr nz, .done
; play out-of-battle pokeflute music
- ld a, $ff
- call PlaySound ; turn off music
+ call StopAllMusic ; turn off music
ld a, SFX_POKEFLUTE
ld c, BANK(SFX_Pokeflute)
call PlayMusic
@@ -1906,13 +2106,28 @@ INCLUDE "data/good_rod.asm"
ItemUseSuperRod:
call FishingInit
jp c, ItemUseNotTime
- call ReadSuperRodData
- ld a, e
+ callab 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
@@ -1921,7 +2136,7 @@ RodResponse:
ld a, c ; species
ld [wCurOpponent], a
-.next
+DoNotGenerateFishingEncounter:
ld hl, wWalkBikeSurfState
ld a, [hl] ; store the value in a
push af
@@ -1941,22 +2156,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 [wd49c], a
+ ld a, $81
+ ld [wPikachuMood], a
ld c, 80
call DelayFrames
and a
ret
-.surfing
+
+.cannotFish
scf ; can't fish when surfing
ret
@@ -2009,7 +2230,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
@@ -2049,6 +2286,7 @@ ItemUsePPRestore:
ld hl, PPMaxedOutText
call PrintText
jr .chooseMove
+
.PPNotMaxedOut
ld a, [hl]
add 1 << 6 ; increase PP Up count by 1
@@ -2056,6 +2294,8 @@ ItemUsePPRestore:
ld a, 1 ; 1 PP Up used
ld [wd11e], a
call RestoreBonusPP ; add the bonus PP to current PP
+ ld a, SFX_HEAL_AILMENT
+ call PlaySound
ld hl, PPIncreasedText
call PrintText
.done
@@ -2064,6 +2304,7 @@ ItemUsePPRestore:
call GBPalWhiteOut
call RunDefaultPaletteCommand
jp RemoveUsedItem
+
.afterRestoringPP ; after using a (Max) Ether/Elixir
ld a, [wWhichPokemon]
ld b, a
@@ -2082,10 +2323,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
@@ -2120,6 +2363,7 @@ ItemUsePPRestore:
add b
ld [hl], a
ret
+
.fullyRestorePP
ld a, [hl] ; move PP
; Note that this code has a bug. It doesn't mask out the upper two bits, which
@@ -2129,6 +2373,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
@@ -2232,6 +2477,7 @@ ItemUseTMHM:
ld a, 2
ld [wActionResultOrTookBattleTurn], a ; item not used
ret
+
.useMachine
ld a, [wWhichPokemon]
push af
@@ -2277,10 +2523,13 @@ ItemUseTMHM:
ld hl, MonCannotLearnMachineMoveText
call PrintText
jr .chooseMon
+
.checkIfAlreadyLearnedMove
callab 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 [wcf91], a
pop af
@@ -2288,6 +2537,28 @@ ItemUseTMHM:
ld a, b
and a
ret z
+
+ ld a, [wWhichPokemon]
+ push af
+ ld a, d
+ ld [wWhichPokemon], a
+ callabd_ModifyPikachuHappiness PIKAHAPPY_USEDTMHM
+ callab IsThisPartymonStarterPikachu_Party
+ jr nc, .notTeachingThunderboltOrThunderToPikachu
+ ld a, [wcf91]
+ cp TM_24 ; are we teaching thunderbolt to the player pikachu?
+ jr z, .teachingThunderboltOrThunderToPlayerPikachu
+ cp TM_25 ; are we teaching thunder then?
+ jr nz, .notTeachingThunderboltOrThunderToPikachu
+.teachingThunderboltOrThunderToPlayerPikachu
+ ld a, $5
+ ld [wd49c], a
+ ld a, $85
+ ld [wPikachuMood], a
+.notTeachingThunderboltOrThunderToPikachu
+ pop af
+ ld [wWhichPokemon], a
+
ld a, [wcf91]
call IsItemHM
ret c
@@ -2334,6 +2605,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
@@ -2395,6 +2672,10 @@ BoxFullCannotThrowBallText:
TX_FAR _BoxFullCannotThrowBallText
db "@"
+DontHavePokemonText:
+ TX_FAR _DontHavePokemonText
+ db "@"
+
ItemUseText00:
TX_FAR _ItemUseText001
TX_LINE
@@ -2529,6 +2810,7 @@ GetMaxPP:
.sourceWithOneMon
call GetSelectedMoveOffset2
jr .next
+
.sourceWithMultipleMon
call GetSelectedMoveOffset
.next
@@ -2630,6 +2912,7 @@ TossItem_:
pop hl
and a
ret
+
.tooImportantToToss
push hl
ld hl, TooImportantToTossText
@@ -2696,7 +2979,7 @@ SendNewMonToBox:
ld a, [wcf91]
ld [wd0b5], a
ld c, a
-.asm_e7b1
+.asm_e6f5
inc de
ld a, [de]
ld b, a
@@ -2704,13 +2987,13 @@ SendNewMonToBox:
ld c, b
ld [de], a
cp $ff
- jr nz, .asm_e7b1
+ jr nz, .asm_e6f5
call GetMonHeader
ld hl, wBoxMonOT
ld bc, NAME_LENGTH
ld a, [wNumInBox]
dec a
- jr z, .asm_e7ee
+ jr z, .asm_e732
dec a
call AddNTimes
push hl
@@ -2722,7 +3005,7 @@ SendNewMonToBox:
ld a, [wNumInBox]
dec a
ld b, a
-.asm_e7db
+.asm_e71f
push bc
push hl
ld bc, NAME_LENGTH
@@ -2734,15 +3017,15 @@ SendNewMonToBox:
add hl, bc
pop bc
dec b
- jr nz, .asm_e7db
-.asm_e7ee
+ jr nz, .asm_e71f
+.asm_e732
ld hl, wPlayerName
ld de, wBoxMonOT
ld bc, NAME_LENGTH
call CopyData
ld a, [wNumInBox]
dec a
- jr z, .asm_e82a
+ jr z, .asm_e76e
ld hl, wBoxMonNicks
ld bc, NAME_LENGTH
dec a
@@ -2756,7 +3039,7 @@ SendNewMonToBox:
ld a, [wNumInBox]
dec a
ld b, a
-.asm_e817
+.asm_e75b
push bc
push hl
ld bc, NAME_LENGTH
@@ -2768,15 +3051,15 @@ SendNewMonToBox:
add hl, bc
pop bc
dec b
- jr nz, .asm_e817
-.asm_e82a
+ jr nz, .asm_e75b
+.asm_e76e
ld hl, wBoxMonNicks
ld a, NAME_MON_SCREEN
ld [wNamingScreenType], a
predef AskName
ld a, [wNumInBox]
dec a
- jr z, .asm_e867
+ jr z, .asm_e7ab
ld hl, wBoxMons
ld bc, wBoxMon2 - wBoxMon1
dec a
@@ -2790,7 +3073,7 @@ SendNewMonToBox:
ld a, [wNumInBox]
dec a
ld b, a
-.asm_e854
+.asm_e798
push bc
push hl
ld bc, wBoxMon2 - wBoxMon1
@@ -2802,8 +3085,8 @@ SendNewMonToBox:
add hl, bc
pop bc
dec b
- jr nz, .asm_e854
-.asm_e867
+ jr nz, .asm_e798
+.asm_e7ab
ld a, [wEnemyMonLevel]
ld [wEnemyMonBoxLevel], a
ld hl, wEnemyMon
@@ -2833,11 +3116,11 @@ SendNewMonToBox:
inc de
xor a
ld b, NUM_STATS * 2
-.asm_e89f
+.asm_e7e3
ld [de], a
inc de
dec b
- jr nz, .asm_e89f
+ jr nz, .asm_e7e3
ld hl, wEnemyMonDVs
ld a, [hli]
ld [de], a
@@ -2846,12 +3129,18 @@ SendNewMonToBox:
ld [de], a
ld hl, wEnemyMonPP
ld b, NUM_MOVES
-.asm_e8b1
+.asm_e7f5
ld a, [hli]
inc de
ld [de], a
dec b
- jr nz, .asm_e8b1
+ jr nz, .asm_e7f5
+ ld a, [wcf91]
+ cp KADABRA
+ jr nz, .notKadabra
+ ld a, $60 ; twistedspoon in gsc
+ ld [wBoxMon1CatchRate], a
+.notKadabra
ret
; checks if the tile in front of the player is a shore or water tile
@@ -2861,24 +3150,21 @@ 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
+ ld a, [wTileInFrontOfPlayer]
+ ld de, $1
+ call IsInArray
ret
; tilesets with water
@@ -2886,52 +3172,12 @@ WaterTilesets:
db OVERWORLD, FOREST, DOJO, GYM, SHIP, SHIP_PORT, CAVERN, FACILITY, PLATEAU
db $ff ; terminator
-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
- 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/super_rod.asm"
+; shore tiles
+ShoreTiles:
+ db $48, $32
+WaterTile:
+ db $14
+ db $ff ; terminator
; reloads map view and processes sprite data
; for items that cause the overworld to be displayed
diff --git a/engine/items/tms.asm b/engine/items/tms.asm
index da1b5e72..84770747 100755
--- a/engine/items/tms.asm
+++ b/engine/items/tms.asm
@@ -11,6 +11,8 @@ CanLearnTM:
ld hl, TechnicalMachines
.findTMloop
ld a, [hli]
+ cp $ff ; 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 wd11e into move number
; HMs start at 51
diff --git a/engine/joypad.asm b/engine/joypad.asm
index 31e197e2..4126568c 100644
--- a/engine/joypad.asm
+++ b/engine/joypad.asm
@@ -1,12 +1,48 @@
+ReadJoypad_::
+; Poll joypad input.
+; Unlike the hardware register, button
+; presses are indicated by a set bit.
+ ld a, [hDisableJoypadPolling]
+ and a
+ ret nz
+
+ ld a, 1 << 5 ; select direction keys
+ ;ld c, 0
+
+ ld [rJOYP], a
+ ld a, [rJOYP]
+ ld a, [rJOYP]
+ cpl
+ and %1111
+ swap a
+ ld b, a
+
+ ld a, 1 << 4 ; select button keys
+ ld [rJOYP], a
+ rept 6
+ ld a, [rJOYP]
+ endr
+ cpl
+ and %1111
+ or b
+
+ ld [hJoyInput], a
+
+ ld a, 1 << 4 + 1 << 5 ; deselect keys
+ ld [rJOYP], a
+ ret
+
+
_Joypad::
; hJoyReleased: (hJoyLast ^ hJoyInput) & hJoyLast
; hJoyPressed: (hJoyLast ^ hJoyInput) & hJoyInput
ld a, [hJoyInput]
+ ld b,a
+ and $4F
cp A_BUTTON + B_BUTTON + SELECT + START ; soft reset
jp z, TrySoftReset
- ld b, a
ld a, [hJoyLast]
ld e, a
xor b
diff --git a/engine/learn_move.asm b/engine/learn_move.asm
index 53c7f87e..021d0eeb 100755
--- a/engine/learn_move.asm
+++ b/engine/learn_move.asm
@@ -121,18 +121,17 @@ TryingToLearn:
ld hl, WhichMoveToForgetText
call PrintText
coord hl, 4, 7
- ld b, 4
- ld c, 14
+ lb bc, 4, 14
call TextBoxBorder
coord hl, 6, 8
ld de, wMovesString
- ld a, [hFlags_0xFFF6]
+ ld a, [hFlags_0xFFFA]
set 2, a
- ld [hFlags_0xFFF6], a
+ ld [hFlags_0xFFFA], a
call PlaceString
- ld a, [hFlags_0xFFF6]
+ ld a, [hFlags_0xFFFA]
res 2, a
- ld [hFlags_0xFFF6], a
+ ld [hFlags_0xFFFA], a
ld hl, wTopMenuItemY
ld a, 8
ld [hli], a ; wTopMenuItemY
@@ -146,10 +145,10 @@ TryingToLearn:
ld a, A_BUTTON | B_BUTTON
ld [hli], a ; wMenuWatchedKeys
ld [hl], 0 ; wLastMenuItem
- ld hl, hFlags_0xFFF6
+ ld hl, hFlags_0xFFFA
set 1, [hl]
call HandleMenuInput
- ld hl, hFlags_0xFFF6
+ ld hl, hFlags_0xFFFA
res 1, [hl]
push af
call LoadScreenTilesFromBuffer1
@@ -206,11 +205,36 @@ TryingToLearnText:
db "@"
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
TX_FAR _OneTwoAndText
TX_DELAY
TX_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/load_mon_data.asm b/engine/load_mon_data.asm
index a71a81c5..e708113f 100644
--- a/engine/load_mon_data.asm
+++ b/engine/load_mon_data.asm
@@ -15,7 +15,7 @@ LoadMonData_:
ld a, [wWhichPokemon]
ld e, a
- callab GetMonSpecies
+ call GetMonSpecies
.GetMonHeader
ld a, [wcf91]
@@ -47,3 +47,22 @@ LoadMonData_:
ld de, wLoadedMon
ld bc, wPartyMon2 - wPartyMon1
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, wEnemyPartyMons
+.getSpecies
+ ld d, 0
+ add hl, de
+ ld a, [hl]
+ ld [wcf91], a
+ ret
diff --git a/engine/menu/bills_pc.asm b/engine/menu/bills_pc.asm
index 0864828a..41626310 100644
--- a/engine/menu/bills_pc.asm
+++ b/engine/menu/bills_pc.asm
@@ -11,18 +11,15 @@ DisplayPCMainMenu::
and a
jr nz, .leaguePCAvailable
coord hl, 0, 0
- ld b, 8
- ld c, 14
+ lb bc, 8, 14
jr .next
.noOaksPC
coord hl, 0, 0
- ld b, 6
- ld c, 14
+ lb bc, 6, 14
jr .next
.leaguePCAvailable
coord hl, 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), $01
call CopyVideoData
call LoadScreenTilesFromBuffer2DisableBGTransfer
+ coord hl, 0, 12
+ lb bc, 4, 18
+ call TextBoxBorder
coord hl, 0, 0
- ld b, 10
- ld c, 12
+ lb bc, 12, 12
call TextBoxBorder
+ call UpdateSprites
coord hl, 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, A_BUTTON | B_BUTTON
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
coord hl, 9, 14
- ld b, 2
- ld c, 9
+ lb bc, 2, 9
call TextBoxBorder
ld a, [wCurrentBoxNum]
and $7f
@@ -184,6 +181,8 @@ BillsPCMenu:
jp z, BillsPCRelease ; release
cp $3
jp z, BillsPCChangeBox ; change box
+ cp $4
+ jp z, BillsPCPrintBox
ExitBillsPC:
ld a, [wFlags_0xcd60]
@@ -204,6 +203,10 @@ ExitBillsPC:
res 6, [hl]
ret
+BillsPCPrintBox:
+ callab PrintPCBox
+ jp BillsPCMenu
+
BillsPCDeposit:
ld a, [wPartyCount]
dec a
@@ -222,11 +225,26 @@ BillsPCDeposit:
ld hl, wPartyCount
call DisplayMonListMenu
jp c, BillsPCMenu
+ callab IsThisPartymonStarterPikachu_Party
+ jr nc, .asm_215ad
+ call CheckPikachuFollowingPlayer
+ jr z, .asm_215ad
+ ld hl, SleepingPikachuText2
+ call PrintText
+ jp BillsPCMenu
+.asm_215ad
call DisplayDepositWithdrawMenu
jp nc, BillsPCMenu
+ callab IsThisPartymonStarterPikachu_Party
+ jr nc, .asm_215c9
+ ld e, $1b
+ callab PlayPikachuSoundClip
+ jr .asm_215cf
+.asm_215c9
ld a, [wcf91]
- call GetCryData
- call PlaySoundWaitForCurrent
+ call PlayCry
+.asm_215cf
+ callabd_ModifyPikachuHappiness PIKAHAPPY_DEPOSITED
ld a, PARTY_TO_BOX
ld [wMoveMonType], a
call MoveMon
@@ -253,6 +271,10 @@ BillsPCDeposit:
call PrintText
jp BillsPCMenu
+SleepingPikachuText2:
+ TX_FAR _SleepingPikachuText2
+ db "@"
+
BillsPCWithdraw:
ld a, [wNumInBox]
and a
@@ -276,9 +298,15 @@ BillsPCWithdraw:
ld a, [wWhichPokemon]
ld hl, wBoxMonNicks
call GetPartyMonName
+ callab IsThisPartymonStarterPikachu_Box
+ jr nc, .asm_21660
+ ld e, $22
+ callab PlayPikachuSoundClip
+ jr .asm_21666
+.asm_21660
ld a, [wcf91]
- 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, wNumInBox
call DisplayMonListMenu
jp c, BillsPCMenu
+ callab IsThisPartymonStarterPikachu_Box
+ 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
+ ld e, $27
+ callab PlayPikachuSoundClip
+ ld hl, PikachuUnhappyText
+ call PrintText
+ jp BillsPCMenu
+
BillsPCChangeBox:
callba ChangeBox
jp BillsPCMenu
@@ -343,6 +383,7 @@ BillsPCMenuText:
next "DEPOSIT ", $4a
next "RELEASE ", $4a
next "CHANGE BOX"
+ next "PRINT BOX"
next "SEE YA!"
db "@"
@@ -386,8 +427,7 @@ HMMoveArray:
DisplayDepositWithdrawMenu:
coord hl, 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?
@@ -493,6 +533,10 @@ CantTakeMonText:
TX_FAR _CantTakeMonText
db "@"
+PikachuUnhappyText:
+ TX_FAR _PikachuUnhappyText
+ db "@"
+
ReleaseWhichMonText:
TX_FAR _ReleaseWhichMonText
db "@"
@@ -509,7 +553,7 @@ CableClubLeftGameboy::
ld a, [hSerialConnectionStatus]
cp USING_EXTERNAL_CLOCK
ret z
- ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+ ld a, [wSpritePlayerStateData1FacingDirection] ; player's sprite facing direction
cp SPRITE_FACING_RIGHT
ret nz
ld a, [wCurMap]
@@ -526,7 +570,7 @@ CableClubRightGameboy::
ld a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
ret z
- ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+ ld a, [wSpritePlayerStateData1FacingDirection] ; player's sprite facing direction
cp SPRITE_FACING_LEFT
ret nz
ld a, [wCurMap]
@@ -543,12 +587,12 @@ JustAMomentText::
TX_FAR _JustAMomentText
db "@"
- ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+ ld a, [wSpritePlayerStateData1FacingDirection] ; player's sprite facing direction
cp SPRITE_FACING_UP
ret nz
call EnableAutoTextBoxDrawing
tx_pre_jump OpenBillsPCText
OpenBillsPCText::
- db $FD ; FuncTX_BillsPC
+ TX_BILLS_PC
diff --git a/engine/menu/diploma.asm b/engine/menu/diploma.asm
index 09ba123e..3f309bd2 100755..100644
--- a/engine/menu/diploma.asm
+++ b/engine/menu/diploma.asm
@@ -6,108 +6,12 @@ DisplayDiploma:
ld [wUpdateSpritesEnabled], a
ld hl, wd730
set 6, [hl]
- call DisableLCD
- ld hl, CircleTile
- ld de, vChars2 + $700
- ld bc, $0010
- ld a, BANK(CircleTile)
- call FarCopyData2
- coord hl, 0, 0
- lb bc, 16, 18
- predef Diploma_TextBoxBorder
- ld hl, DiplomaTextPointersAndCoords
- ld c, $5
-.asm_56715
- 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, .asm_56715
- coord hl, 10, 4
- ld de, wPlayerName
- call PlaceString
- callba DrawPlayerCharacter
-
-; Move the player 33 pixels right and set the priority bit so he appears
-; behind the background layer.
- ld hl, wOAMBuffer + $01
- 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
- callba LoadTrainerInfoTextBoxTiles
- ld b, SET_PAL_GENERIC
- call RunPaletteCommand
- call Delay3
- call GBPalNormal
- ld a, $90
- ld [rOBP0], a
+ callab _DisplayDiploma
call WaitForTextScrollButtonPress
ld hl, wd730
res 6, [hl]
call GBPalWhiteOutWithDelay3
+ call ReloadTilesetTilePatterns
call RestoreScreenTilesAndReloadTilePatterns
call Delay3
jp GBPalNormal
-
-UnusedPlayerNameLengthFunc:
-; Unused function that does a calculation involving the length of the player's
-; name.
- ld hl, wPlayerName
- ld bc, $ff00
-.loop
- ld a, [hli]
- cp "@"
- ret z
- dec c
- jr .loop
-
-DiplomaTextPointersAndCoords:
- dw DiplomaText
- dwCoord 5, 2
- dw DiplomaPlayer
- dwCoord 3, 4
- dw DiplomaEmptyText
- dwCoord 15, 4
- dw DiplomaCongrats
- dwCoord 2, 6
- dw DiplomaGameFreak
- dwCoord 9, 16
-
-DiplomaText:
- db $70,"Diploma",$70,"@"
-
-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/menu/draw_start_menu.asm b/engine/menu/draw_start_menu.asm
index 11777dc6..632b8c3a 100644
--- a/engine/menu/draw_start_menu.asm
+++ b/engine/menu/draw_start_menu.asm
@@ -3,13 +3,11 @@ DrawStartMenu:
CheckEvent EVENT_GOT_POKEDEX
; menu with pokedex
coord hl, 10, 0
- ld b, $0e
- ld c, $08
- jr nz, .drawTextBoxBorder
+ lb bc, 14, 8
+ jr nz,.drawTextBoxBorder
; shorter menu if the player doesn't have the pokedex
coord hl, 10, 0
- ld b, $0c
- ld c, $08
+ lb bc, 12, 8
.drawTextBoxBorder
call TextBoxBorder
ld a, D_DOWN | D_UP | START | B_BUTTON | A_BUTTON
@@ -63,7 +61,7 @@ StartMenuPokedexText:
db "POKéDEX@"
StartMenuPokemonText:
- db "POKéMON@"
+ db "#MON@"
StartMenuItemText:
db "ITEM@"
diff --git a/engine/menu/league_pc.asm b/engine/menu/league_pc.asm
index 170c0ef3..9946b90d 100755
--- a/engine/menu/league_pc.asm
+++ b/engine/menu/league_pc.asm
@@ -100,8 +100,7 @@ LeaguePCShowMon:
call LoadFrontSpriteByMonIndex
call GBPalNormal
coord hl, 0, 13
- ld b, 2
- ld c, $12
+ lb bc, 2, 18
call TextBoxBorder
coord hl, 1, 15
ld de, HallOfFameNoText
@@ -110,7 +109,7 @@ LeaguePCShowMon:
ld de, wHoFTeamNo
lb bc, 1, 3
call PrintNumber
- jpba HoFDisplayMonInfo
+ jpba Func_7033f
HallOfFameNoText:
db "HALL OF FAME No @"
diff --git a/engine/menu/link_menu.asm b/engine/menu/link_menu.asm
new file mode 100644
index 00000000..9bc28b31
--- /dev/null
+++ b/engine/menu/link_menu.asm
@@ -0,0 +1,910 @@
+Func_f531b::
+ ld c,$14
+ call DelayFrames
+ ld a,$1
+ ld [wBuffer],a
+ xor a
+ ld [wUnknownSerialFlag_d499],a
+ coord hl, 0,0
+ lb bc, 4, 5
+ call TextBoxBorder
+ ld de,Text_f5791
+ coord hl, 1,2
+ call PlaceString
+ coord hl, 8,0
+ lb bc, 8, 10
+ call TextBoxBorder
+ coord hl, 10,2
+ ld de,Text_f579c
+ call PlaceString
+ coord hl, 0,10
+ lb bc, 6, 18
+ call TextBoxBorder
+ call UpdateSprites
+ xor a
+ ld [wUnusedCD37],a
+ ld [wd72d],a
+ ld [wd11e],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]
+ ld [hSerialSendData],a
+ call Serial_ExchangeByte
+ push af
+ ld hl,wLinkMenuSelectionSendBuffer
+ ld a,[hl]
+ ld [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
+ ld a,[hSerialConnectionStatus]
+ cp $2
+ jr z,.asm_f53df
+.asm_f53d1
+ ld a,$1
+ ld [wd11e],a
+ ld a,b
+ ld [wLinkMenuSelectionSendBuffer],a
+ and $3
+ ld [wCurrentMenuItem],a
+.asm_f53df
+ call DelayFrame
+ call DelayFrame
+ ld hl,wLinkMenuSelectionSendBuffer
+ ld a,[hl]
+ ld [hSerialSendData],a
+ call Serial_ExchangeByte
+ call Serial_ExchangeByte
+ ld b,$14
+.loop
+ call DelayFrame
+ call Serial_SendZeroByte
+ dec b
+ jr nz,.loop
+ ld b,$7f
+ ld c,$7f
+ ld d,$7f
+ ld e,$ec
+ 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
+ Coorda 9,2
+ ld a,c
+ Coorda 9,4
+ ld a,d
+ Coorda 9,6
+ ld a,e
+ Coorda 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 [wcf91],a
+ push hl
+ callab Func_3b10f
+ pop hl
+ jp c,asm_f56ad
+ inc hl
+ ld a,[hl]
+ ld [wcf91],a
+ push hl
+ callab Func_3b10f
+ pop hl
+ jp c,asm_f56ad
+ inc hl
+ ld a,[hl]
+ ld [wcf91],a
+ push hl
+ callab 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,wcd6d
+ ld bc,$2
+ ld a,BANK(PokedexEntryPointers)
+ call FarCopyData
+ ld hl,wcd6d
+ ld a,[hli]
+ ld h,[hl]
+ ld l,a
+ ld de,wcd6d
+ ld bc,$14
+ ld a,BANK(PokedexEntryPointers)
+ call FarCopyData
+ ld hl,wcd6d
+.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 [wd11e],a
+ call GetMonName
+ ld hl,ColosseumHeightText
+ call PrintText
+ ld a,$d
+ ret
+
+asm_f569b::
+ pop af
+ pop bc
+ pop hl
+ ld [wd11e],a
+ call GetMonName
+ ld hl,ColosseumWeightText
+ call PrintText
+ ld a,$e
+ ret
+
+asm_f56ad::
+ ld a,[hl]
+ ld [wd11e],a
+ call GetMonName
+ ld hl,ColosseumEvolvedText
+ call PrintText
+ ld a,$f
+ ret
+
+Func_f56bd::
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED],a
+ coord hl, 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
+ coord hl, 1,12
+ call PlaceString
+.asm_f56e6
+ call Delay3
+ ld a,$1
+ ld [H_AUTOBGTRANSFERENABLED],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::
+ TX_FAR _Colosseum3MonsText
+ db "@"
+
+ColosseumMewText::
+ TX_FAR _ColosseumMewText
+ db "@"
+
+ColosseumDifferentMonsText::
+ TX_FAR _ColosseumDifferentMonsText
+ db "@"
+
+ColosseumMaxL55Text::
+ TX_FAR _ColosseumMaxL55Text
+ db "@"
+
+ColosseumMinL50Text::
+ TX_FAR _ColosseumMinL50Text
+ db "@"
+
+ColosseumTotalL155Text::
+ TX_FAR _ColosseumTotalL155Text
+ db "@"
+
+ColosseumMaxL30Text::
+ TX_FAR _ColosseumMaxL30Text
+ db "@"
+
+ColosseumMinL25Text::
+ TX_FAR _ColosseumMinL25Text
+ db "@"
+
+ColosseumTotalL80Text::
+ TX_FAR _ColosseumTotalL80Text
+ db "@"
+
+ColosseumMaxL20Text::
+ TX_FAR _ColosseumMaxL20Text
+ db "@"
+
+ColosseumMinL15Text::
+ TX_FAR _ColosseumMinL15Text
+ db "@"
+
+ColosseumTotalL50Text::
+ TX_FAR _ColosseumTotalL50Text
+ db "@"
+
+ColosseumHeightText::
+ TX_FAR _ColosseumHeightText
+ db "@"
+
+ColosseumWeightText::
+ TX_FAR _ColosseumWeightText
+ db "@"
+
+ColosseumEvolvedText::
+ TX_FAR _ColosseumEvolvedText
+ db "@"
+
+ColosseumIneligibleText::
+ TX_FAR _ColosseumIneligibleText
+ db "@"
+
+LinkMenu:
+ xor a
+ ld [wLetterPrintingDelayFlags], a
+ ld hl, wd72e
+ set 6, [hl]
+ ld hl, TextTerminator_f5a16
+ call PrintText
+ call SaveScreenTilesToBuffer1
+ ld hl, ColosseumWhereToText
+ call PrintText
+ coord hl, 5, 3
+ lb bc, 8, 13
+ call TextBoxBorder
+ call UpdateSprites
+ coord hl, 7, 5
+ ld de, TradeCenterText
+ call PlaceString
+ xor a
+ ld [wUnusedCD37], a
+ ld [wd72d], a
+ ld [wd11e], a
+ ld hl, wTopMenuItemY
+ ld a, $5
+ ld [hli], a
+ ld a, $6
+ ld [hli], a
+ xor a
+ ld [hli], a
+ inc hl
+ ld a, $3
+ ld [hli], a
+ ld [hli], a
+ xor a
+ ld [hl], a
+.waitForInputLoop
+ call HandleMenuInput
+ and A_BUTTON | B_BUTTON
+ 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, .asm_f5c7d
+ ld a, [wLinkMenuSelectionReceiveBuffer + 1]
+ ld b, a
+ and $f0
+ cp $d0
+ jr nz, .exchangeMenuSelectionLoop
+.asm_f5c7d
+ 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.
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr z, .doneChoosingMenuSelection
+.useEnemyMenuSelection
+ ld a, $1
+ ld [wd11e], a
+ ld a, b
+ ld [wLinkMenuSelectionSendBuffer], a
+ and $3
+ ld [wCurrentMenuItem], a ; wCurrentMenuItem
+.doneChoosingMenuSelection
+ ld a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr nz, .skipStartingTransfer
+ call DelayFrame
+ call DelayFrame
+ ld a, START_TRANSFER_INTERNAL_CLOCK
+ ld [rSC], a
+.skipStartingTransfer
+ ld b, " "
+ ld c, " "
+ ld d, " "
+ ld e, "▷"
+ ld a, [wLinkMenuSelectionSendBuffer]
+ and (B_BUTTON << 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 (B_BUTTON << 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 [wd72d], a
+ ld hl, ColosseumPleaseWaitText
+ call PrintText
+ ld c, 50
+ call DelayFrames
+ ld hl, wd732
+ res 1, [hl]
+ ld a, [wDefaultMap]
+ ld [wDestinationMap], a
+ callab SpecialWarpIn
+ 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
+ jpab SpecialEnterMap
+.choseCancel
+ xor a
+ ld [wMenuJoypadPollCount], a
+ call Delay3
+ callab CloseLinkConnection
+ ld hl, ColosseumCanceledText
+ call PrintText
+ ld hl, wd72e
+ res 6, [hl]
+ ret
+
+.asm_f5963
+ ld a,[wd11e]
+ 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
+ ld 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,[wd11e]
+ 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
+ Coorda 6, 5
+ ld a, c
+ Coorda 6, 7
+ ld a, d
+ Coorda 6, 9
+ ld a, e
+ Coorda 6, 11
+ ld c, 40
+ call DelayFrames
+ ret
+
+ColosseumWhereToText:
+ TX_FAR _ColosseumWhereToText
+ db "@"
+
+ColosseumPleaseWaitText:
+ TX_FAR _ColosseumPleaseWaitText
+ db "@"
+
+ColosseumCanceledText:
+ TX_FAR _ColosseumCanceledText
+ db "@"
+
+ColosseumVersionText:
+ TX_FAR _ColosseumVersionText
+ db "@"
+
+TextTerminator_f5a16:
+ db "@"
+
+TradeCenterText:
+ db "TRADE CENTER"
+ next "COLOSSEUM"
+ next "COLOSSEUM2"
+ next "CANCEL@"
diff --git a/engine/menu/main_menu.asm b/engine/menu/main_menu.asm
index da2e98e4..ce27ebba 100755
--- a/engine/menu/main_menu.asm
+++ b/engine/menu/main_menu.asm
@@ -34,8 +34,7 @@ MainMenu:
jr z, .noSaveFile
; there's a save file
coord hl, 0, 0
- ld b, 6
- ld c, 13
+ lb bc, 6, 13
call TextBoxBorder
coord hl, 2, 2
ld de, ContinueText
@@ -43,8 +42,7 @@ MainMenu:
jr .next2
.noSaveFile
coord hl, 0, 0
- ld b, 4
- ld c, 13
+ lb bc, 4, 13
call TextBoxBorder
coord hl, 2, 2
ld de, NewGameText
@@ -129,185 +127,29 @@ InitOptions:
ld [wLetterPrintingDelayFlags], a
ld a, 3 ; medium speed
ld [wOptions], a
+ ld a, 64 ; audio?
+ ld [wPrinterSettings], a
ret
-LinkMenu:
- xor a
- ld [wLetterPrintingDelayFlags], a
- ld hl, wd72e
- set 6, [hl]
- ld hl, TextTerminator_6b20
- call PrintText
- call SaveScreenTilesToBuffer1
- ld hl, WhereWouldYouLikeText
- call PrintText
- coord hl, 5, 5
- ld b, $6
- ld c, $d
- call TextBoxBorder
- call UpdateSprites
- coord hl, 7, 7
- ld de, CableClubOptionsText
- call PlaceString
- xor a
- ld [wUnusedCD37], a
- ld [wd72d], a
- ld hl, wTopMenuItemY
- ld a, $7
- ld [hli], a
- ld a, $6
- ld [hli], a
- xor a
- ld [hli], a
- inc hl
- ld a, $2
- ld [hli], a
- inc a
- ; ld a, A_BUTTON | B_BUTTON
- ld [hli], a ; wMenuWatchedKeys
- xor a
- ld [hl], a
-.waitForInputLoop
- call HandleMenuInput
- and A_BUTTON | B_BUTTON
- 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, .asm_5c7d
- ld a, [wLinkMenuSelectionReceiveBuffer + 1]
- ld b, a
- and $f0
- cp $d0
- jr nz, .exchangeMenuSelectionLoop
-.asm_5c7d
- 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.
- ld a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- jr z, .doneChoosingMenuSelection
-.useEnemyMenuSelection
- ld a, b
- ld [wLinkMenuSelectionSendBuffer], a
- and $3
- ld [wCurrentMenuItem], a
-.doneChoosingMenuSelection
- ld a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- jr nz, .skipStartingTransfer
- call DelayFrame
- call DelayFrame
- ld a, START_TRANSFER_INTERNAL_CLOCK
- ld [rSC], a
-.skipStartingTransfer
- ld b, $7f
- ld c, $7f
- ld d, $ec
- ld a, [wLinkMenuSelectionSendBuffer]
- and (B_BUTTON << 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
- Coorda 6, 7
- ld a, c
- Coorda 6, 9
- ld a, d
- Coorda 6, 11
- ld c, 40
- call DelayFrames
- call LoadScreenTilesFromBuffer1
- ld a, [wLinkMenuSelectionSendBuffer]
- and (B_BUTTON << 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 [wd72d], a
- ld hl, PleaseWaitText
+Func_5cc1:
+; unused?
+ ld a, $6d
+ cp $80
+ ret c ; will always be executed
+ ld hl, NotEnoughMemoryText
call PrintText
- ld c, 50
- call DelayFrames
- ld hl, wd732
- res 1, [hl]
- ld a, [wDefaultMap]
- ld [wDestinationMap], a
- call SpecialWarpIn
- 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
- call Delay3
- call CloseLinkConnection
- ld hl, LinkCanceledText
- call PrintText
- ld hl, wd72e
- res 6, [hl]
ret
-WhereWouldYouLikeText:
- TX_FAR _WhereWouldYouLikeText
- db "@"
-
-PleaseWaitText:
- TX_FAR _PleaseWaitText
- db "@"
-
-LinkCanceledText:
- TX_FAR _LinkCanceledText
+NotEnoughMemoryText:
+ TX_FAR _NotEnoughMemoryText
db "@"
StartNewGame:
ld hl, wd732
res 1, [hl]
call OakSpeech
+ ld a, $8
+ ld [wPlayerMovingDirection], a
ld c, 20
call DelayFrames
@@ -323,6 +165,7 @@ SpecialEnterMap:
call ResetPlayerSpriteData
ld c, 20
call DelayFrames
+ call Func_5cc1
ld a, [wEnteringCableClub]
and a
ret nz
@@ -335,17 +178,11 @@ NewGameText:
db "NEW GAME"
next "OPTION@"
-CableClubOptionsText:
- db "TRADE CENTER"
- next "COLOSSEUM"
- next "CANCEL@"
-
DisplayContinueGameInfo:
xor a
ld [H_AUTOBGTRANSFERENABLED], a
coord hl, 4, 7
- ld b, 8
- ld c, 14
+ lb bc, 8, 14
call TextBoxBorder
coord hl, 5, 9
ld de, SaveScreenInfoText
@@ -368,8 +205,7 @@ PrintSaveScreenText:
xor a
ld [H_AUTOBGTRANSFERENABLED], a
coord hl, 4, 0
- ld b, $8
- ld c, $e
+ lb bc, 8, 14
call TextBoxBorder
call LoadTextBoxTilePatterns
call UpdateSprites
@@ -427,259 +263,8 @@ SaveScreenInfoText:
next "TIME@"
DisplayOptionMenu:
- coord hl, 0, 0
- ld b, 3
- ld c, 18
- call TextBoxBorder
- coord hl, 0, 5
- ld b, 3
- ld c, 18
- call TextBoxBorder
- coord hl, 0, 10
- ld b, 3
- ld c, 18
- call TextBoxBorder
- coord hl, 1, 1
- ld de, TextSpeedOptionText
- call PlaceString
- coord hl, 1, 6
- ld de, BattleAnimationOptionText
- call PlaceString
- coord hl, 1, 11
- ld de, BattleStyleOptionText
- call PlaceString
- coord hl, 2, 16
- ld de, OptionMenuCancelText
- call PlaceString
- xor a
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- inc a
- ld [wLetterPrintingDelayFlags], a
- ld [wUnusedCD40], 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
- ld [H_AUTOBGTRANSFERENABLED], a ; enable auto background transfer
- call Delay3
-.loop
- call PlaceMenuCursor
- call SetOptionsFromCursorPositions
-.getJoypadStateLoop
- call JoypadLowSensitivity
- ld a, [hJoy5]
- ld b, a
- and A_BUTTON | B_BUTTON | START | D_RIGHT | D_LEFT | D_UP | D_DOWN ; any key besides select pressed?
- jr z, .getJoypadStateLoop
- bit 1, b ; B button pressed?
- jr nz, .exitMenu
- bit 3, b ; Start button pressed?
- jr nz, .exitMenu
- bit 0, b ; A button pressed?
- jr z, .checkDirectionKeys
- ld a, [wTopMenuItemY]
- cp 16 ; is the cursor on Cancel?
- jr nz, .loop
-.exitMenu
- ld a, SFX_PRESS_AB
- call PlaySound
+ callab DisplayOptionMenu_
ret
-.eraseOldMenuCursor
- ld [wTopMenuItemX], a
- call EraseMenuCursor
- jp .loop
-.checkDirectionKeys
- ld a, [wTopMenuItemY]
- bit 7, b ; Down pressed?
- jr nz, .downPressed
- bit 6, b ; Up pressed?
- 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
-.cursorInTextSpeed
- bit 5, b ; Left pressed?
- 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 $0b ; toggle between 1 and 10
- ld [wOptionsBattleAnimCursorX], a
- jp .eraseOldMenuCursor
-.cursorInBattleStyle
- ld a, [wOptionsBattleStyleCursorX] ; battle style cursor X coordinate
- xor $0b ; 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
-.battleAnimationOff
- set 7, d
- jr .checkBattleStyle
-.battleAnimationOn
- res 7, d
-.checkBattleStyle
- ld a, [wOptionsBattleStyleCursorX] ; battle style cursor X coordinate
- dec a
- jr z, .battleStyleShift
-.battleStyleSet
- set 6, d
- jr .storeOptions
-.battleStyleShift
- res 6, 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
- coord hl, 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
- coord hl, 0, 8
- call .placeUnfilledRightArrow
- sla c
- ld a, 1
- jr nc, .storeBattleStyleCursorX
- ld a, 10
-.storeBattleStyleCursorX
- ld [wOptionsBattleStyleCursorX], a ; battle style cursor X coordinate
- coord hl, 0, 13
- call .placeUnfilledRightArrow
-; cursor in front of Cancel
- coord hl, 0, 16
- ld a, 1
-.placeUnfilledRightArrow
- ld e, a
- ld d, 0
- add hl, de
- ld [hl], $ec ; unfilled right arrow menu cursor
- 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,5 ; Slow
- db 7,3 ; Medium
- db 1,1 ; Fast
- db 7 ; default X coordinate (Medium)
- db $ff ; terminator
CheckForPlayerNameInSRAM:
; Check if the player name data in SRAM has a string terminator character
diff --git a/engine/menu/naming_screen.asm b/engine/menu/naming_screen.asm
index 64065c4d..2560677a 100755
--- a/engine/menu/naming_screen.asm
+++ b/engine/menu/naming_screen.asm
@@ -5,8 +5,7 @@ AskName:
ld a, [wIsInBattle]
dec a
coord hl, 0, 0
- ld b, 4
- ld c, 11
+ lb bc, 4, 11
call z, ClearScreenArea ; only if in wild battle
ld a, [wcf91]
ld [wd11e], a
@@ -94,8 +93,7 @@ DisplayNamingScreen:
call LoadEDTile
callba LoadMonPartySpriteGfx
coord hl, 0, 4
- ld b, 9
- ld c, 18
+ lb bc, 9, 18
call TextBoxBorder
call PrintNamingText
ld a, 3
@@ -324,12 +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 + $700
- ld bc, (ED_TileEnd - ED_Tile) / $8
- ; to fix the graphical bug on poor emulators
- ;lb bc, BANK(ED_Tile), (ED_TileEnd - ED_Tile) / $8
- jp CopyVideoDataDouble
+ ld c, $4 ; number of copies needed
+.waitForHBlankLoop
+ ld 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/ED_tile.1bpp"
diff --git a/engine/menu/options.asm b/engine/menu/options.asm
new file mode 100644
index 00000000..da89ad82
--- /dev/null
+++ b/engine/menu/options.asm
@@ -0,0 +1,443 @@
+DisplayOptionMenu_:
+ call InitOptionsMenu
+.optionMenuLoop
+ call JoypadLowSensitivity
+ ld a, [hJoy5]
+ and START | B_BUTTON
+ 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
+
+OptionsMenu_TextSpeed:
+ call GetTextSpeed
+ ld a, [hJoy5]
+ bit 4, a ; right
+ jr nz, .pressedRight
+ bit 5, a
+ jr nz, .pressedLeft
+ jr .asm_41ce0
+.pressedRight
+ ld a, c
+ cp $2
+ jr c, .asm_41cca
+ ld c, $ff
+.asm_41cca
+ inc c
+ ld a, e
+ jr .asm_41cd6
+.pressedLeft
+ ld a, c
+ and a
+ jr nz, .asm_41cd4
+ ld c, $3
+.asm_41cd4
+ dec c
+ ld a, d
+.asm_41cd6
+ ld b, a
+ ld a, [wOptions]
+ and $f0
+ or b
+ ld [wOptions], a
+.asm_41ce0
+ ld b, $0
+ ld hl, TextSpeedStringsPointerTable
+ add hl, bc
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ coord hl, 14, 2
+ call PlaceString
+ and a
+ ret
+
+TextSpeedStringsPointerTable:
+ dw FastText
+ dw MidText
+ dw SlowText
+
+FastText:
+ db "FAST@"
+MidText:
+ db "MID @"
+SlowText:
+ db "SLOW@"
+
+GetTextSpeed:
+ ld a, [wOptions]
+ and $f
+ cp $5
+ jr z, .slowTextOption
+ cp $1
+ jr z, .fastTextOption
+; mid text option
+ ld c, $1
+ lb de, 1, 5
+ ret
+.slowTextOption
+ ld c, $2
+ lb de, 3, 1
+ ret
+.fastTextOption
+ ld c, $0
+ lb de, 5, 3
+ ret
+
+OptionsMenu_BattleAnimations:
+ ld a, [hJoy5]
+ and D_RIGHT | D_LEFT
+ jr nz, .asm_41d33
+ ld a, [wOptions]
+ and $80 ; mask other bits
+ jr .asm_41d3b
+.asm_41d33
+ ld a, [wOptions]
+ xor $80
+ ld [wOptions], a
+.asm_41d3b
+ ld bc, $0
+ sla a
+ rl c
+ ld hl, AnimationOptionStringsPointerTable
+ add hl, bc
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ coord hl, 14, 4
+ call PlaceString
+ and a
+ ret
+
+AnimationOptionStringsPointerTable:
+ dw AnimationOnText
+ dw AnimationOffText
+
+AnimationOnText:
+ db "ON @"
+AnimationOffText:
+ db "OFF@"
+
+OptionsMenu_BattleStyle:
+ ld a, [hJoy5]
+ and D_LEFT | D_RIGHT
+ jr nz, .asm_41d6b
+ ld a, [wOptions]
+ and $40 ; mask other bits
+ jr .asm_41d73
+.asm_41d6b
+ ld a, [wOptions]
+ xor $40
+ ld [wOptions], a
+.asm_41d73
+ ld bc, $0
+ sla a
+ sla a
+ rl c
+ ld hl, BattleStyleOptionStringsPointerTable
+ add hl, bc
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ coord hl, 14, 6
+ call PlaceString
+ and a
+ ret
+
+BattleStyleOptionStringsPointerTable:
+ dw BattleStyleShiftText
+ dw BattleStyleSetText
+
+BattleStyleShiftText:
+ db "SHIFT@"
+BattleStyleSetText:
+ db "SET @"
+
+OptionsMenu_SpeakerSettings:
+ ld a, [wOptions]
+ and $30
+ swap a
+ ld c, a
+ ld a, [hJoy5]
+ bit 4, a
+ jr nz, .pressedRight
+ bit 5, a
+ jr nz, .pressedLeft
+ jr .asm_41dca
+.pressedRight
+ ld a, c
+ inc a
+ and $3
+ jr .asm_41dba
+.pressedLeft
+ ld a, c
+ dec a
+ and $3
+.asm_41dba
+ ld c, a
+ swap a
+ ld b, a
+ xor a
+ ld [rNR51], a
+ ld a, [wOptions]
+ and $cf
+ or b
+ ld [wOptions], a
+.asm_41dca
+ ld b, $0
+ ld hl, SpeakerOptionStringsPointerTable
+ add hl, bc
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ coord hl, 8, 8
+ call PlaceString
+ and a
+ ret
+
+SpeakerOptionStringsPointerTable:
+ dw MonoSoundText
+ dw Earphone1SoundText
+ dw Earphone2SoundText
+ dw Earphone3SoundText
+
+MonoSoundText:
+ db "MONO @"
+Earphone1SoundText:
+ db "EARPHONE1@"
+Earphone2SoundText:
+ db "EARPHONE2@"
+Earphone3SoundText:
+ db "EARPHONE3@"
+
+OptionsMenu_GBPrinterBrightness:
+ call Func_41e7b
+ ld a, [hJoy5]
+ bit 4, a
+ jr nz, .pressedRight
+ bit 5, a
+ jr nz, .pressedLeft
+ jr .asm_41e32
+.pressedRight
+ ld a, c
+ cp $4
+ jr c, .asm_41e22
+ ld c, $ff
+.asm_41e22
+ inc c
+ ld a, e
+ jr .asm_41e2e
+.pressedLeft
+ ld a, c
+ and a
+ jr nz, .asm_41e2c
+ ld c, $5
+.asm_41e2c
+ dec c
+ ld a, d
+.asm_41e2e
+ ld b, a
+ ld [wPrinterSettings], a
+.asm_41e32
+ ld b, $0
+ ld hl, GBPrinterOptionStringsPointerTable
+ add hl, bc
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ coord hl, 8, 10
+ call PlaceString
+ and a
+ ret
+
+GBPrinterOptionStringsPointerTable:
+ dw LightestPrintText
+ dw LighterPrintText
+ dw NormalPrintText
+ dw DarkerPrintText
+ dw DarkestPrintText
+
+LightestPrintText:
+ db "LIGHTEST@"
+LighterPrintText:
+ db "LIGHTER @"
+NormalPrintText:
+ db "NORMAL @"
+DarkerPrintText:
+ db "DARKER @"
+DarkestPrintText:
+ db "DARKEST @"
+
+Func_41e7b:
+ ld a, [wPrinterSettings]
+ and a
+ jr z, .asm_41e93
+ cp $20
+ jr z, .asm_41e99
+ cp $60
+ jr z, .asm_41e9f
+ cp $7f
+ jr z, .asm_41ea5
+ ld c, $2
+ lb de, $20, $60
+ ret
+.asm_41e93
+ ld c, $0
+ lb de, $7f, $20
+ ret
+.asm_41e99
+ ld c, $1
+ lb de, $0, $40
+ ret
+.asm_41e9f
+ ld c, $3
+ lb de, $40, $7f
+ ret
+.asm_41ea5
+ ld c, $4
+ lb de, $60, $0
+ ret
+
+OptionsMenu_Dummy:
+ and a
+ ret
+
+OptionsMenu_Cancel:
+ ld a, [hJoy5]
+ and A_BUTTON
+ jr nz, .pressedCancel
+ and a
+ ret
+.pressedCancel
+ scf
+ ret
+
+OptionsControl:
+ ld hl, wOptionsCursorLocation
+ ld a, [hJoy5]
+ cp D_DOWN
+ jr z, .pressedDown
+ cp D_UP
+ jr z, .pressedUp
+ and a
+ ret
+.pressedDown
+ ld a, [hl]
+ cp $7
+ jr nz, .doNotWrapAround
+ ld [hl], $0
+ scf
+ ret
+.doNotWrapAround
+ cp $4
+ jr c, .regularIncrement
+ ld [hl], $6
+.regularIncrement
+ inc [hl]
+ scf
+ ret
+.pressedUp
+ ld a, [hl]
+ cp $7
+ jr nz, .doNotMoveCursorToPrintOption
+ ld [hl], $4
+ scf
+ ret
+.doNotMoveCursorToPrintOption
+ and a
+ jr nz, .regularDecrement
+ ld [hl], $8
+.regularDecrement
+ dec [hl]
+ scf
+ ret
+
+OptionsMenu_UpdateCursorPosition:
+ coord hl, 1, 1
+ ld de, SCREEN_WIDTH
+ ld c, 16
+.loop
+ ld [hl], " "
+ add hl, de
+ dec c
+ jr nz, .loop
+ coord hl, 1, 2
+ ld bc, SCREEN_WIDTH * 2
+ ld a, [wOptionsCursorLocation]
+ call AddNTimes
+ ld [hl], "▶"
+ ret
+
+InitOptionsMenu:
+ coord hl, 0, 0
+ lb bc, SCREEN_HEIGHT - 2, SCREEN_WIDTH - 2
+ call TextBoxBorder
+ coord hl, 2, 2
+ ld de, AllOptionsText
+ call PlaceString
+ coord hl, 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
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Delay3
+ ret
+
+AllOptionsText:
+ db "TEXT SPEED :"
+ next "ANIMATION :"
+ next "BATTLESTYLE:"
+ next "SOUND:"
+ next "PRINT:@"
+
+OptionMenuCancelText:
+ db "CANCEL@"
diff --git a/engine/menu/party_menu.asm b/engine/menu/party_menu.asm
index 8323d0eb..00c757be 100755
--- a/engine/menu/party_menu.asm
+++ b/engine/menu/party_menu.asm
@@ -49,9 +49,17 @@ RedrawPartyMenu_:
call GetPartyMonName
pop hl
call PlaceString ; print the pokemon's name
- callba WriteMonPartySpriteOAMByPartyIndex ; place the appropriate pokemon icon
ld a, [hPartyMonIndex]
ld [wWhichPokemon], a
+ callab IsThisPartymonStarterPikachu_Party
+ jr nc, .regularMon
+ call CheckPikachuFollowingPlayer
+ jr z, .regularMon
+ ld a, $ff
+ ld [hPartyMonIndex], a
+.regularMon
+ callba WriteMonPartySpriteOAMByPartyIndex ; place the appropriate pokemon icon
+ ld a, [wWhichPokemon]
inc a
ld [hPartyMonIndex], a
call LoadMonData
@@ -88,14 +96,14 @@ RedrawPartyMenu_:
pop hl
push hl
ld bc, SCREEN_WIDTH + 1 ; down 1 row and right 1 column
- ld a, [hFlags_0xFFF6]
+ ld a, [hFlags_0xFFFA]
set 0, a
- ld [hFlags_0xFFF6], a
+ ld [hFlags_0xFFFA], a
add hl, bc
predef DrawHP2 ; draw HP bar and prints current / max HP
- ld a, [hFlags_0xFFF6]
+ ld a, [hFlags_0xFFFA]
res 0, a
- ld [hFlags_0xFFF6], a
+ ld [hFlags_0xFFFA], a
call SetPartyMenuHPBarColor ; color the HP bar (on SGB)
pop hl
jr .printLevel
@@ -109,8 +117,8 @@ RedrawPartyMenu_:
jr nz, .placeMoveLearnabilityString
ld de, .notAbleToLearnMoveText
.placeMoveLearnabilityString
- ld bc, 20 + 9 ; down 1 row and right 9 columns
push hl
+ ld bc, 20 + 9 ; down 1 row and right 9 columns
add hl, bc
call PlaceString
pop hl
@@ -176,9 +184,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/menu/players_pc.asm b/engine/menu/players_pc.asm
index bc2be4ef..1cc02cbf 100755
--- a/engine/menu/players_pc.asm
+++ b/engine/menu/players_pc.asm
@@ -1,6 +1,4 @@
PlayerPC:
- ld hl, wd730
- set 6, [hl]
ld a, ITEM_NAME
ld [wNameListType], a
call SaveScreenTilesToBuffer1
@@ -17,14 +15,15 @@ PlayerPC:
call PrintText
PlayerPCMenu:
+ ld hl, wd730
+ set 6, [hl]
ld a, [wParentMenuItem]
ld [wCurrentMenuItem], a
ld hl, wFlags_0xcd60
set 5, [hl]
call LoadScreenTilesFromBuffer2
coord hl, 0, 0
- ld b, $8
- ld c, $e
+ lb bc, 8, 14
call TextBoxBorder
call UpdateSprites
coord hl, 2, 2
diff --git a/engine/menu/pokedex.asm b/engine/menu/pokedex.asm
index 8e1fd480..bc2a7e9b 100755
--- a/engine/menu/pokedex.asm
+++ b/engine/menu/pokedex.asm
@@ -12,9 +12,10 @@ ShowPokedexMenu:
ld [wd11e], a
ld [hJoy7], a
.setUpGraphics
+ callab LoadPokedexTilePatterns
+.loop
ld b, SET_PAL_GENERIC
call RunPaletteCommand
- callab 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, A_BUTTON | B_BUTTON
+ ld a, A_BUTTON | B_BUTTON
ld [hli], a ; menu watched keys (A button and B button)
xor a
ld [hli], a ; old menu item ID
ld [wMenuWatchMovingOutOfBounds], a
+ ld [hJoy7], a
.handleMenuInput
call HandleMenuInput
bit 1, a ; was the B button pressed?
@@ -105,6 +110,8 @@ HandlePokedexSideMenu:
jr z, .choseCry
dec a
jr z, .choseArea
+ dec a
+ jr z, .chosePrint
.choseQuit
ld b, 1
.exitSideMenu
@@ -118,6 +125,8 @@ HandlePokedexSideMenu:
ld [wLastMenuItem], a
pop af
ld [wCurrentMenuItem], a
+ ld a, $1
+ ld [hJoy7], a
push bc
coord hl, 0, 3
ld de, 20
@@ -128,9 +137,9 @@ HandlePokedexSideMenu:
.buttonBPressed
push bc
- coord hl, 15, 10
+ coord hl, 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 +161,105 @@ HandlePokedexSideMenu:
ld b, 0
jr .exitSideMenu
+.chosePrint
+ ld a, [hTilesetType]
+ push af
+ xor a
+ ld [hTilesetType], a
+ ld a, [wd11e]
+ ld [wcf91], a
+ callab PrintPokedexEntry
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call ClearScreen
+ pop af
+ ld [hTilesetType], 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 BIT_B_BUTTON, a ; was the B button pressed?
+ jp nz, .buttonBPressed
+ bit BIT_A_BUTTON, a ; was the A button pressed?
+ jp nz, .buttonAPressed
+.checkIfUpPressed
+ bit BIT_D_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 BIT_D_DOWN, a ; was Down pressed?
+ jr z, .checkIfRightPressed
+.downPressed ; scroll down one row
+ ld a, [wDexMaxSeenMon]
+ cp a, 7
+ jp c, .loop ; can't if the list is shorter than 7
+ sub a, 7
+ ld b, a
+ ld a, [wListScrollOffset]
+ cp b
+ jp z, .loop
+ inc a
+ ld [wListScrollOffset], a
+ jp .loop
+
+.checkIfRightPressed
+ bit BIT_D_RIGHT, a ; was Right pressed?
+ jr z, .checkIfLeftPressed
+.rightPressed ; scroll down 7 rows
+ ld a, [wDexMaxSeenMon]
+ cp a, 7
+ jp c, .loop ; can't if the list is shorter than 7
+ sub a, 6
+ ld b, a
+ ld a, [wListScrollOffset]
+ add a, 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 BIT_D_LEFT, a ; was Left pressed?
+ jr z, .buttonAPressed
+.leftPressed
+ ld a, [wListScrollOffset]
+ sub a, 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
ld [H_AUTOBGTRANSFERENABLED], a
; draw the horizontal line separating the seen and owned amounts from the menu
- coord hl, 15, 8
+ coord hl, 15, 6
ld a, "─"
ld [hli], a
ld [hli], a
@@ -175,26 +276,26 @@ HandlePokedexListMenu:
ld b, wPokedexSeenEnd - wPokedexSeen
call CountSetBits
ld de, wNumSetBits
- coord hl, 16, 3
+ coord hl, 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
- coord hl, 16, 6
+ coord hl, 16, 5
lb bc, 1, 3
call PrintNumber ; print number of owned pokemon
- coord hl, 16, 2
+ coord hl, 16, 1
ld de, PokedexSeenText
call PlaceString
- coord hl, 16, 5
+ coord hl, 16, 4
ld de, PokedexOwnText
call PlaceString
coord hl, 1, 1
ld de, PokedexContentsText
call PlaceString
- coord hl, 16, 10
+ coord hl, 16, 8
ld de, PokedexMenuItemsText
call PlaceString
; find the highest pokedex number among the pokemon the player has seen
@@ -214,7 +315,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 a, 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
ld [H_AUTOBGTRANSFERENABLED], a
coord hl, 4, 2
@@ -282,98 +413,8 @@ HandlePokedexListMenu:
ld a, 01
ld [H_AUTOBGTRANSFERENABLED], a
call Delay3
- call GBPalNormal
- call HandleMenuInput
- bit 1, a ; was the B button pressed?
- jp nz, .buttonBPressed
-.checkIfUpPressed
- bit 6, 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 7, 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 4, 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 5, 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
-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:
; [wd11e] = pokedex number
@@ -401,8 +442,11 @@ ShowPokedexDataInternal:
set 1, [hl]
ld a, $33 ; 3/7 volume
ld [rNR50], a
+ ld a, [hTilesetType]
+ push af
+ xor a
+ ld [hTilesetType], a
call GBPalWhiteOut ; zero all palettes
- call ClearScreen
ld a, [wd11e] ; pokemon ID
ld [wcf91], a
push af
@@ -410,10 +454,44 @@ ShowPokedexDataInternal:
call RunPaletteCommand
pop af
ld [wd11e], a
- ld a, [hTilesetType]
- push af
- xor a
+ call DrawDexEntryOnScreen
+ call c, Pokedex_PrintFlavorTextAtRow11
+.waitForButtonPress
+ call JoypadLowSensitivity
+ ld a, [hJoy5]
+ and a, A_BUTTON | B_BUTTON
+ jr z, .waitForButtonPress
+ pop af
ld [hTilesetType], a
+ call GBPalWhiteOut
+ call ClearScreen
+ call RunDefaultPaletteCommand
+ call LoadTextBoxTilePatterns
+ call GBPalNormal
+ ld hl, wd72c
+ res 1, [hl]
+ ld a, $77 ; max volume
+ ld [rNR50], a
+ ret
+
+HeightWeightText:
+ db "HT ?", $60, "??", $61
+ next "WT ???lb@"
+
+; XXX does anything point to this?
+PokeText:
+ db "#@"
+
+; horizontal line that divides the pokedex text description from the rest of the data
+PokedexDataDividerLine:
+ db $68, $69, $6B, $69, $6B
+ db $69, $6B, $69, $6B, $6B
+ db $6B, $6B, $69, $6B, $69
+ db $6B, $69, $6B, $69, $6A
+ db "@"
+
+DrawDexEntryOnScreen:
+ call ClearScreen
coord hl, 0, 0
ld de, 1
@@ -512,7 +590,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
coord hl, 12, 6
@@ -565,45 +644,48 @@ ShowPokedexDataInternal:
ld [hDexWeight], a ; restore original value of [hDexWeight]
pop hl
inc hl ; hl = address of pokedex description text
+ scf
+ ret
+
+Pokedex_PrintFlavorTextAtRow11:
coord bc, 1, 11
+Pokedex_PrintFlavorTextAtBC:
ld a, 2
- ld [$fff4], a
+ ld [$fff9], a
call TextCommandProcessor ; print pokedex description text
xor a
- ld [$fff4], a
-.waitForButtonPress
- call JoypadLowSensitivity
- ld a, [hJoy5]
- and A_BUTTON | B_BUTTON
- jr z, .waitForButtonPress
- pop af
- ld [hTilesetType], a
- call GBPalWhiteOut
- call ClearScreen
- call RunDefaultPaletteCommand
- call LoadTextBoxTilePatterns
- call GBPalNormal
- ld hl, wd72c
- res 1, [hl]
- ld a, $77 ; max volume
- ld [rNR50], a
+ ld [$fff9], a
ret
-HeightWeightText:
- db "HT ?",$60,"??",$61
- next "WT ???lb@"
-
-; XXX does anything point to this?
-PokeText:
- db "#@"
-
-; horizontal line that divides the pokedex text description from the rest of the data
-PokedexDataDividerLine:
- db $68,$69,$6B,$69,$6B
- db $69,$6B,$69,$6B,$6B
- db $6B,$6B,$69,$6B,$69
- db $6B,$69,$6B,$69,$6A
- db "@"
+Pokedex_PrepareDexEntryForPrinting:
+ coord hl, 0, 0
+ ld de, SCREEN_WIDTH
+ lb bc, $66, $d
+ call DrawTileLine
+ coord hl, 19, 0
+ ld b, $67
+ call DrawTileLine
+ coord hl, 0, 13
+ ld de, $1
+ lb bc, $6f, SCREEN_WIDTH
+ call DrawTileLine
+ ld a, $6c
+ Coorda 0, 13
+ ld a, $6e
+ Coorda 19, 13
+ ld a, [wPrinterPokedexEntryTextPointer]
+ ld l, a
+ ld a, [wPrinterPokedexEntryTextPointer + 1]
+ ld h, a
+ coord bc, 1, 1
+ ld a, [hFlags_0xFFFA]
+ set 3, a
+ ld [hFlags_0xFFFA], a
+ call Pokedex_PrintFlavorTextAtBC
+ ld a, [hFlags_0xFFFA]
+ res 3, a
+ ld [hFlags_0xFFFA], a
+ ret
; draws a line of tiles
; INPUT:
diff --git a/engine/menu/prize_menu.asm b/engine/menu/prize_menu.asm
index bcd0d4ea..405441c8 100755
--- a/engine/menu/prize_menu.asm
+++ b/engine/menu/prize_menu.asm
@@ -23,8 +23,7 @@ CeladonPrizeMenu:
ld [wTopMenuItemX], a
call PrintPrizePrice
coord hl, 0, 2
- ld b, 8
- ld c, 16
+ lb bc, 8, 16
call TextBoxBorder
call GetPrizeMenuId
call UpdateSprites
@@ -145,12 +144,14 @@ GetPrizeMenuId:
ld c, (1 << 7 | 2)
jp PrintBCDNumber
+NoThanksText:
+ db "NO THANKS@"
+
INCLUDE "data/prizes.asm"
PrintPrizePrice:
coord hl, 11, 0
- ld b, 1
- ld c, 7
+ lb bc, 1, 7
call TextBoxBorder
call UpdateSprites
coord hl, 12, 0
diff --git a/engine/menu/start_menu.asm b/engine/menu/start_menu.asm
index eb4b4f2d..498d1467 100755
--- a/engine/menu/start_menu.asm
+++ b/engine/menu/start_menu.asm
@@ -1,7 +1,5 @@
DisplayStartMenu::
- ld a, BANK(StartMenu_Pokedex)
- ld [H_LOADEDROMBANK], a
- ld [MBC1RomBank], a
+ switchbank StartMenu_Pokedex ; also bank for other functions
ld a, [wWalkBikeSurfState] ; walking/biking/surfing
ld [wWalkBikeSurfStateCopy], a
ld a, SFX_START_MENU
@@ -9,6 +7,7 @@ DisplayStartMenu::
RedisplayStartMenu::
callba DrawStartMenu
+RedisplayStartMenu_DoNotDrawStartMenu:
callba PrintSafariZoneSteps ; print Safari Zone info, if in Safari Zone
call UpdateSprites
.loop
diff --git a/engine/menu/start_sub_menus.asm b/engine/menu/start_sub_menus.asm
index 947837e3..abc8f000 100755
--- a/engine/menu/start_sub_menus.asm
+++ b/engine/menu/start_sub_menus.asm
@@ -144,11 +144,14 @@ StartMenu_Pokemon:
call ChooseFlyDestination
ld a, [wd732]
bit 3, a ; did the player decide to fly?
- jp nz, .goBackToMap
+ jr nz, .asm_5d4c
call LoadFontTilePatterns
ld hl, wd72e
set 1, [hl]
jp StartMenu_Pokemon
+.asm_5d4c
+ call Func_1510
+ jp .goBackToMap
.cut
bit 1, a ; does the player have the Cascade Badge?
jp z, .newBadgeRequired
@@ -165,15 +168,28 @@ StartMenu_Pokemon:
bit 1, [hl]
res 1, [hl]
jp z, .loop
- ld a, SURFBOARD
+ ld a, [wcf91]
+ cp PIKACHU ; is this surfing pikachu?
+ jr z, .surfingPikachu
+ ld a, $1
+ jr .continue
+.surfingPikachu
+ ld a, $2
+.continue
+ ld [wd473], a
+ ld a,SURFBOARD
ld [wcf91], 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 [wd473], a
+ jp .loop
.strength
bit 3, a ; does the player have the Rainbow Badge?
jp z, .newBadgeRequired
@@ -217,6 +233,7 @@ StartMenu_Pokemon:
ld hl, wd732
set 3, [hl]
set 6, [hl]
+ call Func_1510
ld hl, wd72e
set 1, [hl]
res 4, [hl]
@@ -307,11 +324,10 @@ StartMenu_Item:
call PrintText
jr .exitMenu
.notInCableClubRoom
- ld bc, wNumBagItems
ld hl, wListPointer
- ld a, c
- ld [hli], a
- ld [hl], b ; store item bag pointer in wListPointer (for DisplayListMenuID)
+ ld [hl], wNumBagItems & $ff
+ inc hl
+ ld [hl], wNumBagItems / $100 ; store item bag pointer in wListPointer (for DisplayListMenuID)
xor a
ld [wPrintItemPrices], a
ld a, ITEMLISTMENU
@@ -515,10 +531,11 @@ StartMenu_TrainerInfo:
call LoadScreenTilesFromBuffer2 ; restore saved screen
call RunDefaultPaletteCommand
call ReloadMapData
+ callba DrawStartMenu ; XXX what difference does this make?
call LoadGBPal
pop af
ld [hTilesetType], a
- jp RedisplayStartMenu
+ jp RedisplayStartMenu_DoNotDrawStartMenu
; loads tile patterns and draws everything except for gym leader faces / badges
DrawTrainerInfo:
@@ -552,7 +569,7 @@ DrawTrainerInfo:
ld de, vChars2 + $200
ld bc, $0400
ld a, $03
- call FarCopyData2
+ call FarCopyData
ld hl, TextBoxGraphics
ld de, $00d0
add hl, de ; hl = colon tile pattern
@@ -560,7 +577,7 @@ DrawTrainerInfo:
ld bc, $0010
ld a, $04
push bc
- call FarCopyData2
+ call FarCopyData
pop bc
ld hl, TrainerInfoTextBoxTileGraphics + $80 ; background tile pattern
ld de, vChars1 + $570
@@ -612,7 +629,7 @@ DrawTrainerInfo:
TrainerInfo_FarCopyData:
ld a, BANK(TrainerInfoTextBoxTileGraphics)
- jp FarCopyData2
+ jp FarCopyData
TrainerInfo_NameMoneyTimeText:
db "NAME/"
diff --git a/engine/menu/status_screen.asm b/engine/menu/status_screen.asm
index ef94f13c..1e2ba889 100755
--- a/engine/menu/status_screen.asm
+++ b/engine/menu/status_screen.asm
@@ -40,7 +40,7 @@ DrawHP_:
push hl
call DrawHPBar
pop hl
- ld a, [hFlags_0xFFF6]
+ ld a, [hFlags_0xFFFA]
bit 0, a
jr z, .printFractionBelowBar
ld bc, $9 ; right of bar
@@ -170,8 +170,25 @@ StatusScreen:
call GBPalNormal
coord hl, 1, 0
call LoadFlippedFrontSpriteByMonIndex ; draw Pokémon picture
+ ld a, [wMonDataLocation]
+ cp ENEMY_PARTY_DATA
+ jr z, .playRegularCry
+ cp BOX_DATA
+ jr z, .checkBoxData
+ callab IsThisPartymonStarterPikachu_Party
+ jr nc, .playRegularCry
+ jr .playPikachuSoundClip
+.checkBoxData
+ callab IsThisPartymonStarterPikachu_Box
+ jr nc, .playRegularCry
+.playPikachuSoundClip
+ ld e, 16
+ callab PlayPikachuSoundClip
+ jr .continue
+.playRegularCry
ld a, [wcf91]
call PlayCry ; play Pokémon cry
+.continue
call WaitForTextScrollButtonPress ; wait for button
pop af
ld [hTilesetType], a
@@ -250,16 +267,14 @@ PrintStatsBox:
and a ; a is 0 from the status screen
jr nz, .DifferentBox
coord hl, 0, 8
- ld b, 8
- ld c, 8
+ lb bc, 8, 8
call TextBoxBorder ; Draws the box
coord hl, 1, 9 ; Start printing stats from here
ld bc, $0019 ; Number offset
jr .PrintStats
.DifferentBox
coord hl, 9, 2
- ld b, 8
- ld c, 9
+ lb bc, 8, 9
call TextBoxBorder
coord hl, 11, 3
ld bc, $0018
@@ -314,8 +329,7 @@ StatusScreen2:
coord hl, 19, 3
ld [hl], $78
coord hl, 0, 8
- ld b, 8
- ld c, 18
+ lb bc, 8, 18
call TextBoxBorder ; Draw move container
coord hl, 2, 9
ld de, wMovesString
diff --git a/engine/menu/text_box.asm b/engine/menu/text_box.asm
index b9a36652..a109bff2 100644
--- a/engine/menu/text_box.asm
+++ b/engine/menu/text_box.asm
@@ -273,8 +273,7 @@ DisplayMoneyBox:
ld [wTextBoxID], a
call DisplayTextBoxID
coord hl, 13, 1
- ld b, 1
- ld c, 6
+ lb bc, 1, 6
call ClearScreenArea
coord hl, 12, 1
ld de, wPlayerMoney
@@ -416,36 +415,10 @@ DisplayTwoOptionMenu:
pop hl
add hl, bc
call PlaceString
- ld hl, wd730
- res 6, [hl] ; turn on the printing delay
- 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, [wFlags_0xcd60]
- push af
- push hl
- ld hl, wFlags_0xcd60
- bit 5, [hl]
- set 5, [hl] ; don't play sound when A or B is pressed in menu
- pop hl
-.noYesMenuInputLoop
- call HandleMenuInput
- bit 1, a ; A button pressed?
- jr nz, .noYesMenuInputLoop ; try again if A was not pressed
- pop af
- pop hl
- ld [wFlags_0xcd60], a
- ld a, SFX_PRESS_AB
- call PlaySound
- jr .pressedAButton
-.notNoYesMenu
xor a
ld [wTwoOptionMenuID], a
+ ld hl, wd730
+ res 6, [hl] ; turn on the printing delay
call HandleMenuInput
pop hl
bit 1, a ; A button pressed?
@@ -577,8 +550,7 @@ DisplayFieldMoveMonMenu:
; no field moves
coord hl, 11, 11
- ld b, 5
- ld c, 7
+ lb bc, 5, 7
call TextBoxBorder
call UpdateSprites
ld a, 12
diff --git a/engine/menu/vending_machine.asm b/engine/menu/vending_machine.asm
index aab4adf4..37d9b9e7 100755
--- a/engine/menu/vending_machine.asm
+++ b/engine/menu/vending_machine.asm
@@ -18,8 +18,7 @@ VendingMachineMenu:
ld hl, wd730
set 6, [hl]
coord hl, 0, 3
- ld b, 8
- ld c, 12
+ lb bc, 8, 12
call TextBoxBorder
call UpdateSprites
coord hl, 2, 5
diff --git a/engine/mon_party_sprites.asm b/engine/mon_party_sprites.asm
index 864ac136..6f17f876 100755
--- a/engine/mon_party_sprites.asm
+++ b/engine/mon_party_sprites.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
@@ -228,6 +228,11 @@ MonPartySpritePointers:
db BANK(MonPartySprites)
dw vSprites + $260
+ dw PikachuSprite
+ db $40 / $10 ; $40 bytes
+ db BANK(PikachuSprite)
+ dw vSprites + $280
+
dw MonPartySprites + $100
db $40 / $10 ; $40 bytes
db BANK(MonPartySprites)
@@ -298,6 +303,11 @@ MonPartySpritePointers:
db BANK(MonPartySprites)
dw vSprites + $660
+ dw PikachuSprite + $C0
+ db $40 / $10 ; $40 bytes
+ db BANK(PikachuSprite)
+ dw vSprites + $680
+
dw MonPartySprites + $140
db $40 / $10 ; $40 bytes
db BANK(MonPartySprites)
@@ -309,6 +319,8 @@ WriteMonPartySpriteOAMByPartyIndex:
push de
push bc
ld a, [hPartyMonIndex]
+ cp $ff
+ jr z, .asm_7191f
ld hl, wPartySpecies
ld e, a
ld d, 0
@@ -322,6 +334,16 @@ WriteMonPartySpriteOAMByPartyIndex:
pop hl
ret
+.asm_7191f
+ ld hl, wOAMBuffer
+ 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].
@@ -343,7 +365,7 @@ UnusedPartyMonSpriteFunction:
ld hl, vSprites
call .LoadTilePatterns
pop af
- add $54
+ add $5A
ld hl, vSprites + $40
call .LoadTilePatterns
xor a
diff --git a/engine/multiply_divide.asm b/engine/multiply_divide.asm
index 52e86b36..d664c9d4 100755
--- a/engine/multiply_divide.asm
+++ b/engine/multiply_divide.asm
@@ -7,11 +7,12 @@ _Multiply:
ld [H_MULTIPLYBUFFER+1], a
ld [H_MULTIPLYBUFFER+2], a
ld [H_MULTIPLYBUFFER+3], a
-.loop
+.multiplyLoop
ld a, [H_MULTIPLIER]
srl a
- ld [H_MULTIPLIER], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
- jr nc, .smallMultiplier
+ ld [H_MULTIPLIER], a
+ jr nc, .smallMultiplier ; less than $80
+; code to possibly multiply the multiplicand by 2 and divide the multiplier by 2?
ld a, [H_MULTIPLYBUFFER+3]
ld c, a
ld a, [H_MULTIPLICAND+2]
@@ -24,12 +25,12 @@ _Multiply:
ld [H_MULTIPLYBUFFER+2], a
ld a, [H_MULTIPLYBUFFER+1]
ld c, a
- ld a, [H_MULTIPLICAND] ; (aliases: H_MULTIPLICAND)
+ ld a, [H_MULTIPLICAND]
adc c
ld [H_MULTIPLYBUFFER+1], a
ld a, [H_MULTIPLYBUFFER]
ld c, a
- ld a, [H_PRODUCT] ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT)
+ ld a, [H_PRODUCT]
adc c
ld [H_MULTIPLYBUFFER], a
.smallMultiplier
@@ -47,7 +48,7 @@ _Multiply:
ld a, [H_PRODUCT]
rl a
ld [H_PRODUCT], a
- jr .loop
+ jr .multiplyLoop
.done
ld a, [H_MULTIPLYBUFFER+3]
ld [H_PRODUCT+3], a
@@ -68,28 +69,28 @@ _Divide:
ld [H_DIVIDEBUFFER+4], a
ld a, $9
ld e, a
-.asm_37db3
+.asm_f6680
ld a, [H_DIVIDEBUFFER]
ld c, a
- ld a, [H_DIVIDEND+1] ; (aliases: H_MULTIPLICAND)
+ ld a, [H_DIVIDEND+1]
sub c
ld d, a
- ld a, [H_DIVISOR] ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
+ ld a, [H_DIVISOR]
ld c, a
- ld a, [H_DIVIDEND] ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT)
+ ld a, [H_DIVIDEND]
sbc c
- jr c, .asm_37dce
- ld [H_DIVIDEND], a ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT)
+ jr c, .asm_f669b
+ ld [H_DIVIDEND], a
ld a, d
- ld [H_DIVIDEND+1], a ; (aliases: H_MULTIPLICAND)
+ ld [H_DIVIDEND+1], a
ld a, [H_DIVIDEBUFFER+4]
inc a
ld [H_DIVIDEBUFFER+4], a
- jr .asm_37db3
-.asm_37dce
+ jr .asm_f6680
+.asm_f669b
ld a, b
cp $1
- jr z, .asm_37e18
+ jr z, .done
ld a, [H_DIVIDEBUFFER+4]
sla a
ld [H_DIVIDEBUFFER+4], a
@@ -103,41 +104,41 @@ _Divide:
rl a
ld [H_DIVIDEBUFFER+1], a
dec e
- jr nz, .asm_37e04
+ jr nz, .asm_f66d1
ld a, $8
ld e, a
ld a, [H_DIVIDEBUFFER]
- ld [H_DIVISOR], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
+ ld [H_DIVISOR], a
xor a
ld [H_DIVIDEBUFFER], a
- ld a, [H_DIVIDEND+1] ; (aliases: H_MULTIPLICAND)
- ld [H_DIVIDEND], a ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT)
+ ld a, [H_DIVIDEND+1]
+ ld [H_DIVIDEND], a
ld a, [H_DIVIDEND+2]
- ld [H_DIVIDEND+1], a ; (aliases: H_MULTIPLICAND)
+ ld [H_DIVIDEND+1], a
ld a, [H_DIVIDEND+3]
ld [H_DIVIDEND+2], a
-.asm_37e04
+.asm_f66d1
ld a, e
cp $1
- jr nz, .asm_37e0a
+ jr nz, .asm_f66d7
dec b
-.asm_37e0a
- ld a, [H_DIVISOR] ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
+.asm_f66d7
+ ld a, [H_DIVISOR]
srl a
- ld [H_DIVISOR], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
+ ld [H_DIVISOR], a
ld a, [H_DIVIDEBUFFER]
rr a
ld [H_DIVIDEBUFFER], a
- jr .asm_37db3
-.asm_37e18
- ld a, [H_DIVIDEND+1] ; (aliases: H_MULTIPLICAND)
- ld [H_REMAINDER], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN)
+ jr .asm_f6680
+.done
+ ld a, [H_DIVIDEND+1]
+ ld [H_REMAINDER], a
ld a, [H_DIVIDEBUFFER+4]
ld [H_QUOTIENT+3], a
ld a, [H_DIVIDEBUFFER+3]
ld [H_QUOTIENT+2], a
ld a, [H_DIVIDEBUFFER+2]
- ld [H_QUOTIENT+1], a ; (aliases: H_MULTIPLICAND)
+ ld [H_QUOTIENT+1], a
ld a, [H_DIVIDEBUFFER+1]
- ld [H_DIVIDEND], a ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT)
+ ld [H_QUOTIENT], a
ret
diff --git a/engine/oak_speech.asm b/engine/oak_speech.asm
index b1acfb65..8a537579 100755
--- a/engine/oak_speech.asm
+++ b/engine/oak_speech.asm
@@ -5,6 +5,8 @@ SetDefaultNames:
push af
ld a, [wd732]
push af
+ ld a, [wPrinterSettings]
+ push af
ld hl, wPlayerName
ld bc, wBoxDataEnd - wPlayerName
xor a
@@ -13,6 +15,12 @@ SetDefaultNames:
ld bc, $200
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 [wd732], a
pop af
@@ -29,11 +37,11 @@ SetDefaultNames:
ld hl, SonyText
ld de, wRivalName
ld bc, NAME_LENGTH
- jp CopyData
+ call CopyData ; rip optimizations
+ ret
OakSpeech:
- ld a, $FF
- call PlaySound ; stop music
+ call StopAllMusic ; stop music
ld a, BANK(Music_Routes2)
ld c, a
ld a, MUSIC_ROUTES2
@@ -64,7 +72,7 @@ OakSpeech:
call PrintText
call GBFadeOutToWhite
call ClearScreen
- ld a, NIDORINO
+ ld a, PIKACHU
ld [wd0b5], a
ld [wcf91], a
call GetMonHeader
@@ -109,13 +117,13 @@ OakSpeech:
ld a, SFX_SHRINK
call PlaySound
pop af
- ld [H_LOADEDROMBANK], a
- ld [MBC1RomBank], 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
@@ -133,17 +141,13 @@ OakSpeech:
ld [wAudioSavedROMBank], a
ld a, 10
ld [wAudioFadeOutControl], a
- ld a, $FF
- ld [wNewSoundID], a
- call PlaySound ; stop music
+ call StopAllMusic ; stop music
pop af
- ld [H_LOADEDROMBANK], a
- ld [MBC1RomBank], a
+ call BankswitchCommon
ld c, 20
call DelayFrames
coord hl, 6, 5
- ld b, 7
- ld c, 7
+ lb bc, 7, 7
call ClearScreenArea
call LoadTextBoxTilePatterns
ld a, 1
@@ -151,7 +155,9 @@ OakSpeech:
ld c, 50
call DelayFrames
call GBFadeOutToWhite
- jp ClearScreen
+ call ClearScreen ; rip more tail-end optimizations
+ ret
+
OakSpeechText1:
TX_FAR _OakSpeechText1
db "@"
@@ -176,6 +182,7 @@ FadeInIntroPic:
.next
ld a, [hli]
ld [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 10
call DelayFrames
dec b
@@ -197,6 +204,7 @@ MovePicLeft:
ld a, %11100100
ld [rBGP], a
+ call UpdateGBCPal_BGP
.next
call DelayFrame
ld a, [rWX]
@@ -215,10 +223,13 @@ IntroDisplayPicCenteredOrUpperRight:
push bc
ld a, b
call UncompressSpriteFromDE
+ ld a, $0
+ call SwitchSRAMBankAndLatchClockData
ld hl, sSpriteBuffer1
ld de, sSpriteBuffer0
ld bc, $310
call CopyData
+ call PrepareRTCDataAndDisableSRAM
ld de, vFrontPic
call InterlaceMergeSpriteBuffers
pop bc
diff --git a/engine/oak_speech2.asm b/engine/oak_speech2.asm
index 1258c59b..80f1bafc 100755
--- a/engine/oak_speech2.asm
+++ b/engine/oak_speech2.asm
@@ -108,6 +108,7 @@ OakSpeechSlidePicCommon:
.loop
xor a
ld [H_AUTOBGTRANSFERENABLED], a
+ ld [H_AUTOBGTRANSFERPORTION], a
ld 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
coord hl, 0, 0
- ld b, $a
- ld c, $9
+ lb bc, 10, 9
call TextBoxBorder
coord hl, 3, 0
ld de, .namestring
@@ -187,10 +187,9 @@ DisplayIntroNameTextBox:
.namestring
db "NAME@"
-IF DEF(_RED)
DefaultNamesPlayer:
db "NEW NAME"
- next "RED"
+ next "YELLOW"
next "ASH"
next "JACK"
db "@"
@@ -201,23 +200,6 @@ DefaultNamesRival:
next "GARY"
next "JOHN"
db "@"
-ENDC
-
-IF DEF(_BLUE)
-DefaultNamesPlayer:
- db "NEW NAME"
- next "BLUE"
- next "GARY"
- next "JOHN"
- db "@"
-
-DefaultNamesRival:
- db "NEW NAME"
- next "RED"
- next "ASH"
- next "JACK"
- db "@"
-ENDC
GetDefaultName:
; a = name index
@@ -243,30 +225,17 @@ GetDefaultName:
ld bc, $14
jp CopyData
-IF DEF(_RED)
DefaultNamesPlayerList:
db "NEW NAME@"
- db "RED@"
+ db "YELLOW@"
db "ASH@"
db "JACK@"
+
DefaultNamesRivalList:
db "NEW NAME@"
db "BLUE@"
db "GARY@"
db "JOHN@"
-ENDC
-IF DEF(_BLUE)
-DefaultNamesPlayerList:
- db "NEW NAME@"
- db "BLUE@"
- db "GARY@"
- db "JOHN@"
-DefaultNamesRivalList:
- db "NEW NAME@"
- db "RED@"
- db "ASH@"
- db "JACK@"
-ENDC
TextTerminator_6b20:
db "@"
diff --git a/engine/overworld/advance_player_sprite.asm b/engine/overworld/advance_player_sprite.asm
new file mode 100644
index 00000000..6b4a0cbb
--- /dev/null
+++ b/engine/overworld/advance_player_sprite.asm
@@ -0,0 +1,241 @@
+_AdvancePlayerSprite::
+ ld a,[wSpriteStateData1 + 3] ; delta Y
+ ld b,a
+ ld a,[wSpriteStateData1 + 5] ; delta X
+ ld c,a
+ ld hl,wWalkCounter ; walking animation counter
+ 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] ; walking animation counter
+ cp a,$07
+ jp nz,.scrollBackgroundAndSprites
+; if this is the first iteration of the animation
+ ld a,c
+ cp a,$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 a,$ff
+ jr nz,.checkIfMovingSouth
+; moving west
+ ld a,[wMapViewVRAMPointer]
+ ld e,a
+ and a,$e0
+ ld d,a
+ ld a,e
+ sub $02
+ and $1f
+ or d
+ ld [wMapViewVRAMPointer],a
+ jr .adjustXCoordWithinBlock
+.checkIfMovingSouth
+ ld a,b
+ cp a,$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 a,$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 a,$ff
+ jr nz,.adjustYCoordWithinBlock
+; moved into the tile block to the west
+ ld a,$1
+ 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 $2
+ 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 a,$ff
+ jr nz,.updateMapView
+; moved into the tile block to the north
+ ld a,$1
+ ld [hl],a
+ ld hl,wYOffsetSinceLastSpecialWarp
+ dec [hl]
+ ld de,wCurrentTileBlockMapViewPointer
+ ld a,[wCurMapWidth]
+ call MoveTileBlockMapPointerNorth
+.updateMapView
+ call LoadCurrentMapView
+ ld a,[wSpriteStateData1 + 3] ; delta Y
+ cp $1
+ 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,[wSpriteStateData1 + 5] ; delta X
+ cp $1
+ jr nz,.checkIfMovingWest2
+; if moving east
+ call ScheduleEastColumnRedraw
+ jr .scrollBackgroundAndSprites
+.checkIfMovingWest2
+ cp $ff
+ jr nz,.scrollBackgroundAndSprites
+; if moving west
+ call ScheduleWestColumnRedraw
+.scrollBackgroundAndSprites
+ ld a,[wSpriteStateData1 + 3] ; delta Y
+ add a
+ ld b,a
+ ld a,[wSpriteStateData1 + 5] ; delta X
+ 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,wSpriteStateData1 + $14
+ 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
+ ld a,[hSCY]
+ add b
+ ld [hSCY],a ; update background scroll Y
+ ld a,[hSCX]
+ add c
+ ld [hSCX],a ; update background scroll X
+ ret
+
+MoveTileBlockMapPointerEast::
+ ld a,[de]
+ add $1
+ ld [de],a
+ ret nc
+ inc de
+ ld a,[de]
+ inc a
+ ld [de],a
+ ret
+
+MoveTileBlockMapPointerWest::
+ ld a,[de]
+ sub $1
+ ld [de],a
+ ret nc
+ inc de
+ ld a,[de]
+ dec a
+ ld [de],a
+ ret
+
+MoveTileBlockMapPointerSouth::
+ add $6
+ 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 $6
+ 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/cable_club_npc.asm b/engine/overworld/cable_club_npc.asm
index 08067412..12ce64a4 100755
--- a/engine/overworld/cable_club_npc.asm
+++ b/engine/overworld/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
@@ -107,7 +110,61 @@ CableClubNPC:
xor a
ld [hld], a
ld [hl], a
- jpab LinkMenu
+ ld a, [wLetterPrintingDelayFlags]
+ push af
+ callab 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:
TX_FAR _CableClubNPCAreaReservedFor2FriendsLinkedByCableText
diff --git a/engine/overworld/card_key.asm b/engine/overworld/card_key.asm
index 35495c82..a4452b4a 100755
--- a/engine/overworld/card_key.asm
+++ b/engine/overworld/card_key.asm
@@ -8,7 +8,8 @@ PrintCardKeyText:
ret z
cp b
jr nz, .silphCoMapListLoop
- predef GetTileAndCoordsInFrontOfPlayer
+; does not check for tile in front of player. This might be buggy
+ ;predef GetTileAndCoordsInFrontOfPlayer
ld a, [wTileInFrontOfPlayer]
cp $18
jr z, .cardKeyDoorInFrontOfPlayer
@@ -25,12 +26,12 @@ PrintCardKeyText:
ld b, CARD_KEY
call IsItemInBag
jr z, .noCardKey
- call GetCoordsInFrontOfPlayer
- push de
+ xor a
+ ld [wPlayerMovingDirection], a
tx_pre_id CardKeySuccessText
ld [hSpriteIndexOrTextID], a
call PrintPredefTextID
- pop de
+ call GetCoordsInFrontOfPlayer
srl d
ld a, d
ld b, a
@@ -88,7 +89,7 @@ GetCoordsInFrontOfPlayer:
ld d, a
ld a, [wXCoord]
ld e, a
- ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+ ld a, [wSpritePlayerStateData1FacingDirection] ; player's sprite facing direction
and a
jr nz, .notFacingDown
; facing down
diff --git a/engine/overworld/cut.asm b/engine/overworld/cut.asm
index f6ae6468..bc7d092d 100755
--- a/engine/overworld/cut.asm
+++ b/engine/overworld/cut.asm
@@ -76,6 +76,7 @@ InitCutAnimOAM:
ld [wWhichAnimationOffsets], a
ld a, %11100100
ld [rOBP1], a
+ call UpdateGBCPal_OBP1
ld a, [wCutTile]
cp $52
jr z, .grass
@@ -123,8 +124,8 @@ WriteCutOrBoulderDustAnimationOAMBlock:
jp WriteOAMBlock
CutOrBoulderDustAnimationTilesAndAttributes:
- db $FC,$10,$FD,$10
- db $FE,$10,$FF,$10
+ db $FC,$14,$FD,$14
+ db $FE,$14,$FF,$14
GetCutOrBoulderDustAnimationOffsets:
ld hl, wSpriteStateData1 + 4
@@ -187,7 +188,7 @@ ReplaceTreeTileBlock:
ld h, [hl]
ld l, a
add hl, bc
- ld a, [wSpriteStateData1 + 9] ; player sprite's facing direction
+ ld a, [wSpritePlayerStateData1FacingDirection] ; player sprite's facing direction
and a
jr z, .down
cp SPRITE_FACING_UP
diff --git a/engine/overworld/cut2.asm b/engine/overworld/cut2.asm
index f16fed66..37490f95 100755
--- a/engine/overworld/cut2.asm
+++ b/engine/overworld/cut2.asm
@@ -18,6 +18,7 @@ AnimCut:
ld a, [rOBP1]
xor $64
ld [rOBP1], a
+ call UpdateGBCPal_OBP1
call DelayFrame
pop bc
dec c
@@ -68,6 +69,7 @@ AnimCutGrass_UpdateOAMEntries:
ld a, [rOBP1]
xor $64
ld [rOBP1], a
+ call UpdateGBCPal_OBP1
call DelayFrame
pop bc
dec c
diff --git a/engine/overworld/doors.asm b/engine/overworld/doors.asm
index c39e096d..8bde8600 100755
--- a/engine/overworld/doors.asm
+++ b/engine/overworld/doors.asm
@@ -39,6 +39,7 @@ DoorTileIDPointers:
dbw LAB, LabDoorTileIDs
dbw FACILITY, FacilityDoorTileIDs
dbw PLATEAU, PlateauDoorTileIDs
+ dbw INTERIOR, InteriorDoorTileIDs
db $ff
OverworldDoorTileIDs:
@@ -73,3 +74,6 @@ FacilityDoorTileIDs:
PlateauDoorTileIDs:
db $3b,$1b,$00
+
+InteriorDoorTileIDs:
+ db $04,$15,$00
diff --git a/engine/overworld/dungeon_warps.asm b/engine/overworld/dungeon_warps.asm
new file mode 100644
index 00000000..f47dfb01
--- /dev/null
+++ b/engine/overworld/dungeon_warps.asm
@@ -0,0 +1,15 @@
+IsPlayerOnDungeonWarp:
+ xor a
+ ld [wWhichDungeonWarp], a
+ ld a, [wd72d]
+ bit 4, a
+ ret nz
+ call ArePlayerCoordsInArray
+ ret nc
+ ld a, [wCoordIndex]
+ ld [wWhichDungeonWarp], a
+ ld hl, wd72d
+ set 4, [hl]
+ ld hl, wd732
+ set 4, [hl]
+ ret
diff --git a/engine/overworld/elevator.asm b/engine/overworld/elevator.asm
index d68e4f81..47ec78f9 100755
--- 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, $ff
- call PlaySound
+ call StopAllMusic
ld a, [hSCY]
ld d, a
ld e, $1
@@ -27,8 +26,7 @@ ShakeElevator:
jr nz, .shakeLoop
ld a, d
ld [hSCY], a
- ld a, $ff
- 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 ac4276bd..3b02fd55 100755
--- 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 + $780
lb bc, BANK(EmotionBubbles), $04
call CopyVideoData
@@ -59,12 +62,9 @@ EmotionBubble:
pop af
ld [wUpdateSpritesEnabled], a
call DelayFrame
- jp UpdateSprites
+ call UpdateSprites
+ ret
-EmotionBubblesPointerTable:
- dw EmotionBubbles
- dw EmotionBubbles + $40
- dw EmotionBubbles + $80
EmotionBubblesOAM:
db $F8,$00,$F9,$00
diff --git a/engine/overworld/field_move_messages.asm b/engine/overworld/field_move_messages.asm
index b1506742..1d111917 100644
--- a/engine/overworld/field_move_messages.asm
+++ b/engine/overworld/field_move_messages.asm
@@ -32,7 +32,7 @@ IsSurfingAllowed:
ret nz
CheckBothEventsSet EVENT_SEAFOAM4_BOULDER1_DOWN_HOLE, EVENT_SEAFOAM4_BOULDER2_DOWN_HOLE
ret z
- ld hl, CoordsData_cdf7
+ ld hl, CoordsData_f5b64
call ArePlayerCoordsInArray
ret nc
ld hl, wd728
@@ -45,7 +45,7 @@ IsSurfingAllowed:
ld hl, CyclingIsFunText
jp PrintText
-CoordsData_cdf7:
+CoordsData_f5b64:
db $0B,$07,$FF
CurrentTooFastText:
diff --git a/engine/overworld/healing_machine.asm b/engine/overworld/healing_machine.asm
index 38a44cfb..e5ba004e 100755
--- a/engine/overworld/healing_machine.asm
+++ b/engine/overworld/healing_machine.asm
@@ -12,14 +12,13 @@ AnimateHealingMachine:
push af
ld a, $e0
ld [rOBP1], a
+ call UpdateGBCPal_OBP1
ld hl, wOAMBuffer + $84
ld de, PokeCenterOAMData
call CopyHealingMachineOAM
ld a, 4
ld [wAudioFadeOutControl], a
- ld a, $ff
- ld [wNewSoundID], a
- call PlaySound
+ call StopAllMusic
.waitLoop
ld a, [wAudioFadeOutControl]
and a ; is fade-out finished?
@@ -35,12 +34,10 @@ AnimateHealingMachine:
dec b
jr nz, .partyLoop
ld a, [wAudioROMBank]
- cp BANK(Audio3_UpdateMusic)
+ cp BANK(AudioEngine3)
ld [wAudioSavedROMBank], a
jr nz, .next
- ld a, $ff
- 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
ld [rOBP1], a
+ call UpdateGBCPal_OBP1
pop hl
pop af
ld [hl], a
@@ -66,13 +64,13 @@ PokeCenterFlashingMonitorAndHealBall:
INCBIN "gfx/pokecenter_ball.2bpp"
PokeCenterOAMData:
- db $24,$34,$7C,$10 ; heal machine monitor
- db $2B,$30,$7D,$10 ; pokeballs 1-6
- db $2B,$38,$7D,$30
- db $30,$30,$7D,$10
- db $30,$38,$7D,$30
- db $35,$30,$7D,$10
- db $35,$38,$7D,$30
+ db $24,$34,$7C,$14 ; heal machine monitor
+ db $2B,$30,$7D,$14 ; pokeballs 1-6
+ db $2B,$38,$7D,$34
+ db $30,$30,$7D,$14
+ db $30,$38,$7D,$34
+ db $35,$30,$7D,$14
+ db $35,$38,$7D,$34
; d = value to xor with palette
FlashSprite8Times:
@@ -81,6 +79,7 @@ FlashSprite8Times:
ld a, [rOBP1]
xor d
ld [rOBP1], a
+ call UpdateGBCPal_OBP1
ld c, 10
call DelayFrames
dec b
diff --git a/engine/overworld/hidden_items.asm b/engine/overworld/hidden_items.asm
index 32783f83..b64411c7 100755
--- a/engine/overworld/hidden_items.asm
+++ b/engine/overworld/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
+ ld [hItemAlreadyFound], a
+ ret
+
INCLUDE "data/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
ld [hUnusedCoinsByte], a
ld [hCoins], a
@@ -79,6 +84,12 @@ HiddenCoins:
cp 40
jr z, .bcd20 ; should be bcd40
jr .bcd100
+
+.doNotPickUpCoins
+ ld a, $ff
+ ld [hItemAlreadyFound], a
+ ret
+
.bcd10
ld a, $10
ld [hCoins + 1], a
diff --git a/engine/overworld/hidden_objects.asm b/engine/overworld/hidden_objects.asm
index dcdf8537..66815b60 100755
--- a/engine/overworld/hidden_objects.asm
+++ b/engine/overworld/hidden_objects.asm
@@ -1,43 +1,17 @@
-IsPlayerOnDungeonWarp:
- xor a
- ld [wWhichDungeonWarp], a
- ld a, [wd72d]
- bit 4, a
- ret nz
- call ArePlayerCoordsInArray
- ret nc
- ld a, [wCoordIndex]
- ld [wWhichDungeonWarp], a
- ld hl, wd72d
- set 4, [hl]
- ld hl, wd732
- set 4, [hl]
- ret
-
-; if a hidden object was found, stores $00 in [$ffee], else stores $ff
+; if a hidden object was found, stores $00 in [hDidntFindAnyHiddenObject], else stores $ff
CheckForHiddenObject:
- ld hl, $ffeb
+ ld hl, hItemAlreadyFound
xor a
ld [hli], a
ld [hli], a
ld [hli], a
ld [hl], a
- ld de, $0
ld hl, HiddenObjectMaps
-.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, HiddenObjectPointers
- add hl, de
+ call IsInArray
+ jr nc, .noMatch
+ inc hl
ld a, [hli]
ld h, [hl]
ld l, a
@@ -81,13 +55,13 @@ CheckForHiddenObject:
ret
.noMatch
ld a, $ff
- ld [$ffee], a
+ ld [hDidntFindAnyHiddenObject], a
ret
; checks if the coordinates in front of the player's sprite match Y in b and X in c
; [hCoordsInFrontOfPlayerMatch] = $00 if they match, $ff if they don't match
CheckIfCoordsInFrontOfPlayerMatch:
- ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+ ld a, [wSpritePlayerStateData1FacingDirection] ; player's sprite facing direction
cp SPRITE_FACING_UP
jr z, .facingUp
cp SPRITE_FACING_LEFT
diff --git a/engine/overworld/ledges.asm b/engine/overworld/ledges.asm
index 342540b2..a44ddf8b 100755
--- a/engine/overworld/ledges.asm
+++ b/engine/overworld/ledges.asm
@@ -6,7 +6,7 @@ HandleLedges:
and a ; OVERWORLD
ret nz
predef GetTileAndCoordsInFrontOfPlayer
- ld a, [wSpriteStateData1 + 9]
+ ld a, [wSpritePlayerStateData1FacingDirection]
ld b, a
aCoord 8, 9
ld c, a
@@ -71,10 +71,13 @@ LoadHoppingShadowOAM:
ld de, LedgeHoppingShadow
lb bc, BANK(LedgeHoppingShadow), (LedgeHoppingShadowEnd - LedgeHoppingShadow) / $8
call CopyVideoDataDouble
- ld a, $9
- lb bc, $54, $48 ; b, c = y, x coordinates of shadow
- ld de, LedgeHoppingShadowOAM
- call WriteOAMBlock
+ ld hl, LedgeHoppingShadowOAM
+ ld de, wOAMBuffer + 36 * 4
+ ld bc, LedgeHoppingShadowOAMEnd - LedgeHoppingShadowOAM
+ call CopyData
+ ld a, $a0
+ ld [wOAMBuffer + 38 * 4], a
+ ld [wOAMBuffer + 39 * 4], a
ret
LedgeHoppingShadow:
@@ -82,5 +85,6 @@ LedgeHoppingShadow:
LedgeHoppingShadowEnd:
LedgeHoppingShadowOAM:
- db $FF,$10,$FF,$20
- db $FF,$40,$FF,$60
+ db $58,$48,$FF,$00
+ db $58,$50,$FF,$20
+LedgeHoppingShadowOAMEnd:
diff --git a/engine/overworld/map_sprite_functions1.asm b/engine/overworld/map_sprite_functions1.asm
index d1a411fa..2ad923fb 100644
--- a/engine/overworld/map_sprite_functions1.asm
+++ b/engine/overworld/map_sprite_functions1.asm
@@ -1,7 +1,7 @@
_UpdateSprites:
- ld h, $c1
+ ld h, wSpriteStateData1 / $100
inc h
- ld a, $e ; wSpriteStateData2 + $0e
+ ld a, $e ; (wSpriteStateData2 + $0e) & $ff
.spriteLoop
ld l, a
sub $e
@@ -24,9 +24,12 @@ _UpdateSprites:
jr nz, .spriteLoop
ret
.updateCurrentSprite
- cp $1
- jp nz, UpdateNonPlayerSprite
- jp UpdatePlayerSprite
+ ld a, [H_CURRENTSPRITEOFFSET]
+ and a
+ jp z, UpdatePlayerSprite
+ cp $f0 ; pikachu
+ jp z, SpawnPikachu
+ ld a, [hl]
UpdateNonPlayerSprite:
dec a
@@ -51,11 +54,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, wSpriteStateData1 / $100
ld a, [H_CURRENTSPRITEOFFSET]
- add wSpriteStateData1 % $100
ld l, a
ld a, [hl] ; a = [$c1i0] (picture) (0 if slot is unused)
@@ -270,6 +272,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 [wd434], a
+ ld a, [$ff8f]
+ cp $f
+ jr nz, .asm_4cd9
+ call Func_4d0a
+ jr .asm_4cef
+.asm_4cd9
ld a, [$ff91] ; a = 7 or 9 depending on sprite i's delta X
ld b, a
ld a, [$ff90] ; a = 7 or 9 depending on sprite i's delta Y
@@ -294,6 +307,7 @@ DetectCollisionBetweenSprites:
; set bit in [$c1ie] or [$c1if] to indicate which sprite the collision occurred with
inc l
inc l
+.asm_4cef
ld a, [$ff8f] ; a = loop counter
ld de, SpriteCollisionBitTable
add a
@@ -322,6 +336,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:
+ ld a, [$ff91]
+ ld b, a
+ ld a, [$ff90]
+ 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 [wd434], a
+ ld a, c
+ inc l
+ inc l
+ ret
+
SetSpriteCollisionValues:
and a
ld b, 0
diff --git a/engine/overworld/map_sprites.asm b/engine/overworld/map_sprites.asm
index 8a6057a0..3e2c3912 100755
--- a/engine/overworld/map_sprites.asm
+++ b/engine/overworld/map_sprites.asm
@@ -8,261 +8,23 @@
; fields, respectively, within loops. The X is the loop index.
; If there is an inner loop, Y is the inner loop index, i.e. $C1Y* and $C2Y*
; 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 >= $25)
- ld hl, wSpriteStateData1
- ld de, wSpriteStateData2 + $0d
-; Loop to copy picture ID's from $C1X0 to $C2XD for LoadMapSpriteTilePatterns.
-.copyPictureIDLoop
- ld a, [hl] ; $C1X0 (picture ID)
- ld [de], a ; $C2XD
- ld a, $10
- add e
- ld e, a
- ld a, $10
- 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, $10 ; number of sprite slots
- ld hl, wSpriteStateData2 + $0d
- xor a
- ld [hFourTileSpriteCount], a
-.copyPictureIDLoop ; loop to copy picture ID from $C2XD to $C2XE
- ld a, [hli] ; $C2XD (sprite picture ID)
- ld [hld], a ; $C2XE
- ld a, l
- add $10
- ld l, a
- dec b
- jr nz, .copyPictureIDLoop
- ld hl, wSpriteStateData2 + $1e
-.loadTilePatternLoop
- ld de, wSpriteStateData2 + $1d
-; 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 $10
- ld e, a
- jr .checkIfAlreadyLoadedLoop
-.notAlreadyLoaded
- ld de, wSpriteStateData2 + $0e
- ld b, $01
-; 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 $10
- ld e, a
- ld a, l
- cp e ; reached current slot?
- jr z, .foundNextVRAMSlot
- ld a, [de] ; $C2YE (VRAM slot)
- 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] ; $C2XE (sprite picture ID)
- ld b, a ; b = current sprite picture ID
- cp SPRITE_BALL ; is it a 4-tile sprite?
- jr c, .notFourTileSprite
- pop af
- ld a, [hFourTileSpriteCount]
- add 11
- jr .storeVRAMSlot
-.notFourTileSprite
- pop af
-.storeVRAMSlot
- ld [hl], a ; store VRAM slot at $C2XE
- ld [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, $c0 ; number of bytes per VRAM slot
- ld a, [hVRAMSlot]
- cp 11 ; is it a 4-tile sprite?
- jr nc, .fourTileSpriteVRAMAddr
- ld d, a
- dec d
-; Equivalent to multiplying $C0 (number of bytes in 12 tiles) times the VRAM
-; slot and adding the result to $8000 (the VRAM base address).
-.calculateVRAMAddrLoop
- add hl, bc
- dec d
- jr nz, .calculateVRAMAddrLoop
- jr .loadStillTilePattern
-.fourTileSpriteVRAMAddr
- ld hl, vSprites + $7c0 ; address for second 4-tile sprite
- ld a, [hFourTileSpriteCount]
- and a
- jr nz, .loadStillTilePattern
-; if it's the first 4-tile sprite
- ld hl, vSprites + $780 ; address for first 4-tile sprite
- inc a
- ld [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 0, 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
- ld 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 0, a ; reloading upper half of tile patterns after displaying text?
- jr nz, .loadWhileLCDOn
- pop af
- pop hl
- set 3, h ; add $800 to hl
- 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 to hl
- 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 = VRAM slot for the current picture ID (from $C2YE)
- ld [hl], a ; store VRAM slot in current wSpriteStateData2 sprite slot (at $C2XE)
-.nextSpriteSlot
- ld a, l
- add $10
- ld l, a
- dec c
- jp nz, .loadTilePatternLoop
- ld hl, wSpriteStateData2 + $0d
- ld b, $10
-; the pictures ID's stored at $C2XD are no longer needed, so zero them
-.zeroStoredPictureIDLoop
- xor a
- ld [hl], a ; $C2XD
- ld a, $10
- 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 Func_14150
ret
; Loads sprite set for outside maps (cities and routes) and sets VRAM slots.
; sets carry if the map is a city or route, unsets carry if not
InitOutsideMapSprites:
ld a, [wCurMap]
- cp REDS_HOUSE_1F ; is the map a city or a route (map ID less than $25)?
+ cp a, REDS_HOUSE_1F ; is the map a city or a route (map ID less than $25)?
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 $f0 ; 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 0, a ; reloading upper half of tile patterns after displaying text?
@@ -274,120 +36,285 @@ 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) * 11
- 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, wSpriteStateData2 + $0d
- ld a, SPRITE_RED
- ld [hl], a
- ld bc, wSpriteSet
-; Load the sprite set into RAM.
-; This loop also fills $C2XD (sprite picture ID) where X is from $0 to $A
-; with picture ID's. This is done so that LoadMapSpriteTilePatterns will
-; load tile patterns for all sprite pictures in the sprite set.
-.loadSpriteSetLoop
- ld a, $10
- add l
- ld l, a
- ld a, [de] ; sprite picture ID from sprite set
- ld [hl], a ; $C2XD (sprite picture ID)
- ld [bc], a
- inc de
- inc bc
- ld a, l
- cp $bd ; 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, $10
- add l
- ld l, a
- xor a
- ld [hl], a ; $C2XD (sprite picture ID)
- dec b
- jr nz, .zeroRemainingSlotsLoop
- ld a, [wNumSprites]
- push af ; save number of sprites
- ld a, 11 ; 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, wSpriteStateData2 + $1e
- ld b, $0f
-; 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 ; $C2XE (VRAM slot)
- ld a, $10
- add l
- ld l, a
- dec b
- jr nz, .zeroVRAMSlotsLoop
.skipLoadingSpriteSet
- ld hl, wSpriteStateData1 + $10
+ call Func_14150
+ 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] ; $C1X0 (picture ID) (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, .isFourTileSprite
+; loop through the space reserved for four tile picture IDs
+ ld de, wSpriteSet + 9
+ ld b, 2
+ call CheckIfPictureIDAlreadyLoaded
+ jr .continue
+
+.isFourTileSprite
+; 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
- ld a, $0e
- add l
- ld l, a
- ld a, c ; a = VRAM slot (zero if sprite slot is not used)
- ld [hl], a ; $C2XE (VRAM slot)
- pop hl
- ld a, $10
- 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 SPRITE_BALL ; 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
+ ld [hVRAMSlot], a
+ cp 9
+ jr nc, .fourTileSprite
+ call LoadStillTilePattern
+ call LoadWalkingTilePattern
+ jr .continue
+
+.fourTileSprite
+ call LoadStillTilePattern
+.continue
+ ld a, [hVRAMSlot]
+ inc a
+ cp 11
+ jr nz, .loop
+ ret
+
+ReloadWalkingTilePatterns:
+ xor a
+.loop
+ ld [hVRAMSlot], a
+ cp 9
+ jr nc, .fourTileSprite
+ call LoadWalkingTilePattern
+.fourTileSprite
+ ld a, [hVRAMSlot]
+ inc a
+ cp 11
+ jr nz, .loop
+ ret
+
+LoadStillTilePattern:
+ ld a, [wFontLoaded]
+ bit 0, 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 to hl
+ call CopyVideoDataAlternate
+ ret
+
+GetSpriteVRAMAddress:
+ push bc
+ ld 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:
+; Equivalent to multiplying $C0 (number of bytes in 12 tiles) times the VRAM
+; slot and adding the result to $8000 (the VRAM base address).
+ dw vChars0 + $0c0
+ dw vChars0 + $180
+ dw vChars0 + $240
+ dw vChars0 + $300
+ dw vChars0 + $3c0
+ dw vChars0 + $480
+ dw vChars0 + $540
+ dw vChars0 + $600
+ dw vChars0 + $6c0
+ dw vChars0 + $780 ; 4-tile sprites
+ dw vChars0 + $7c0 ; 4-tile sprites
+
+ReadSpriteSheetData:
+ ld 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
+Func_14150:
+ 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
+ ld [hVRAMSlot], a ; store current sprite set slot as a counter
+ ld a, [hl] ; $c1x0 (picture ID)
+ and a ; is the sprite unused?
+ jr z, .spriteUnused
+ call Func_14179
+ push hl
+ ld de, (wSpritePlayerStateData2ImageBaseOffset) - (wSpriteStateData1) ; $10e
+ add hl, de ; get $c2xe (sprite image base offset)
+ ld [hl], a ; write offset
+ pop hl
+.spriteUnused
+ ld de, wSprite02StateData1 - wSprite01StateData1
+ add hl, de
+ ld a, [hVRAMSlot]
+ dec a
+ jr nz, .loop
+ ret
+
+Func_14179:
+ 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 a, $f0 ; 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 $f8
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/missable_objects.asm b/engine/overworld/missable_objects.asm
index 8587c0f7..dd601451 100644
--- a/engine/overworld/missable_objects.asm
+++ b/engine/overworld/missable_objects.asm
@@ -17,33 +17,30 @@ MarkTownVisitedAndLoadMissableObjects:
ld h, [hl]
; fall through
-LoadMissableObjects:
+; LoadMissableObjects:
+; seems to not exist in yellow (predef replaced with something near TryPushingBoulder)
ld l, a
push hl
- ld de, MapHS00 ; calculate difference between out pointer and the base pointer
ld a, l
- sub e
- jr nc, .asm_f13c
- dec h
-.asm_f13c
+ sub MapHS00 & $ff ; calculate difference between out pointer and the base pointer
ld l, a
ld a, h
- sub d
+ sbc MapHS00 / $100
ld h, a
ld a, h
ld [H_DIVIDEND], a
ld a, l
- ld [H_DIVIDEND+1], a
+ ld [H_DIVIDEND + 1], a
xor a
- ld [H_DIVIDEND+2], a
- ld [H_DIVIDEND+3], a
+ ld [H_DIVIDEND + 2], a
+ ld [H_DIVIDEND + 3], a
ld a, $3
ld [H_DIVISOR], a
ld b, $2
call Divide ; divide difference by 3, resulting in the global offset (number of missable items before ours)
ld a, [wCurMap]
ld b, a
- ld a, [H_DIVIDEND+3]
+ ld a, [H_DIVIDEND + 3]
ld c, a ; store global offset in c
ld de, wMissableObjectList
pop hl
diff --git a/engine/overworld/movement.asm b/engine/overworld/movement.asm
index f272f497..f2334479 100644
--- a/engine/overworld/movement.asm
+++ b/engine/overworld/movement.asm
@@ -22,7 +22,13 @@ UpdatePlayerSprite:
ld [wSpriteStateData1 + 2], a
ret
.lowerLeftTileIsMapTile
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
call DetectCollisionBetweenSprites
+ pop af
+ ld [wUpdateSpritesEnabled], a
ld h, wSpriteStateData1 / $100
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 0, a
+ jr z, .moving
.notMoving
; zero the animation counters
xor a
ld [wSpriteStateData1 + 7], a
ld [wSpriteStateData1 + 8], a
- jr .calcImageIndex
-.next
- ld [wSpriteStateData1 + 9], a ; facing direction
- ld a, [wFontLoaded]
- bit 0, a
- jr nz, .notMoving
+ call Func_4e32
+ jr .skipSpriteAnim
.moving
ld a, [wd736]
bit 7, a ; is the player sprite spinning due to a spin tile?
jr nz, .skipSpriteAnim
- ld a, [H_CURRENTSPRITEOFFSET]
- 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, [wSpriteStateData1 + 8]
- ld b, a
- ld a, [wSpriteStateData1 + 9]
- add b
- ld [wSpriteStateData1 + 2], 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
@@ -97,18 +85,15 @@ UpdatePlayerSprite:
jr nz, .next2
ld a, $80
.next2
- ld [wSpriteStateData2 + 7], a
+ ld [wSpriteStateData2 + $07], a
ret
-UnusedReadSpriteDataFunction:
- push bc
- push af
- ld a, [H_CURRENTSPRITEOFFSET]
- ld c, a
- pop af
- add c
- ld l, a
- pop bc
+Func_4e32:
+ ld a, [wSpriteStateData1 + 8]
+ ld b, a
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ add b
+ ld [wSpriteStateData1 + 2], a
ret
UpdateNPCSprite:
@@ -121,7 +106,7 @@ UpdateNPCSprite:
ld l, a
ld a, [hl] ; read movement byte 2
ld [wCurSpriteMovement2], a
- ld h, $c1
+ ld h, wSpriteStateData1 / $100
ld a, [H_CURRENTSPRITEOFFSET]
ld l, a
inc l
@@ -130,7 +115,7 @@ UpdateNPCSprite:
jp z, InitializeSpriteStatus
call CheckSpriteAvailability
ret c ; if sprite is invisible, on tile >=MAP_TILESET_SIZE, in grass or player is currently walking
- ld h, $c1
+ ld h, wSpriteStateData1 / $100
ld a, [H_CURRENTSPRITEOFFSET]
ld l, a
inc l
@@ -146,19 +131,21 @@ UpdateNPCSprite:
jp z, UpdateSpriteMovementDelay ; c1x1 == 2
cp $3
jp z, UpdateSpriteInWalkingAnimation ; c1x1 == 3
+ cp $4
+ jp z, Func_5357
ld a, [wWalkCounter]
and a
ret nz ; don't do anything yet if player is currently moving (redundant, already tested in CheckSpriteAvailability)
call InitializeSpriteScreenPosition
- ld h, $c2
+ ld h, wSpriteStateData2 / $100
ld a, [H_CURRENTSPRITEOFFSET]
add $6
ld l, a
ld a, [hl] ; c2x6: movement byte 1
inc a
- jr z, .randomMovement ; value $FF
+ jp z, .randomMovement ; value $FF
inc a
- jr z, .randomMovement ; value $FE
+ jp z, .randomMovement ; value $FE
; 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 $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,59 +256,25 @@ ChangeFacingDirection:
; set carry on failure, clears carry on success
TryWalking:
push hl
- ld h, $c1
- ld a, [H_CURRENTSPRITEOFFSET]
- add $9
- ld l, a
- ld [hl], c ; c1x9 (update facing direction)
- ld a, [H_CURRENTSPRITEOFFSET]
- add $3
- ld l, a
- ld [hl], d ; c1x3 (update Y movement delta)
- inc l
- inc l
- ld [hl], e ; c1x5 (update X movement delta)
+ 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, $c2
+ ret c
+ call Func_5349
ld a, [H_CURRENTSPRITEOFFSET]
- add $4
ld l, a
- ld a, [hl] ; c2x4: Y position
- add d
- ld [hli], a ; update Y position
- ld a, [hl] ; c2x5: X position
- add e
- ld [hl], a ; update X position
- ld a, [H_CURRENTSPRITEOFFSET]
- ld l, a
- ld [hl], $10 ; c2x0=16: walk animation counter
+ ld [hl], $10 ; c1x9 (update facing direction)
dec h
inc l
- ld [hl], $3 ; c1x1: set movement status to walking
+ ld [hl], $3
jp UpdateSpriteImage
; update the walking animation parameters for a sprite that is currently walking
UpdateSpriteInWalkingAnimation:
- ld a, [H_CURRENTSPRITEOFFSET]
- add $7
- ld l, a
- ld a, [hl] ; c1x7 (counter until next walk animation frame)
- inc a
- ld [hl], a ; c1x7 += 1
- cp $4
- jr nz, .noNextAnimationFrame
- xor a
- ld [hl], a ; c1x7 = 0
- inc l
- ld a, [hl] ; c1x8 (walk animation frame)
- inc a
- and $3
- ld [hl], a ; advance to next animation frame every 4 ticks (16 ticks total for one step)
+ call Func_5274
.noNextAnimationFrame
ld a, [H_CURRENTSPRITEOFFSET]
add $3
@@ -446,6 +405,7 @@ InitializeSpriteStatus:
ld a, $8
ld [hli], a ; $c2x2: set Y displacement to 8
ld [hl], a ; $c2x3: set X displacement to 8
+ call InitializeSpriteScreenPosition ; could have done fallthrough here
ret
; calculates the sprite's screen position form its map position and the player position
@@ -458,7 +418,7 @@ InitializeSpriteScreenPosition:
ld b, a
ld a, [hl] ; c2x4 (Y position + 4)
sub b ; relative to player position
- swap a ; * 16
+ call Func_5033
sub $4 ; - 4
dec h
ld [hli], a ; c1x4 (screen Y position)
@@ -467,11 +427,23 @@ InitializeSpriteScreenPosition:
ld b, a
ld a, [hli] ; c2x6 (X position + 4)
sub b ; relative to player position
- swap a ; * 16
+ call Func_5033
dec h
ld [hl], a ; c1x6 (screen X position)
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
@@ -591,17 +563,9 @@ 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
- ld h, $c2
+ call _IsTilePassable
+ jr c, .impassable
+ ld h, wSpriteStateData2 / $100
ld a, [H_CURRENTSPRITEOFFSET]
add $6
ld l, a
@@ -624,7 +588,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, wSpriteStateData1 / $100
@@ -643,7 +613,7 @@ CanWalkOntoTile:
jr nz, .upwards
add d
cp $5
- jr c, .impassable ; if c2x2+d < 5, don't go ;bug: this tests probably were supposed to prevent sprites
+ ;jr c, .impassable (bugfix) ; if c2x2+d < 5, don't go ;bug: this tests probably were supposed to prevent sprites
jr .checkHorizontal ; from walking out too far, but this line makes sprites get stuck
.upwards ; whenever they walked upwards 5 steps
sub $1 ; on the other hand, the amount a sprite can walk out to the
@@ -665,7 +635,7 @@ CanWalkOntoTile:
and a ; clear carry (marking success)
ret
.impassable
- ld h, $c1
+ ld h, wSpriteStateData1 / $100
ld a, [H_CURRENTSPRITEOFFSET]
inc a
ld l, a
@@ -697,7 +667,7 @@ GetTileSpriteStandsOn:
ld l, a
ld a, [hli] ; c1x4: screen Y position
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
@@ -863,20 +833,235 @@ AnimScriptedNPCMovement:
ret
AdvanceScriptedNPCAnimFrameCounter:
+ call Func_5274
+ ld h, wSpriteStateData1 / $100
ld a, [H_CURRENTSPRITEOFFSET]
- add $7
+ add $8
ld l, a
ld a, [hl] ; intra-animation frame counter
+ and $3
+ ld [hSpriteAnimFrameCounter], a
+ ret
+
+Func_5274:
+ ld a, [H_CURRENTSPRITEOFFSET]
+ add $7
+ ld l, a
+ ld h, wSpriteStateData1 / $100
+ ld a, [hl] ; c1x7 (counter until next walk animation frame)
inc a
+ and $3
+ ld [hl], a ; c1x7 += 1
+ ret nz ; c1x7 = 0
+ inc l
+ ld a, [hl] ; c1x8 (walk animation frame)
+ 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
+ ld a, [H_CURRENTSPRITEOFFSET]
+ ld l, a
+ ld [hl], $8
+ dec h
+ inc l
+ ld [hl], $4
+ call UpdateSpriteImage
+ scf
+ ret
+
+.asm_52fa
+ call Func_5337
+ ld a, [H_CURRENTSPRITEOFFSET]
+ 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
+ ld a, [H_CURRENTSPRITEOFFSET]
+ 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:
+ ld a, [H_CURRENTSPRITEOFFSET]
+ add $9
+ ld l, a
+ ld h, wSpriteStateData1 / $100
+ ld [hl], c ; c1x9 (update facing direction)
+ ld a, [H_CURRENTSPRITEOFFSET]
+ add $3
+ ld l, a
+ ld [hl], d ; c1x3 (update Y movement delta)
+ inc l
+ inc l
+ ld [hl], e ; c1x5 (update X movement delta)
+ ret
+
+Func_5349:
+ ld h, wSpriteStateData2 / $100
+ ld a, [H_CURRENTSPRITEOFFSET]
+ add $4
+ ld l, a
+ ld a, [hl] ; c2x4: Y position
+ add d
+ ld [hli], a ; update Y position
+ ld a, [hl] ; c2x5: X position
+ add e
+ ld [hl], a ; update X position
+ ret
+
+Func_5357:
+ call Func_5274
+ ld a, [H_CURRENTSPRITEOFFSET]
+ add $3
+ ld l, a
+ ld h, wSpriteStateData1 / $100
+ 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
- cp 4
+ ld a, [H_CURRENTSPRITEOFFSET]
+ ld l, a
+ ld h, wSpriteStateData2 / $100
+ dec [hl]
ret nz
+ ld a, $6
+ add l
+ ld l, a
+ ld a, [hl]
+ cp $fe
+ jr nc, .asm_5386
+ ld a, [H_CURRENTSPRITEOFFSET]
+ inc a
+ ld l, a
+ ld h, wSpriteStateData1 / $100
+ ld [hl], $1
+ ret
+.asm_5386
+ call Random
+ ld a, [H_CURRENTSPRITEOFFSET]
+ add $8
+ ld l, a
+ ld h, wSpriteStateData2 / $100
+ ld a, [hRandomAdd]
+ and $7f
+ ld [hl], a
+ dec h
+ ld a, [H_CURRENTSPRITEOFFSET]
+ inc a
+ ld l, a
+ ld [hl], $2
+ inc l
+ inc l
xor a
- ld [hl], a ; reset intra-animation frame counter
+ ld b, [hl]
+ ld [hli], a
inc l
- ld a, [hl] ; animation frame counter
- inc a
- and $3
+ ld c, [hl]
ld [hl], a
- ld [hSpriteAnimFrameCounter], a
ret
diff --git a/engine/overworld/npc_movement.asm b/engine/overworld/npc_movement.asm
index 968615f0..670cb121 100755
--- a/engine/overworld/npc_movement.asm
+++ b/engine/overworld/npc_movement.asm
@@ -37,8 +37,8 @@ _EndNPCMovementScript:
res 1, [hl]
xor a
ld [wNPCMovementScriptSpriteOffset], a
- ld [wNPCMovementScriptPointerTableNum], a
ld [wNPCMovementScriptFunctionNum], a
+ ld [wNPCMovementScriptPointerTableNum], a
ld [wWastedByteCD3A], 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, wFlags_D733
set 1, [hl]
ld a, $fc
@@ -127,8 +131,9 @@ PalletMovementScript_WalkToLab:
ld [wNPCMovementScriptFunctionNum], a
ret
+
RLEList_ProfOakWalkToLab:
- db NPC_MOVEMENT_DOWN, $05
+ db NPC_MOVEMENT_DOWN, $06 ; differs from red
db NPC_MOVEMENT_LEFT, $01
db NPC_MOVEMENT_DOWN, $05
db NPC_MOVEMENT_RIGHT, $03
@@ -141,7 +146,7 @@ RLEList_PlayerWalkToLab:
db D_RIGHT, $03
db D_DOWN, $05
db D_LEFT, $01
- db D_DOWN, $06
+ db D_DOWN, $07 ; differs from red
db $FF
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, $03
db $FF
-FreezeEnemyTrainerSprite:
- ld a, [wCurMap]
- cp POKEMON_TOWER_7F
- ret z ; the Rockets on Pokemon Tower 7F leave after battling, so don't freeze them
- ld hl, RivalIDs
- ld a, [wEngagedTrainerClass]
- ld b, a
-.loop
- ld a, [hli]
- cp $ff
- jr z, .notRival
- cp b
- ret z ; the rival leaves after battling, so don't freeze him
- jr .loop
-.notRival
- ld a, [wSpriteIndex]
- ld [H_SPRITEINDEX], a
- jp SetSpriteMovementBytesToFF
-
-RivalIDs:
- db OPP_SONY1
- db OPP_SONY2
- db OPP_SONY3
- db $ff
+INCLUDE "engine/overworld/pewter_guys.asm"
diff --git a/engine/overworld/npc_movement_2.asm b/engine/overworld/npc_movement_2.asm
new file mode 100755
index 00000000..93d1afce
--- /dev/null
+++ b/engine/overworld/npc_movement_2.asm
@@ -0,0 +1,24 @@
+FreezeEnemyTrainerSprite:
+ ld a, [wCurMap]
+ cp POKEMON_TOWER_7F
+ ret z ; the Rockets on Pokemon Tower 7F leave after battling, so don't freeze them
+ ld hl, RivalIDs
+ ld a, [wEngagedTrainerClass]
+ ld b, a
+.loop
+ ld a, [hli]
+ cp $ff
+ jr z, .notRival
+ cp b
+ ret z ; the rival leaves after battling, so don't freeze him
+ jr .loop
+.notRival
+ ld a, [wSpriteIndex]
+ ld [H_SPRITEINDEX], a
+ jp SetSpriteMovementBytesToFF
+
+RivalIDs:
+ db OPP_SONY1
+ db OPP_SONY2
+ db OPP_SONY3
+ db $ff
diff --git a/engine/overworld/oam.asm b/engine/overworld/oam.asm
index 2c2a3dff..5a831327 100644
--- a/engine/overworld/oam.asm
+++ b/engine/overworld/oam.asm
@@ -1,6 +1,8 @@
PrepareOAMData:
; Determine OAM data for currently visible
; sprites and write it to wOAMBuffer.
+; Yellow code has been changed to use registers more efficiently
+; as well as tweaking the code to show gbc palettes
ld a, [wUpdateSpritesEnabled]
dec a
@@ -18,9 +20,9 @@ PrepareOAMData:
.spriteLoop
ld [hSpriteOffset2], a
- ld d, wSpriteStateData1 / $100
- ld a, [hSpriteOffset2]
ld e, a
+ ld d, wSpriteStateData1 / $100
+
ld a, [de] ; c1x0
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:
ld [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
ld a, [hOAMBufferOffset]
+ add [hl]
+ cp $a0
+ jr z, .hidden
+ jr nc, .asm_4a41
+.hidden
+ call Func_4a7b
+ ld [wd5cd], a
+ ld a, [hOAMBufferOffset]
+
ld e, a
ld d, wOAMBuffer / $100
.tileLoop
+ ld a, [hli]
+ ld c, a
+.loop
ld 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
ld 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 a, [wd5cd]
+ add [hl]
+ cp $80
+ jr c, .asm_4a1c
ld b, a
-
- ld a, [wd5cd] ; temp copy of c1x2
- 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
+ ld a, [$fffc]
+ add b
+.asm_4a1c
ld [de], a ; tile id
inc hl
inc e
@@ -129,15 +118,19 @@ PrepareOAMData:
ld a, [hSpritePriority]
or [hl]
.skipPriority
- inc hl
+ and $f0
+ bit 4, a ; OBP0 or OBP1
+ jr z, .spriteusesOBP0
+ or %100 ; palettes 4-7 are OBP1
+.spriteusesOBP0
ld [de], a
+ inc hl
inc e
- bit 0, a ; OAMFLAG_ENDOFDATA
- jr z, .tileLoop
+ dec c
+ jr nz, .loop
ld a, e
ld [hOAMBufferOffset], a
-
.nextSprite
ld a, [hSpriteOffset2]
add $10
@@ -145,26 +138,31 @@ PrepareOAMData:
jp nz, .spriteLoop
; Clear unused OAM.
- ld a, [hOAMBufferOffset]
- ld l, a
- ld h, wOAMBuffer / $100
- ld de, $4
- ld b, $a0
+.asm_4a41
ld a, [wd736]
bit 6, a ; jumping down ledge or fishing animation?
- ld a, $a0
+ ld c, $a0
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, $90
+ ld c, $90
.clear
- cp l
- ret z
+ ld a, [hOAMBufferOffset]
+ cp c
+ ret nc
+ ld l, a
+ ld h, wOAMBuffer / $100
+ 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 ; c1xb (x)
ret
+
+Func_4a7b:
+ push bc
+ ld a, [wd5cd] ; temp copy of c1x2
+ 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/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 a,$ff
+ jr z,.tileNotPassable
+ cp c
+ jr nz,.loop
+ xor a
+ ret
+.tileNotPassable
+ scf
+ ret
+
+INCLUDE "data/collision.asm" ; probably
diff --git a/engine/overworld/player_animations.asm b/engine/overworld/player_animations.asm
index a17e67bd..d4ecec53 100755
--- a/engine/overworld/player_animations.asm
+++ b/engine/overworld/player_animations.asm
@@ -13,8 +13,8 @@ EnterMapAnim:
call PlaySound
ld hl, wd732
bit 4, [hl] ; used dungeon warp?
- res 4, [hl]
pop hl
+ ;res 4, [hl]
jr nz, .dungeonWarpAnimation
call PlayerSpinWhileMovingDown
ld a, SFX_TELEPORT_ENTER_2
@@ -34,21 +34,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 +62,8 @@ EnterMapAnim:
ld de, FlyAnimationEnterScreenCoords
call DoFlyAnimation
call LoadPlayerSpriteGraphics
+ ld a, $1
+ ld [wPikachuSpawnState], a
jr .restoreDefaultMusic
FlyAnimationEnterScreenCoords:
@@ -90,7 +93,9 @@ PlayerSpinWhileMovingDown:
ld [hl], a ; wPlayerSpinWhileMovingUpOrDownAnimFrameDelay
jp PlayerSpinWhileMovingUpOrDown
+
_LeaveMapAnim:
+ call Func_1510
call InitFacingDirectionList
call IsPlayerStandingOnWarpPadOrHole
ld a, b
@@ -249,12 +254,14 @@ DoFlyAnimation:
LoadBirdSpriteGraphics:
ld de, BirdSprite
+ ld b, BANK(BirdSprite)
+ ld c, $c
ld hl, vNPCSprites
- lb bc, BANK(BirdSprite), $0c
call CopyVideoData
ld de, BirdSprite + $c0 ; moving animation sprite
+ ld b, BANK(BirdSprite)
+ ld c, $0c
ld hl, vNPCSprites2
- lb bc, BANK(BirdSprite), $0c
jp CopyVideoData
InitFacingDirectionList:
@@ -386,9 +393,10 @@ FishingAnim:
call DelayFrames
ld hl, wd736
set 6, [hl] ; reserve the last 4 OAM entries
- ld de, RedSprite
ld hl, vNPCSprites
- lb bc, BANK(RedSprite), $c
+ ld de, RedSprite
+ ld b, BANK(RedSprite)
+ ld c, $c
call CopyVideoData
ld a, $4
ld hl, RedFishingTiles
diff --git a/engine/overworld/player_state.asm b/engine/overworld/player_state.asm
index 73c55da2..8cbacc61 100644
--- a/engine/overworld/player_state.asm
+++ b/engine/overworld/player_state.asm
@@ -70,7 +70,8 @@ CheckForceBikeOrSurf:
ld a, $1
ld [wWalkBikeSurfState], a
ld [wWalkBikeSurfStateCopy], a
- jp ForceBikeOrSurf
+ call ForceBikeOrSurf
+ ret
.incorrectMap
inc hl
.incorrectY
@@ -80,7 +81,8 @@ CheckForceBikeOrSurf:
ld a, $2
ld [wWalkBikeSurfState], a
ld [wWalkBikeSurfStateCopy], a
- jp ForceBikeOrSurf
+ call ForceBikeOrSurf
+ ret
INCLUDE "data/force_bike_surf.asm"
@@ -101,10 +103,10 @@ IsPlayerFacingEdgeOfMap:
ld b, a
ld a, [wXCoord]
ld c, a
- ld de, .asm_c41e
+ ld de, .returnaddress
push de
jp hl
-.asm_c41e
+.returnaddress
pop bc
pop de
pop hl
@@ -240,8 +242,7 @@ PrintSafariZoneSteps:
cp CERULEAN_CAVE_2F
ret nc
coord hl, 0, 0
- ld b, 3
- ld c, 7
+ lb bc, 3, 7
call TextBoxBorder
coord hl, 1, 1
ld de, wSafariSteps
@@ -255,11 +256,11 @@ PrintSafariZoneSteps:
call PlaceString
ld a, [wNumSafariBalls]
cp 10
- jr nc, .asm_c56d
+ jr nc, .numSafariBallsTwoDigits
coord hl, 5, 3
ld a, " "
ld [hl], a
-.asm_c56d
+.numSafariBallsTwoDigits
coord hl, 6, 3
ld de, wNumSafariBalls
lb bc, 1, 2
@@ -361,16 +362,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/poison.asm b/engine/overworld/poison.asm
index 5d8eb9fd..03fb8a65 100644
--- a/engine/overworld/poison.asm
+++ b/engine/overworld/poison.asm
@@ -2,13 +2,20 @@ ApplyOutOfBattlePoisonDamage:
ld a, [wd730]
add a
jp c, .noBlackOut ; no black out if joypad states are being simulated
+ ld a, [wd492]
+ bit 7, a
+ jp nz, .noBlackOut
+ ld a, [wd72e]
+ bit 6, 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
@@ -54,6 +61,12 @@ ApplyOutOfBattlePoisonDamage:
ld a, TEXT_MON_FAINTED
ld [hSpriteIndexOrTextID], a
call DisplayTextID
+ callab IsThisPartymonStarterPikachu_Party
+ jr nc, .curMonNotPlayerPikachu
+ ld e, $3
+ callab PlayPikachuSoundClip
+ calladb_ModifyPikachuHappiness PIKAHAPPY_PSNFNT
+.curMonNotPlayerPikachu
pop de
pop hl
.nextMon
@@ -110,3 +123,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
+ calladb_ModifyPikachuHappiness $6
+.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 [wd49c], a
+ ret
diff --git a/engine/overworld/pokecenter.asm b/engine/overworld/pokecenter.asm
index f26bedf8..cf0159f9 100755
--- a/engine/overworld/pokecenter.asm
+++ b/engine/overworld/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
+ callab IsStarterPikachuInOurParty
+ jr nc, .notHealingPlayerPikachu
+ call CheckPikachuFollowingPlayer
+ jr nz, .notHealingPlayerPikachu
+ call LoadCurrentMapView
+ call Delay3
+ call UpdateSprites
+ callab PikachuWalksToNurseJoy ; todo
+.notHealingPlayerPikachu
ld hl, NeedYourPokemonText
call PrintText
- ld a, $18
- ld [wSpriteStateData1 + $12], 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
+ callab IsStarterPikachuInOurParty
+ call c, Func_6eaa
+.playerPikachuNotOnScreen
+ lb bc, 1, 8
+ call Func_6ebb
+ ld c, 30
+ call DelayFrames
callba 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
+ callab IsStarterPikachuInOurParty
+ 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 [wSpriteStateData1 + $12], a ; make the nurse bow
- ld c, a
+ callab IsStarterPikachuInOurParty
+ jr nc, .notInParty
+ lb bc, 15, 0
+ call Func_6ebb
+.notInParty
+ call LoadCurrentMapView
+ call Delay3
+ call UpdateSprites
+ callab ReloadWalkingTilePatterns
+ ld a, $1
+ ld [H_SPRITEINDEX], a
+ ld a, $1
+ ld [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
+ ld [H_SPRITEINDEX], a
+ ld a, $4
+ ld [hSpriteImageIndex], a
+ call SpriteFunc_34a1
+ ld c, 64
+ call DelayFrames
+ ret
+
+Func_6ebb:
+ ld a, b
+ ld [H_SPRITEINDEX], a
+ ld a, c
+ ld [hSpriteImageIndex], a
+ push bc
+ call SetSpriteFacingDirectionAndDelay
+ pop bc
+ ld a, b
+ ld [H_SPRITEINDEX], a
+ ld a, c
+ ld [hSpriteImageIndex], a
+ call SpriteFunc_34a1
+ ret
PokemonCenterWelcomeText:
TX_FAR _PokemonCenterWelcomeText
@@ -66,3 +143,7 @@ PokemonCenterFarewellText:
TX_DELAY
TX_FAR _PokemonCenterFarewellText
db "@"
+
+LooksContentText:
+ TX_FAR _LooksContentText
+ db "@"
diff --git a/engine/overworld/push_boulder.asm b/engine/overworld/push_boulder.asm
index c91605a8..8a385345 100644
--- a/engine/overworld/push_boulder.asm
+++ b/engine/overworld/push_boulder.asm
@@ -2,6 +2,8 @@ TryPushingBoulder:
ld a, [wd728]
bit 0, a ; using Strength?
ret z
+Func_f0a7:
+; where LoadMissableObjects predef points to now
ld a, [wFlags_0xcd60]
bit 1, a ; has boulder dust animation from previous push played yet?
ret nz
@@ -36,7 +38,7 @@ TryPushingBoulder:
jp nz, ResetBoulderPushFlags
ld a, [hJoyHeld]
ld b, a
- ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+ ld a, [wSpritePlayerStateData1FacingDirection] ; player's sprite facing direction
cp SPRITE_FACING_UP
jr z, .pushBoulderUp
cp SPRITE_FACING_LEFT
diff --git a/engine/overworld/ssanne.asm b/engine/overworld/ssanne.asm
index ea4747ce..cf3b1284 100755
--- a/engine/overworld/ssanne.asm
+++ b/engine/overworld/ssanne.asm
@@ -7,6 +7,7 @@ AnimateBoulderDust:
ld [wUpdateSpritesEnabled], a
ld a, %11100100
ld [rOBP1], a
+ call UpdateGBCPal_OBP1
call LoadSmokeTileFourTimes
callba WriteCutOrBoulderDustAnimationOAMBlock
ld c, 8 ; number of steps in animation
@@ -21,6 +22,7 @@ AnimateBoulderDust:
ld a, [rOBP1]
xor %01100100
ld [rOBP1], a
+ call UpdateGBCPal_OBP1
call Delay3
pop bc
dec c
@@ -30,7 +32,7 @@ AnimateBoulderDust:
jp LoadPlayerSpriteGraphics
GetMoveBoulderDustFunctionPointer:
- ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction
+ ld a, [wSpritePlayerStateData1FacingDirection] ; player's sprite facing direction
ld hl, MoveBoulderDustFunctionPointerTable
ld c, a
ld b, $0
diff --git a/engine/overworld/tileset_header.asm b/engine/overworld/tileset_header.asm
index 6e33974f..05061651 100644
--- a/engine/overworld/tileset_header.asm
+++ b/engine/overworld/tileset_header.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]
ld [hTilesetType], a
xor a
@@ -35,13 +26,13 @@ LoadTilesetHeader:
call IsInArray
pop de
pop hl
- jr c, .asm_c797
+ jr c, .notDungeonTileset
ld a, [wCurMapTileset]
ld b, a
ld a, [hPreviousTileset]
cp b
jr z, .done
-.asm_c797
+.notDungeonTileset
ld a, [wDestinationWarpID]
cp $ff
jr z, .done
diff --git a/engine/palettes.asm b/engine/palettes.asm
index 39991d48..ec9816ab 100755
--- a/engine/palettes.asm
+++ b/engine/palettes.asm
@@ -19,7 +19,7 @@ _RunPaletteCommand:
push de
jp hl
-SetPal_BattleBlack:
+SetPal_Black:
ld hl, PalPacket_Black
ld de, BlkPacket_Battle
ret
@@ -30,11 +30,19 @@ SetPal_Battle:
ld de, wPalPacket
ld bc, $10
call CopyData
- ld a, [wPlayerBattleStatus3]
+ ;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 a, [wEnemyBattleStatus3]
ld hl, wEnemyMonSpecies2
call DeterminePaletteID
ld c, a
@@ -110,7 +118,7 @@ SetPal_Slots:
ld de, BlkPacket_Slots
ret
-SetPal_TitleScreen:
+SetPal_Titlescreen:
ld hl, PalPacket_Titlescreen
ld de, BlkPacket_Titlescreen
ret
@@ -155,6 +163,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 +190,9 @@ SetPal_Overworld:
.Lorelei
xor a
jr .town
+.trade_center_colosseum
+ ld a, PAL_GREYMON - 1
+ jr .town
; used when a Pokemon is the only thing on the screen
; such as evolution, trading and the Hall of Fame
@@ -240,14 +255,24 @@ SetPal_TrainerCard:
ld de, wTrainerCardBlkPacket
ret
+SendUnknownPalPacket_7205d::
+ ld hl, UnknownPalPacket_72811
+ ld de, BlkPacket_WholeScreen
+ ret
+
+SendUnknownPalPacket_72064::
+ ld hl, UnknownPalPacket_72821
+ ld de, UnknownPacket_72751
+ ret
+
SetPalFunctions:
- dw SetPal_BattleBlack
+ dw SetPal_Black
dw SetPal_Battle
dw SetPal_TownMap
dw SetPal_StatusScreen
dw SetPal_Pokedex
dw SetPal_Slots
- dw SetPal_TitleScreen
+ dw SetPal_Titlescreen
dw SetPal_NidorinoIntro
dw SetPal_Generic
dw SetPal_Overworld
@@ -255,6 +280,8 @@ SetPalFunctions:
dw SetPal_PokemonWholeScreen
dw SetPal_GameFreakIntro
dw SetPal_TrainerCard
+ dw SendUnknownPalPacket_7205d
+ dw SendUnknownPalPacket_72064
; The length of the blk data of each badge on the Trainer Card.
; The Rainbow Badge has 3 entries because of its many colors.
@@ -269,9 +296,6 @@ BadgeBlkDataLengths:
db 6 ; Earth Badge
DeterminePaletteID:
- bit TRANSFORMED, a ; a is battle status 3
- ld a, PAL_GREYMON ; if the mon has used Transform, use Ditto's palette
- ret nz
ld a, [hl]
DeterminePaletteIDOutOfBattle:
ld [wd11e], a
@@ -289,6 +313,132 @@ DeterminePaletteIDOutOfBattle:
ld a, [hl]
ret
+YellowIntroPaletteAction::
+ ld a, e
+ and a
+ jr nz, .asm_720bd
+ ld hl, PalPacket_Generic
+ ld a, [hGBC]
+ and a
+ jp z, SendSGBPacket
+ jp InitGBCPalettes
+
+.asm_720bd
+ ld hl, UnknownPalPacket_72811
+ ld a, [hGBC]
+ and a
+ jp z, SendSGBPacket
+ call InitGBCPalettes
+ ld hl, PalPacket_Generic
+ inc hl
+ ld a, [hli]
+ call GetGBCBasePalAddress
+ ld a, e
+ ld [wGBCBasePalPointers + 2], a
+ ld a, d
+ ld [wGBCBasePalPointers + 2 + 1], a
+ xor a ; CONVERT_BGP
+ call DMGPalToGBCPal
+ 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, $26
+ ld [hl], a
+ ld hl, wPalPacket
+ ld a, [hGBC]
+ and a
+ jr nz, .cgb_1
+ call SendSGBPacket
+ jr .okay_1
+
+.cgb_1
+ call InitGBCPalettes
+.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
+ ld a, [hGBC]
+ and a
+ jr nz, .cgb_2
+ call SendSGBPacket
+ jr .okay_2
+
+.cgb_2
+ call InitGBCPalettes
+.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_GREYMON - 1
+ jr .town
+
+.caveOrBruno
+ ld a, PAL_CAVE - 1
+ jr .town
+
+.Lorelei
+ xor a ; PAL_PALLET - 1
+ jr .town
+
+.battleOrTradeCenter
+ ld a, PAL_GREYMON - 1
+ jr .town
+
InitPartyMenuBlkPacket:
ld hl, BlkPacket_PartyMenu
ld de, wPartyMenuBlkPacket
@@ -324,6 +474,14 @@ UpdatePartyMenuBlkPacket:
ret
SendSGBPacket:
+ ld a, 1
+ ld [hDisableJoypadPolling], a ; don't poll joypad while sending packet
+ call _SendSGBPacket
+ xor a
+ ld [hDisableJoypadPolling], a
+ ret
+
+_SendSGBPacket:
;check number of packets
ld a, [hl]
and $07
@@ -333,9 +491,6 @@ SendSGBPacket:
.loop2
; save B for later use
push bc
-; disable ReadJoypad to prevent it from interfering with sending the packet
- ld a, 1
- ld [hDisableJoypadPolling], a
; send RESET signal (P14=LOW, P15=LOW)
xor a
ld [rJOYP], a
@@ -352,18 +507,18 @@ SendSGBPacket:
ld d, a
.nextBit0
bit 0, d
-; if 0th bit is not zero set P14=HIGH,P15=LOW (send bit 1)
+; if 0th bit is not zero set P14=HIGH, P15=LOW (send bit 1)
ld a, $10
jr nz, .next0
-; else (if 0th bit is zero) set P14=LOW,P15=HIGH (send bit 0)
+; else (if 0th bit is zero) set P14=LOW, P15=HIGH (send bit 0)
ld a, $20
.next0
ld [rJOYP], a
-; must set P14=HIGH,P15=HIGH between each "pulse"
+; must set P14=HIGH, P15=HIGH between each "pulse"
ld a, $30
ld [rJOYP], a
; rotation will put next bit in 0th position (so we can always use command
-; "bit 0,d" to fetch the bit that has to be sent)
+; "bit 0, d" to fetch the bit that has to be sent)
rr d
; decrease bit counter so we know when we have sent all 8 bits of current byte
dec e
@@ -373,11 +528,9 @@ SendSGBPacket:
; send bit 1 as a "stop bit" (end of parameter data)
ld a, $20
ld [rJOYP], a
-; set P14=HIGH,P15=HIGH
+; set P14=HIGH, P15=HIGH
ld a, $30
ld [rJOYP], a
- xor a
- ld [hDisableJoypadPolling], a
; wait for about 70000 cycles
call Wait7000
; restore (previously pushed) number of packets
@@ -392,14 +545,17 @@ LoadSGB:
xor a
ld [wOnSGB], a
call CheckSGB
- ret nc
- ld a, 1
- ld [wOnSGB], a
- ld a, [wGBC]
+ jr c, .onSGB
+ ld a, [hGBC]
and a
- jr z, .notGBC
+ jr z, .onDMG
+ ld a, $1
+ ld [wOnSGB], a
+.onDMG
ret
-.notGBC
+.onSGB
+ ld a, $1
+ ld [wOnSGB], a
di
call PrepareSuperNintendoVRAMTransfer
ei
@@ -442,23 +598,19 @@ PrepareSuperNintendoVRAMTransfer:
.packetPointers
; Only the first packet is needed.
dw MaskEnFreezePacket
- dw DataSnd_72548
- dw DataSnd_72558
- dw DataSnd_72568
- dw DataSnd_72578
- dw DataSnd_72588
- dw DataSnd_72598
- dw DataSnd_725a8
- dw DataSnd_725b8
+ dw DataSnd_728a1
+ dw DataSnd_728b1
+ dw DataSnd_728c1
+ dw DataSnd_728d1
+ dw DataSnd_728e1
+ dw DataSnd_728f1
+ dw DataSnd_72901
+ dw DataSnd_72911
CheckSGB:
; Returns whether the game is running on an SGB in carry.
ld hl, MltReq2Packet
- di
call SendSGBPacket
- ld a, 1
- ld [hDisableJoypadPolling], a
- ei
call Wait7000
ld a, [rJOYP]
and $3
@@ -514,6 +666,7 @@ CopyGfxToSuperNintendoVRAM:
call DisableLCD
ld a, $e4
ld [rBGP], a
+ call _UpdateGBCPal_BGP_CheckDMG
ld de, vChars1
ld a, [wCopyingSGBTileData]
and a
@@ -544,6 +697,7 @@ CopyGfxToSuperNintendoVRAM:
call SendSGBPacket
xor a
ld [rBGP], a
+ call _UpdateGBCPal_BGP_CheckDMG
ei
ret
@@ -561,13 +715,17 @@ Wait7000:
ret
SendSGBPackets:
- ld a, [wGBC]
+ ld a, [hGBC]
and a
jr z, .notGBC
push de
call InitGBCPalettes
pop hl
- call EmptyFunc5
+ call InitGBCPalettes
+ ld a, [rLCDC]
+ and rLCDC_ENABLE_MASK
+ ret z
+ call Delay3
ret
.notGBC
push de
@@ -576,30 +734,349 @@ SendSGBPackets:
jp SendSGBPacket
InitGBCPalettes:
- ld a, $80 ; index 0 with auto-increment
- ld [rBGPI], a
- inc hl
- ld c, $20
-.loop
- ld a, [hli]
+ ld a, [hl]
+ and $f8
+ cp $20
+ jp z, TranslatePalPacketToBGMapAttributes
+
inc hl
+
+index = 0
+
+ REPT NUM_ACTIVE_PALS
+ IF index > 0
+ pop hl
+ ENDC
+
+ ld a, [hli]
+ inc hl
+
+ IF index < (NUM_ACTIVE_PALS + -1)
+ push hl
+ ENDC
+
+ call GetGBCBasePalAddress
+ ld a, e
+ ld [wGBCBasePalPointers + index * 2], a
+ ld a, d
+ ld [wGBCBasePalPointers + index * 2 + 1], a
+
+ xor a ; CONVERT_BGP
+ call DMGPalToGBCPal
+ ld a, index
+ call TransferCurBGPData
+
+ ld a, CONVERT_OBP0
+ call DMGPalToGBCPal
+ ld a, index
+ call TransferCurOBPData
+
+ ld a, CONVERT_OBP1
+ call DMGPalToGBCPal
+ ld a, index + 4
+ call TransferCurOBPData
+
+index = index + 1
+ ENDR
+
+ ret
+
+GetGBCBasePalAddress::
+; 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, GBCBasePalettes
+ add hl, de
+ ld a, l
+ ld e, a
+ ld a, h
+ ld d, a
+ pop hl
+ ret
+
+DMGPalToGBCPal::
+; Populate wGBCPal with colors from a base palette, selected using one of the
+; DMG palette registers.
+; Input:
+; a = which DMG palette register
+; de = address of GBC base palette
+ and a
+ jr nz, .notBGP
+ ld a, [rBGP]
+ ld [wLastBGP], a
+ jr .convert
+.notBGP
+ dec a
+ jr nz, .notOBP0
+ ld a, [rOBP0]
+ ld [wLastOBP0], a
+ jr .convert
+.notOBP0
+ ld a, [rOBP1]
+ ld [wLastOBP1], a
+.convert
+color_index = 0
+ REPT NUM_COLORS
+ ld b, a
+ and %11
+ call .GetColorAddress
+ ld a, [hli]
+ ld [wGBCPal + color_index * 2], a
+ ld a, [hl]
+ ld [wGBCPal + color_index * 2 + 1], a
+
+ IF color_index < (NUM_COLORS + -1)
+ ld a, b
+ rrca
+ rrca
+ ENDC
+
+color_index = color_index + 1
+ 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
+ ld [rBGPI], a
+ ld de, rBGPD
+ ld hl, wGBCPal
+ ld b, %10 ; mask for non-V-blank/non-H-blank STAT mode
+ ld a, [rLCDC]
+ and rLCDC_ENABLE_MASK
+ jr nz, .lcdEnabled
+ rept NUM_COLORS
+ call TransferPalColorLCDDisabled
+ endr
+ jr .done
+.lcdEnabled
+ rept NUM_COLORS
+ call TransferPalColorLCDEnabled
+ endr
+.done
+ pop de
+ ret
+
+BufferBGPPal::
+; Copy wGBCPal 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, wGBCPal
+ ld c, PAL_SIZE
+.loop
ld a, [de]
- ld [rBGPD], a
+ ld [hli], a
+ inc de
+ dec c
+ jr nz, .loop
+ pop de
+ ret
+
+TransferBGPPals::
+; Transfer the buffered BG palettes.
+ ld a, [rLCDC]
+ and rLCDC_ENABLE_MASK
+ jr z, .lcdDisabled
+ di
+.waitLoop
+ ld a, [rLY]
+ cp 144
+ jr c, .waitLoop
+.lcdDisabled
+ call .DoTransfer
+ ei
+ ret
+
+.DoTransfer:
+ xor a
+ or $80 ; auto-increment
+ ld [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
-EmptyFunc5:
+TransferCurOBPData:
+ push de
+ add a
+ add a
+ add a
+ or $80 ; auto-increment
+ ld [rOBPI], a
+ ld de, rOBPD
+ ld hl, wGBCPal
+ ld b, %10 ; mask for non-V-blank/non-H-blank STAT mode
+ ld a, [rLCDC]
+ and rLCDC_ENABLE_MASK
+ jr nz, .lcdEnabled
+ rept NUM_COLORS
+ call TransferPalColorLCDDisabled
+ endr
+ jr .done
+.lcdEnabled
+ rept NUM_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.
+ ld a, [rSTAT]
+ and b
+ jr z, TransferPalColorLCDEnabled
+
+; Wait for H-blank or V-blank to begin.
+.notInBlankingPeriod
+ ld 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
+
+_UpdateGBCPal_BGP_CheckDMG::
+ ld a, [hGBC]
+ and a
+ ret z
+; fall through
+
+_UpdateGBCPal_BGP::
+index = 0
+
+ REPT NUM_ACTIVE_PALS
+ ld a, [wGBCBasePalPointers + index * 2]
+ ld e, a
+ ld a, [wGBCBasePalPointers + index * 2 + 1]
+ ld d, a
+ xor a ; CONVERT_BGP
+ call DMGPalToGBCPal
+ ld a, index
+ call BufferBGPPal
+
+index = index + 1
+ ENDR
+
+ call TransferBGPPals
+ ret
+
+_UpdateGBCPal_OBP::
+index = 0
+
+ REPT NUM_ACTIVE_PALS
+ ld a, [wGBCBasePalPointers + index * 2]
+ ld e, a
+ ld a, [wGBCBasePalPointers + index * 2 + 1]
+ ld d, a
+ ld a, c
+ call DMGPalToGBCPal
+ ld a, c
+ dec a
+ rlca
+ rlca
+
+ IF index > 0
+ IF index == 1
+ inc a
+ ELSE
+ add index
+ ENDC
+ ENDC
+
+ call TransferCurOBPData
+
+index = index + 1
+ ENDR
+
ret
+TranslatePalPacketToBGMapAttributes::
+; translate the SGB pal packets into something usable for the GBC
+ 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
+ callba 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
@@ -607,9 +1084,7 @@ CopySGBBorderTiles:
; This function converts 2BPP planar data into this format by mapping
; 2BPP colors 0-3 to 4BPP colors 0-3. 4BPP colors 4-15 are not used.
ld b, 128
-
.tileLoop
-
; Copy bit planes 1 and 2 of the tile data.
ld c, 16
.copyLoop
diff --git a/engine/pathfinding.asm b/engine/pathfinding.asm
index ba052d38..f3d23b7c 100644
--- a/engine/pathfinding.asm
+++ b/engine/pathfinding.asm
@@ -14,22 +14,22 @@ FindPathToPlayer:
call CalcDifference
ld d, a
and a
- jr nz, .asm_f8da
+ jr nz, .asm_f76a
ld a, [hFindPathFlags]
set 0, a ; current end of path matches the player's Y coordinate
ld [hFindPathFlags], a
-.asm_f8da
+.asm_f76a
ld a, [hFindPathXProgress]
ld b, a
ld a, [hNPCPlayerXDistance] ; X distance in steps
call CalcDifference
ld e, a
and a
- jr nz, .asm_f8ec
+ jr nz, .asm_f77c
ld a, [hFindPathFlags]
set 1, a ; current end of path matches the player's X coordinate
ld [hFindPathFlags], a
-.asm_f8ec
+.asm_f77c
ld a, [hFindPathFlags]
cp $3 ; has the end of the path reached the player's position?
jr z, .done
diff --git a/engine/pikachu_emotions.asm b/engine/pikachu_emotions.asm
new file mode 100755
index 00000000..1518b28e
--- /dev/null
+++ b/engine/pikachu_emotions.asm
@@ -0,0 +1,421 @@
+IsPlayerTalkingToPikachu:
+ ld a, [wd436]
+ and a
+ ret z
+ ld a, [hSpriteIndexOrTextID]
+ cp $f
+ ret nz
+ call InitializePikachuTextID
+ xor a
+ ld [hSpriteIndexOrTextID], a
+ ld [wd436], a
+ ret
+
+InitializePikachuTextID:
+ ld a, $d4 ; display
+ ld [hSpriteIndexOrTextID], 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
+ callab 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, $f ; Pikachu
+ 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:
+ ret
+
+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
+ ret
+
+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
+
+PikachuEmotionTable:
+pikaemotion_def: MACRO
+\1_id: dw \1
+ endm
+
+ 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
+ callab 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
+ callab CheckPikachuFaintedOrStatused ; 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, [wd49c]
+ 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 PIKACHU
+ jr nz, .curMonNotStarterPikachu
+ callab IsThisPartymonStarterPikachu
+ jr nc, .curMonNotStarterPikachu
+ ld a, [wWhichPokemon]
+ ld hl, wPartyMon1Status
+ ld bc, wPartyMon2 - wPartyMon1
+ call AddNTimes
+ ld a, [hl]
+ and SLP
+ 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_emotions.asm"
+
+PikachuWalksToNurseJoy:
+ ld a, $40
+ ld [h_0xFFFC], a
+ call LoadPikachuSpriteIntoVRAM
+ call .GetMovementData
+ and a
+ jr z, .skip
+ call ApplyPikachuMovementData
+.skip
+ xor a
+ ld [h_0xFFFC], 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_follow.asm b/engine/pikachu_follow.asm
new file mode 100755
index 00000000..d9dc91df
--- /dev/null
+++ b/engine/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 IsStarterPikachuInOurParty
+ 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, wd472
+ 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 0, 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
+ callab 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
+ callab 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
+ ld 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 [wd432], a
+ ld [wd433], a
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $11
+asm_fc87f:
+ ld a, [wd432]
+ ld e, a
+ ld a, [wd433]
+ 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 Pointer_fc8d6 % $100
+ ld l, a
+ ld a, Pointer_fc8d6 / $100
+ adc $0
+ ld h, a
+ ld a, [hli]
+ ld [wd432], a
+ add e
+ ld e, a
+ ld a, [hl]
+ ld [wd433], 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, [wd736]
+ bit 6, 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, [wd736]
+ bit 7, a
+ jr nz, .copy_player
+ ld hl, wSpritePikachuStateData1FacingDirection - wSpritePikachuStateData1
+ add hl, bc
+ ld a, [hl]
+ or d
+ ld d, a
+ ld a, [wFontLoaded]
+ bit 0, 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, [wd736]
+ bit 6, 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, [wd472]
+ 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 3, a
+ jr nz, .asm_fcc58
+ bit 2, a
+ jr nz, .asm_fcc5b
+ bit 1, a
+ jr nz, .asm_fcc5e
+ bit 0, 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 3, a
+ jr nz, .asm_fcc86
+ bit 2, a
+ jr nz, .asm_fcc89
+ bit 1, a
+ jr nz, .asm_fcc8c
+ bit 0, 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]
+ ldd [hl], 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, wSpriteStateData2 / $100
+ ld a, [H_CURRENTSPRITEOFFSET] ; 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, wSpriteStateData1 / $100
+ ld a, [H_CURRENTSPRITEOFFSET]
+ add wSpritePikachuStateData1ImageIndex - wSpritePikachuStateData1
+ ld l, a
+ ld [hl], $ff
+ scf
+ jr .return
+
+.on_screen
+ ld h, wSpriteStateData2 / $100
+ ld a, [H_CURRENTSPRITEOFFSET]
+ 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, wSpriteStateData1 / $100
+ ld a, [H_CURRENTSPRITEOFFSET]
+ 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_movement.asm b/engine/pikachu_movement.asm
new file mode 100755
index 00000000..938715a4
--- /dev/null
+++ b/engine/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, wd736
+ res 6, [hl]
+ ret z
+ set 6, [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, wOAMBuffer + 4 * 36
+ 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, 1 << OAM_X_FLIP
+
+.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/ledge_hopping_shadow.1bpp"
+LedgeHoppingShadowGFX_3FEnd:
+
+LoadPikachuBallIconIntoVRAM:
+ ld hl, vNPCSprites2 + $7e * $10
+ ld de, GFX_fd86b
+ lb bc, BANK(GFX_fd86b), 1
+ jp CopyVideoDataDoubleAlternate
+
+Func_fd851:
+ ld hl, vNPCSprites + $c * $10
+ ld a, 3
+.loop
+ push af
+ push hl
+ ld de, GFX_fd86b
+ lb bc, BANK(GFX_fd86b), 4
+ call CopyVideoDataAlternate
+ pop hl
+ ld de, 4 * $10
+ add hl, de
+ pop af
+ dec a
+ jr nz, .loop
+ ret
+
+GFX_fd86b:
+INCBIN "gfx/unknown_fd86b.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
+ ld a, [h_0xFFFC]
+ 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_wave $100
diff --git a/engine/pikachu_pcm.asm b/engine/pikachu_pcm.asm
new file mode 100755
index 00000000..1e6f8dc2
--- /dev/null
+++ b/engine/pikachu_pcm.asm
@@ -0,0 +1,154 @@
+PlayPikachuSoundClip::
+ 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
+ ld [rNR52], a
+ ld a, $77
+ ld [rNR50], a
+ xor a
+ ld [rNR30], a
+ ld hl, $ff30 ; wave data
+ 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
+ ld a, $80
+ ld [rNR30], a
+ ld a, [rNR51]
+ or $44
+ ld [rNR51], a
+ ld a, $ff
+ ld [rNR31], a
+ ld a, $20
+ ld [rNR32], a
+ ld a, $ff
+ ld [rNR33], a
+ ld a, $87
+ ld [rNR34], a
+ pop hl
+ pop bc
+ call PlayPikachuPCM
+ xor a
+ ld [wc0f3], a
+ ld [wc0f4], a
+ ld a, $80
+ ld [rNR52], a
+ xor a
+ ld [rNR30], a
+ ld hl, $ff30
+ 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
+ ld [rNR30], a
+ ld a, [rNR51]
+ and $bb
+ ld [rNR51], a
+ xor a
+ ld [wChannelSoundIDs + Ch5], a
+ ld [wChannelSoundIDs + Ch6], a
+ ld [wChannelSoundIDs + Ch7], a
+ ld [wChannelSoundIDs + Ch8], a
+ ld a, [H_LOADEDROMBANK]
+ ei
+ ret
+
+PikachuCriesPointerTable:
+; format:
+; db bank
+; dw pointer to cry
+
+; 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
diff --git a/engine/pikachu_pic_animation.asm b/engine/pikachu_pic_animation.asm
new file mode 100755
index 00000000..c79d9add
--- /dev/null
+++ b/engine/pikachu_pic_animation.asm
@@ -0,0 +1,851 @@
+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:
+ ld a, [H_AUTOBGTRANSFERENABLED]
+ push af
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld a, [de]
+ ld [wPikaPicAnimNumber], a
+ inc de
+ push de
+ call .RunPikapic
+ pop de
+ pop af
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ret
+
+.RunPikapic:
+ call PlacePikapicTextBoxBorder
+ callab 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
+ ld [H_AUTOBGTRANSFERENABLED], a
+ coord hl, 6, 5
+ lb bc, 5, 5
+ call TextBoxBorder
+ call Delay3
+ call UpdateSprites
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], 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
+
+PikaPicAnimPointers:
+pikapic_def: macro
+\1_id: dw \1
+endm
+
+ 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
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call RunPikaPicAnimSetupScript
+ call DummyFunction_fdad5
+ call AnimateCurrentPikaPicAnimFrame
+ call DummyFunction_fdad5
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call PikaPicAnimTimerAndJoypad
+ and a
+ jr z, .loop
+ ret
+
+PikaPicAnimTimerAndJoypad:
+ call Delay3
+ call CheckPikaPicAnimTimer
+ and a
+ ret nz
+ call JoypadLowSensitivity
+ ld a, [hJoyPressed]
+ and A_BUTTON | B_BUTTON
+ 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_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
+ coord hl, 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_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
+ ld a, [H_AUTOBGTRANSFERENABLED]
+ push af
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld a, [hTilesetType]
+ push af
+ xor a
+ ld [hTilesetType], a
+ call GetPikaPicAnimByte
+ ld [wPikaPicAnimCurGraphicID], a
+ ld a, [wPikaPicAnimCurGraphicID]
+ call LoadPikaPicAnimGFXHeader
+ ld a, c
+ cp a, $ff
+ jr z, .compressed
+ call RequestPikaPicAnimGFX
+ jr .done
+
+.compressed
+ call DecompressRequestPikaPicAnimGFX
+.done
+ pop af
+ ld [hTilesetType], a
+ pop af
+ ld [H_AUTOBGTRANSFERENABLED], 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(sSpriteBuffer1)
+ call SwitchSRAMBankAndLatchClockData
+ ld hl, sSpriteBuffer1
+ ld de, sSpriteBuffer0
+ ld bc, SPRITEBUFFERSIZE * 2
+ call CopyData
+ call PrepareRTCDataAndDisableSRAM
+ 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
+ callab 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
+ ld [rBGP], a
+ call UpdateGBCPal_BGP
+ call DelayFrames
+ ret
+
+INCLUDE "data/pikachu_pic_animation.asm"
diff --git a/engine/pikachu_status.asm b/engine/pikachu_status.asm
new file mode 100755
index 00000000..c73d3b3f
--- /dev/null
+++ b/engine/pikachu_status.asm
@@ -0,0 +1,258 @@
+IsStarterPikachuInOurParty::
+ 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 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, $6 ; possible player length - 1
+.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, -NAME_LENGTH
+ add hl, bc
+ ld a, [hli]
+ or [hl]
+ jr z, .noPlayerPikachu ; XXX how is this determined?
+ pop hl
+ scf
+ ret
+
+.noPlayerPikachu
+ pop hl
+ and a
+ ret
+
+IsThisPartymonStarterPikachu_Box::
+ ld hl, wBoxMon1
+ ld bc, wBoxMon2 - wBoxMon1
+ ld de, wBoxMonOT
+ jr asm_fce21
+
+IsThisPartymonStarterPikachu_Party::
+IsThisPartymonStarterPikachu::
+ ld hl, wPartyMon1
+ ld bc, wPartyMon2 - wPartyMon1
+ ld de, wPartyMonOT
+asm_fce21:
+ ld a, [wWhichPokemon]
+ call AddNTimes
+ ld a, [hl]
+ cp 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, $6
+.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 IsStarterPikachuInOurParty
+ 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
+
+CheckPikachuFaintedOrStatused::
+; function to test if Pikachu is alive?
+ xor a
+ ld [wWhichPokemon], a
+ ld hl, wPartyCount
+.loop
+ inc hl
+ ld a, [hl]
+ cp $ff
+ jr z, .dead_or_not_in_party
+ push hl
+ call IsThisPartymonStarterPikachu_Party
+ 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, .alive
+ jr .dead_or_not_in_party
+
+.next
+ ld a, [wWhichPokemon]
+ inc a
+ ld [wWhichPokemon], a
+ jr .loop
+
+.alive
+ scf
+ ret
+
+.dead_or_not_in_party
+ and a
+ ret
+
+IsSurfingPikachuInThePlayersParty::
+ 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 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, $6
+.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/play_time.asm b/engine/play_time.asm
deleted file mode 100755
index a5202cc6..00000000
--- a/engine/play_time.asm
+++ /dev/null
@@ -1,61 +0,0 @@
-TrackPlayTime:
- call CountDownIgnoreInputBitReset
- ld a, [wd732]
- bit 0, 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, .asm_18e40
- ld a, $ff
- jr .asm_18e41
-.asm_18e40
- dec a
-.asm_18e41
- ld [wIgnoreInputCounter], a
- and a
- ret nz
- ld a, [wd730]
- res 1, a
- res 2, a
- bit 5, a
- res 5, a
- ld [wd730], a
- ret z
- xor a
- ld [hJoyPressed], a
- ld [hJoyHeld], a
- ret
diff --git a/engine/pokedex_rating.asm b/engine/pokedex_rating.asm
index f1aaf618..4dfb6b39 100755
--- a/engine/pokedex_rating.asm
+++ b/engine/pokedex_rating.asm
@@ -26,7 +26,7 @@ DisplayDexRating:
CheckAndResetEventA EVENT_HALL_OF_FAME_DEX_RATING
jr nz, .hallOfFame
push hl
- ld hl, PokedexRatingText_441cc
+ ld hl, DexCompletionText
call PrintText
pop hl
call PrintText
@@ -51,104 +51,104 @@ DisplayDexRating:
ld [de], a
ret
-PokedexRatingText_441cc:
- TX_FAR _OaksLabText_441cc
+DexCompletionText:
+ TX_FAR _DexCompletionText
db "@"
DexRatingsTable:
db 10
- dw PokedexRatingText_44201
+ dw DexRatingText_Own0To9
db 20
- dw PokedexRatingText_44206
+ dw DexRatingText_Own10To19
db 30
- dw PokedexRatingText_4420b
+ dw DexRatingText_Own20To29
db 40
- dw PokedexRatingText_44210
+ dw DexRatingText_Own30To39
db 50
- dw PokedexRatingText_44215
+ dw DexRatingText_Own40To49
db 60
- dw PokedexRatingText_4421a
+ dw DexRatingText_Own50To59
db 70
- dw PokedexRatingText_4421f
+ dw DexRatingText_Own60To69
db 80
- dw PokedexRatingText_44224
+ dw DexRatingText_Own70To79
db 90
- dw PokedexRatingText_44229
+ dw DexRatingText_Own80To89
db 100
- dw PokedexRatingText_4422e
+ dw DexRatingText_Own90To99
db 110
- dw PokedexRatingText_44233
+ dw DexRatingText_Own100To109
db 120
- dw PokedexRatingText_44238
+ dw DexRatingText_Own110To119
db 130
- dw PokedexRatingText_4423d
+ dw DexRatingText_Own120To129
db 140
- dw PokedexRatingText_44242
+ dw DexRatingText_Own130To139
db 150
- dw PokedexRatingText_44247
+ dw DexRatingText_Own140To149
db NUM_POKEMON + 1
- dw PokedexRatingText_4424c
+ dw DexRatingText_Own150To151
-PokedexRatingText_44201:
- TX_FAR _OaksLabText_44201
+DexRatingText_Own0To9:
+ TX_FAR _DexRatingText_Own0To9
db "@"
-PokedexRatingText_44206:
- TX_FAR _OaksLabText_44206
+DexRatingText_Own10To19:
+ TX_FAR _DexRatingText_Own10To19
db "@"
-PokedexRatingText_4420b:
- TX_FAR _OaksLabText_4420b
+DexRatingText_Own20To29:
+ TX_FAR _DexRatingText_Own20To29
db "@"
-PokedexRatingText_44210:
- TX_FAR _OaksLabText_44210
+DexRatingText_Own30To39:
+ TX_FAR _DexRatingText_Own30To39
db "@"
-PokedexRatingText_44215:
- TX_FAR _OaksLabText_44215
+DexRatingText_Own40To49:
+ TX_FAR _DexRatingText_Own40To49
db "@"
-PokedexRatingText_4421a:
- TX_FAR _OaksLabText_4421a
+DexRatingText_Own50To59:
+ TX_FAR _DexRatingText_Own50To59
db "@"
-PokedexRatingText_4421f:
- TX_FAR _OaksLabText_4421f
+DexRatingText_Own60To69:
+ TX_FAR _DexRatingText_Own60To69
db "@"
-PokedexRatingText_44224:
- TX_FAR _OaksLabText_44224
+DexRatingText_Own70To79:
+ TX_FAR _DexRatingText_Own70To79
db "@"
-PokedexRatingText_44229:
- TX_FAR _OaksLabText_44229
+DexRatingText_Own80To89:
+ TX_FAR _DexRatingText_Own80To89
db "@"
-PokedexRatingText_4422e:
- TX_FAR _OaksLabText_4422e
+DexRatingText_Own90To99:
+ TX_FAR _DexRatingText_Own90To99
db "@"
-PokedexRatingText_44233:
- TX_FAR _OaksLabText_44233
+DexRatingText_Own100To109:
+ TX_FAR _DexRatingText_Own100To109
db "@"
-PokedexRatingText_44238:
- TX_FAR _OaksLabText_44238
+DexRatingText_Own110To119:
+ TX_FAR _DexRatingText_Own110To119
db "@"
-PokedexRatingText_4423d:
- TX_FAR _OaksLabText_4423d
+DexRatingText_Own120To129:
+ TX_FAR _DexRatingText_Own120To129
db "@"
-PokedexRatingText_44242:
- TX_FAR _OaksLabText_44242
+DexRatingText_Own130To139:
+ TX_FAR _DexRatingText_Own130To139
db "@"
-PokedexRatingText_44247:
- TX_FAR _OaksLabText_44247
+DexRatingText_Own140To149:
+ TX_FAR _DexRatingText_Own140To149
db "@"
-PokedexRatingText_4424c:
- TX_FAR _OaksLabText_4424c
+DexRatingText_Own150To151:
+ TX_FAR _DexRatingText_Own150To151
db "@"
diff --git a/engine/predefs.asm b/engine/predefs.asm
index 6f605043..cc6af5ac 100755
--- a/engine/predefs.asm
+++ b/engine/predefs.asm
@@ -1,8 +1,8 @@
GetPredefPointer:
-; Store the contents of the register
-; pairs (hl, de, bc) at wPredefRegisters.
-; Then put the bank and address of predef
-; wPredefID in [wPredefBank] and hl.
+ ; Store the contents of the register
+ ; pairs (hl, de, bc) at wPredefRegisters.
+ ; Then put the bank and address of predef
+ ; wPredefID in [wPredefBank] and hl.
ld a, h
ld [wPredefRegisters], a
@@ -50,15 +50,16 @@ GetPredefPointer:
ret
PredefPointers::
-; these are pointers to ASM routines.
-; they appear to be used in overworld map scripts.
+ ; these are pointers to ASM routines.
+ ; they appear to be used in overworld map scripts.
+ const_def
add_predef DrawPlayerHUDAndHPBar
add_predef CopyUncompressedPicToTilemap
add_predef AnimateSendingOutMon
add_predef ScaleSpriteByTwo
add_predef LoadMonBackPic
add_predef CopyDownscaledMonTiles
- dbw $03,JumpMoveEffect ; wrong bank
+ add_predef Func_f0a7
add_predef HealParty
add_predef MoveAnimation
add_predef DivideBCDPredef
@@ -81,8 +82,12 @@ PredefPointers::
add_predef LearnMoveFromLevelUp
add_predef LearnMove
add_predef GetQuantityOfItemInBag
- dbw $03,CheckForHiddenObjectOrBookshelfOrCardKeyDoor ; home bank
- dbw $03,GiveItem ; home bank
+
+ predef_const CheckForHiddenObjectOrBookshelfOrCardKeyDoor
+ predef_const GiveItem
+ dbw $03, CheckForHiddenObjectOrBookshelfOrCardKeyDoor ; home bank
+ dbw $03, GiveItem ; home bank
+
add_predef ChangeBGPalColor0_4Frames
add_predef FindPathToPlayer
add_predef PredefShakeScreenVertically
@@ -129,7 +134,7 @@ PredefPointers::
add_predef LoadTownMap_Nest
add_predef PrintMonType
add_predef EmotionBubble
- add_predef EmptyFunc3; return immediately
+ add_predef EmptyFunc3 ; return immediately
add_predef AskName
add_predef PewterGuys
add_predef SaveSAVtoSRAM2
@@ -139,6 +144,9 @@ PredefPointers::
add_predef DoInGameTradeDialogue
add_predef HallOfFamePC
add_predef DisplayDexRating
+
+ predef_const _LeaveMapAnim
+ predef_const EnterMapAnim
dbw $1E, _LeaveMapAnim ; wrong bank
dbw $1E, EnterMapAnim ; wrong bank
add_predef GetTileTwoStepsInFrontOfPlayer
diff --git a/engine/predefs7.asm b/engine/predefs7.asm
index 752bdd1a..bfa0ab57 100755
--- a/engine/predefs7.asm
+++ b/engine/predefs7.asm
@@ -1,6 +1,12 @@
DisplayElevatorFloorMenu:
+ ld hl, wd730
+ ld a, [hl]
+ push af
+ set 6, [hl]
ld hl, WhichFloorText
call PrintText
+ pop af
+ ld [wd730], a
ld hl, wItemList
ld a, l
ld [wListPointer], a
diff --git a/engine/predefs12.asm b/engine/predefsA.asm
index 95f0ea25..e25735c5 100755..100644
--- a/engine/predefs12.asm
+++ b/engine/predefsA.asm
@@ -1,14 +1,16 @@
-; b = new colour for BG colour 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
ld a, [rBGP]
- or b
+ xor $ff
ld [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 4
call DelayFrames
ld a, [rBGP]
- and %11111100
+ xor $ff
ld [rBGP], a
+ call UpdateGBCPal_BGP
ret
PredefShakeScreenVertically:
diff --git a/engine/print_waiting_text.asm b/engine/print_waiting_text.asm
index 7a95da2a..bd2180a1 100644
--- a/engine/print_waiting_text.asm
+++ b/engine/print_waiting_text.asm
@@ -1,15 +1,14 @@
PrintWaitingText:
coord hl, 3, 10
- ld b, $1
- ld c, $b
+ lb bc, 1, 11
ld a, [wIsInBattle]
and a
- jr z, .asm_4c17
+ jr z, .asm_4b9a
call TextBoxBorder
- jr .asm_4c1a
-.asm_4c17
+ jr .asm_4b9d
+.asm_4b9a
call CableClub_TextBoxBorder
-.asm_4c1a
+.asm_4b9d
coord hl, 4, 11
ld de, WaitingText
call PlaceString
diff --git a/engine/printer.asm b/engine/printer.asm
new file mode 100644
index 00000000..5be5286c
--- /dev/null
+++ b/engine/printer.asm
@@ -0,0 +1,999 @@
+ 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
+
+INCLUDE "engine/printer/serial.asm"
+
+PrintPokedexEntry:
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ xor a
+ ld [wUpdateSpritesEnabled], a
+ ld [hCanceledPrinting], a
+ call Printer_PlayPrinterMusic
+ ld a, [rIE]
+ push af
+ xor a
+ ld [rIF], a
+ ld a, $9
+ ld [rIE], a
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], 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
+ callab Pokedex_DrawInterface
+ callab Pokedex_PlacePokemonList
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], 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
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Printer_PrepareDexEntryForPrinting
+ ld a, $7
+ call Printer_StartTransmission
+ ld a, $3
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call .TryPrintPage
+.finish_printing
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ xor a
+ ld [rIF], a
+ pop af
+ ld [rIE], a
+ call ReloadMapAfterPrinter
+ call Printer_PlayMapMusic
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ ret
+
+.TryPrintPage:
+ call Printer_ResetJoypadHRAM
+.print_loop
+ call JoypadLowSensitivity
+ call Printer_CheckPressingB
+ 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:
+ callab 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
+ callab Pokedex_PrepareDexEntryForPrinting
+ ret
+
+PrintSurfingMinigameHighScore:
+ xor a
+ ld [hCanceledPrinting], a
+ call Printer_PlayPrinterMusic
+ call Printer_PrepareSurfingMinigameHighScoreTileMap
+ ld a, [rIE]
+ push af
+ xor a
+ ld [rIF], a
+ ld a, $9
+ ld [rIE], a
+ call StartTransmission_Send9Rows
+ ld a, $13
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call Printer_ResetJoypadHRAM
+.loop
+ call JoypadLowSensitivity
+ call Printer_CheckPressingB
+ 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
+ ld [rIF], a
+ pop af
+ ld [rIE], a
+ call ReloadMapAfterPrinter
+ call Printer_PlayMapMusic
+ ret
+
+PrintDiploma:
+ xor a
+ ld [hCanceledPrinting], a
+ call Printer_PlayPrinterMusic
+ call _DisplayDiploma
+ ld a, [rIE]
+ push af
+ xor a
+ ld [rIF], a
+ ld a, $9
+ ld [rIE], a
+ call StartTransmission_Send9Rows
+ ld a, $10
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call Func_e8d11
+ jr c, .asm_e8cfa
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ ld c, $c
+ call DelayFrames
+ call SaveScreenTilesToBuffer1
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Func_e9ad3
+ call StartTransmission_Send9Rows
+ ld a, $3
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ call Func_e8d11
+.asm_e8cfa
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ call Printer_CopyTileMapFromPrinterTileBuffer
+ xor a
+ ld [rIF], a
+ pop af
+ ld [rIE], a
+ call ReloadMapAfterPrinter
+ call Printer_PlayMapMusic
+ ret
+
+Func_e8d11:
+ call Printer_ResetJoypadHRAM
+.asm_e8d14
+ call JoypadLowSensitivity
+ call Printer_CheckPressingB
+ jr c, .asm_e8d33
+ ld a, [wPrinterSendState]
+ bit 7, a
+ jr nz, .asm_e8d31
+ call PrinterTransmissionJumptable
+ call GBPrinter_CheckForErrors
+ call GBPrinter_UpdateStatusMessage
+ call DelayFrame
+ jr .asm_e8d14
+
+.asm_e8d31
+ and a
+ ret
+
+.asm_e8d33
+ scf
+ ret
+
+PrintPCBox::
+ ld a, [wBoxDataStart]
+ and a
+ jp z, Func_e8df4
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ xor a
+ ld [wUpdateSpritesEnabled], a
+ ld [hCanceledPrinting], a
+ call Printer_PlayPrinterMusic
+ ld a, [rIE]
+ push af
+ xor a
+ ld [rIF], a
+ ld a, $9
+ ld [rIE], a
+ call SaveScreenTilesToBuffer1
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call PrintPCBox_DrawPage1
+ call StartTransmission_Send9Rows
+ ld a, $10
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ call Func_e8dfb
+ jr c, .asm_e8ddc
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ ld c, 12
+ call DelayFrames
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call PrintPCBox_DrawPage2
+ call StartTransmission_Send9Rows
+ ld a, $0
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ call Func_e8dfb
+ jr c, .asm_e8ddc
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ ld c, 12
+ call DelayFrames
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call PrintPCBox_DrawPage3
+ call StartTransmission_Send9Rows
+ ld a, $0
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ call Func_e8dfb
+ jr c, .asm_e8ddc
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ ld c, 12
+ call DelayFrames
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call PrintPCBox_DrawPage4
+ call StartTransmission_Send9Rows
+ ld a, $3
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ call Func_e8dfb
+.asm_e8ddc
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ xor a
+ ld [rIF], a
+ pop af
+ ld [rIE], a
+ call ReloadMapAfterPrinter
+ call Printer_PlayMapMusic
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ ret
+
+Func_e8df4:
+ ld hl, String_e8e1f
+ call PrintText
+ ret
+
+Func_e8dfb:
+ call Printer_ResetJoypadHRAM
+.asm_e8dfe
+ call JoypadLowSensitivity
+ call Printer_CheckPressingB
+ jr c, .asm_e8e1d
+ ld a, [wPrinterSendState]
+ bit 7, a
+ jr nz, .asm_e8e1b
+ call PrinterTransmissionJumptable
+ call GBPrinter_CheckForErrors
+ call GBPrinter_UpdateStatusMessage
+ call DelayFrame
+ jr .asm_e8dfe
+
+.asm_e8e1b
+ and a
+ ret
+
+.asm_e8e1d
+ scf
+ ret
+
+String_e8e1f:
+ TX_FAR _NoPokemonText
+ db "@"
+
+PrintFanClubPortrait:
+ xor a
+ ld [hCanceledPrinting], a
+ call Printer_PlayPrinterMusic
+ call Printer_GetMonStats
+ ld a, [rIE]
+ push af
+ xor a
+ ld [rIF], a
+ ld a, $9
+ ld [rIE], a
+ call StartTransmission_Send9Rows
+ ld a, $13
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call Printer_ResetJoypadHRAM
+.asm_e8e45
+ call JoypadLowSensitivity
+ call Printer_CheckPressingB
+ jr c, .asm_e8e62
+ ld a, [wPrinterSendState]
+ bit 7, a
+ jr nz, .asm_e8e62
+ call PrinterTransmissionJumptable
+ call GBPrinter_CheckForErrors
+ call GBPrinter_UpdateStatusMessage
+ call DelayFrame
+ jr .asm_e8e45
+
+.asm_e8e62
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ call Printer_CopyTileMapFromPrinterTileBuffer
+ xor a
+ ld [rIF], a
+ pop af
+ ld [rIE], a
+ call ReloadMapAfterPrinter
+ call Printer_PlayMapMusic
+ ret
+
+PrinterDebug:
+ push af
+ push bc
+ push de
+ push hl
+ call StopAllMusic
+ ld a, [rIE]
+ push af
+ xor a
+ ld [rIF], a
+ ld a, $9
+ ld [rIE], a
+ call StartTransmission_Send9Rows
+ ld a, $13
+ ld [wcae2], a
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], 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, wOAMBuffer + 32 * 4
+ ld bc, 8 * 4
+ xor a
+ call FillMemory
+ xor a
+ ld [rIF], a
+ pop af
+ ld [rIE], a
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ret
+
+Printer_CheckPressingB:
+ ld a, [hJoyHeld]
+ and B_BUTTON
+ 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
+ ld [rSB], a
+ ld a, $1
+ ld [rSC], a
+ ld a, $81
+ ld [rSC], a
+.wait_send_cancel
+ ld a, [wPrinterOpcode]
+ and a
+ jr nz, .wait_send_cancel
+.already_done
+ ld a, $1
+ ld [hCanceledPrinting], a
+ scf
+ ret
+
+Printer_CopyTileMapToPrinterTileBuffer:
+ coord hl, 0, 0
+ coord de, 0, 0, wPrinterTileBuffer
+ ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
+ call CopyData
+ ret
+
+Printer_CopyTileMapFromPrinterTileBuffer:
+ coord hl, 0, 0, wPrinterTileBuffer
+ coord de, 0, 0
+ ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
+ call CopyData
+ ret
+
+Printer_ResetJoypadHRAM:
+ xor a
+ ld [hJoyLast], a
+ ld [hJoyReleased], a
+ ld [hJoyPressed], a
+ ld [hJoyHeld], a
+ ld [hJoy5], a
+ ld [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
+ ld [H_AUTOBGTRANSFERENABLED], a
+ coord hl, 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]
+ coord hl, 1, 7
+ call PlaceString
+ coord hl, 2, 15
+ ld de, .PressBToCancel
+ call PlaceString
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], 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
+ coord hl, 0, 0
+ call .PlaceRowAlternatingTiles
+ coord hl, 0, 17
+ call .PlaceRowAlternatingTiles
+ coord hl, 0, 0
+ call .PlaceColumnAlternatingTiles
+ coord hl, 19, 0
+ call .PlaceColumnAlternatingTiles
+ ld a, $4
+ coord hl, 0, 0
+ ld [hl], a
+ coord hl, 0, 17
+ ld [hl], a
+ coord hl, 19, 0
+ ld [hl], a
+ coord hl, 19, 17
+ ld [hl], a
+ ld de, .Tilemap1
+ coord hl, 10, 8
+ lb bc, 3, 8
+ call Diploma_Surfing_CopyBox
+ ld de, .Tilemap2
+ coord hl, 2, 11
+ lb bc, 6, 16
+ call Diploma_Surfing_CopyBox
+ ld de, .PikachusBeachString
+ coord hl, 3, 2
+ call PlaceString
+ ld de, .HiScoreString
+ coord hl, 9, 4
+ call PlaceString
+ ld de, .PointsString
+ coord hl, 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
+ coord hl, 2, 4
+ add hl, bc
+ call PlaceString
+ call CopySurfingMinigameScore
+ ld b, 8
+ call RunPaletteCommand
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], 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:
+ db $7f, $7f, $10, $11, $12, $13, $14, $15
+ db $0f, $3c, $3d, $3e, $20, $21, $30, $31
+ db $4c, $4d, $4e, $50, $34, $1a, $51, $2d
+
+.Tilemap2:
+ db $7f, $7f, $7f, $7f, $7f, $7f, $16, $17, $18, $19, $7f, $1b, $1c, $1d, $1e, $1f
+ db $7f, $7f, $22, $23, $24, $25, $26, $27, $28, $29, $2a, $2b, $2c, $7f, $2e, $2f
+ db $7f, $7f, $32, $33, $33, $35, $36, $37, $38, $39, $3a, $3b, $7f, $7f, $7f, $3f
+ db $40, $41, $42, $43, $44, $45, $46, $47, $48, $49, $4a, $4b, $40, $40, $40, $4f
+ db $52, $52, $52, $53, $54, $55, $56, $57, $58, $59, $5a, $5b, $5c, $5d, $5d, $5e
+ db $7f, $7f, $7f, $05, $06, $07, $08, $09, $0a, $0b, $0c, $0d, $0e, $7f, $7f, $7f
+
+.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
+ coord hl, 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_2.2bpp"
+SurfingPikachu2GraphicsEnd:
+
+PrintPCBox_DrawPage1:
+ xor a
+ ld [wBoxNumString], a
+ call ClearScreen
+ call PrintPCBox_PlaceHorizontalLines
+ coord hl, 0, 0
+ ld bc, 11 * SCREEN_WIDTH
+ ld a, " "
+ call FillMemory
+ call PrintPCBox_DrawLeftAndRightBorders
+ call PrintPCBox_DrawTopBorder
+ coord hl, 4, 4
+ ld de, .PokemonListString
+ call PlaceString
+ coord hl, 7, 6
+ ld de, .BoxString
+ call PlaceString
+ coord hl, 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
+ coord hl, 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
+ coord hl, 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
+ coord hl, 4, 0
+ ld de, wBoxSpecies + 9
+ ld c, 6
+ call PrintPCBox_PlaceBoxMonInfo
+ ret
+
+PrintPCBox_DrawPage4:
+ call ClearScreen
+ call PrintPCBox_PlaceHorizontalLines
+ call PrintPCBox_DrawLeftAndRightBorders
+ coord hl, 0, 15
+ call PrintPCBox_DrawBottomBorderAtHL
+ coord hl, 0, 16
+ ld bc, 2 * SCREEN_WIDTH
+ ld a, " "
+ call FillMemory
+ ld a, [wBoxDataStart]
+ cp 16
+ ret c
+ coord hl, 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 [wd11e], 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], " "
+ 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:
+ coord hl, 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:
+ coord hl, 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:
+ coord hl, 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:
+ coord hl, 4, 0
+ ld c, 6
+ call .PlaceHorizontalLine
+ coord hl, 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/serial.asm b/engine/printer/serial.asm
new file mode 100755
index 00000000..fa83eb9d
--- /dev/null
+++ b/engine/printer/serial.asm
@@ -0,0 +1,621 @@
+StartTransmission_Send9Rows:
+ ld a, 9
+Printer_StartTransmission:
+ push af
+ ld hl, wPrinterData
+ ld bc, wPrinterDataEnd - wPrinterData
+ xor a
+ call Printer_FillMemory
+ xor a
+ ld [rSB], a
+ ld [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, (wPrinterSendDataSource1End - wPrinterSendDataSource1) % $100
+ ld [wPrinterDataSize], a
+ ld a, (wPrinterSendDataSource1End - wPrinterSendDataSource1) / $100
+ 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
+ ld [rSB], a
+ ld a, $1
+ ld [rSC], a
+ ld a, $81
+ ld [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:
+ ld a, [rSB]
+ ld [wPrinterHandshake], a
+ ld a, $0
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.Receive2:
+ ld 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:
+ ld [rSB], a
+ ld a, $1
+ ld [rSC], a
+ ld a, $81
+ ld [rSC], a
+ ret
+
+.Receive2_:
+ ld a, [rSB]
+ ld [wPrinterStatusFlags], a
+ xor a
+ ld [wPrinterOpcode], a
+ ret
diff --git a/engine/remove_pokemon.asm b/engine/remove_pokemon.asm
index 1fcb5d09..f29a428d 100644
--- a/engine/remove_pokemon.asm
+++ b/engine/remove_pokemon.asm
@@ -2,9 +2,9 @@ _RemovePokemon:
ld hl, wPartyCount
ld a, [wRemoveMonFromBox]
and a
- jr z, .asm_7b74
+ jr z, .usePartyCount
ld hl, wNumInBox
-.asm_7b74
+.usePartyCount
ld a, [hl]
dec a
ld [hli], a
@@ -15,28 +15,28 @@ _RemovePokemon:
ld e, l
ld d, h
inc de
-.asm_7b81
+.shiftMonSpeciesLoop
ld a, [de]
inc de
ld [hli], a
- inc a
- jr nz, .asm_7b81
+ inc a ; reached terminator?
+ jr nz, .shiftMonSpeciesLoop ; if not, continue shifting species
ld hl, wPartyMonOT
- ld d, $5
+ ld d, PARTY_LENGTH - 1 ; max number of pokemon to shift
ld a, [wRemoveMonFromBox]
and a
- jr z, .asm_7b97
+ jr z, .usePartyMonOTs
ld hl, wBoxMonOT
- ld d, $13
-.asm_7b97
+ ld d, MONS_PER_BOX - 1
+.usePartyMonOTs
ld a, [wWhichPokemon]
call SkipFixedLengthTextEntries
ld a, [wWhichPokemon]
- cp d
- jr nz, .asm_7ba6
- ld [hl], $ff
+ cp d ; are we removing the last pokemon?
+ jr nz, .notRemovingLastMon ; if not, shift the pokemon below
+ ld [hl], $ff ; else, write the terminator and return
ret
-.asm_7ba6
+.notRemovingLastMon
ld d, h
ld e, l
ld bc, NAME_LENGTH
@@ -44,41 +44,41 @@ _RemovePokemon:
ld bc, wPartyMonNicks
ld a, [wRemoveMonFromBox]
and a
- jr z, .asm_7bb8
+ jr z, .usePartyMonNicks
ld bc, wBoxMonNicks
-.asm_7bb8
+.usePartyMonNicks
call CopyDataUntil
ld hl, wPartyMons
ld bc, wPartyMon2 - wPartyMon1
ld a, [wRemoveMonFromBox]
and a
- jr z, .asm_7bcd
+ jr z, .usePartyMonStructs
ld hl, wBoxMons
ld bc, wBoxMon2 - wBoxMon1
-.asm_7bcd
+.usePartyMonStructs
ld a, [wWhichPokemon]
- call AddNTimes
- ld d, h
+ call AddNTimes ; get address of the pokemon removed
+ ld d, h ; store in de for CopyDataUntil
ld e, l
ld a, [wRemoveMonFromBox]
and a
- jr z, .asm_7be4
+ jr z, .copyUntilPartyMonOTs
ld bc, wBoxMon2 - wBoxMon1
- add hl, bc
- ld bc, wBoxMonOT
- jr .asm_7beb
-.asm_7be4
+ add hl, bc ; get address of pokemon after the pokemon removed
+ ld bc, wBoxMonOT ; address of when to stop copying
+ jr .continue
+.copyUntilPartyMonOTs
ld bc, wPartyMon2 - wPartyMon1
- add hl, bc
- ld bc, wPartyMonOT
-.asm_7beb
- call CopyDataUntil
+ add hl, bc ; get address of pokemon after the pokemon removed
+ ld bc, wPartyMonOT ; address of when to stop copying
+.continue
+ call CopyDataUntil ; shift all pokemon data after the removed mon to the removed mon's location
ld hl, wPartyMonNicks
ld a, [wRemoveMonFromBox]
and a
- jr z, .asm_7bfa
+ jr z, .usePartyMonNicks2
ld hl, wBoxMonNicks
-.asm_7bfa
+.usePartyMonNicks2
ld bc, NAME_LENGTH
ld a, [wWhichPokemon]
call AddNTimes
@@ -86,10 +86,10 @@ _RemovePokemon:
ld e, l
ld bc, NAME_LENGTH
add hl, bc
- ld bc, wPokedexOwned
+ ld bc, wPartyMonNicksEnd
ld a, [wRemoveMonFromBox]
and a
- jr z, .asm_7c15
+ jr z, .copyUntilPartyMonNicksEnd
ld bc, wBoxMonNicksEnd
-.asm_7c15
+.copyUntilPartyMonNicksEnd
jp CopyDataUntil
diff --git a/engine/save.asm b/engine/save.asm
index 97935dbb..7f453bf0 100755
--- a/engine/save.asm
+++ b/engine/save.asm
@@ -32,10 +32,8 @@ FileDataDestroyedText:
db "@"
LoadSAV0:
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
+ call EnableSRAMAndLatchClockData
ld a, $1
- ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], a
ld hl, sPlayerName ; hero name located in SRAM
ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV
@@ -79,10 +77,8 @@ LoadSAV0:
jp SAVGoodChecksum
LoadSAV1:
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
+ call EnableSRAMAndLatchClockData
ld a, $1
- ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], a
ld hl, sPlayerName ; hero name located in SRAM
ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV
@@ -99,10 +95,8 @@ LoadSAV1:
jp SAVGoodChecksum
LoadSAV2:
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
+ call EnableSRAMAndLatchClockData
ld a, $1
- ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], a
ld hl, sPlayerName ; hero name located in SRAM
ld bc, sMainDataCheckSum - sPlayerName ; but here checks the full SAV
@@ -126,9 +120,7 @@ SAVBadCheckSum:
scf
SAVGoodChecksum:
- ld a, $0
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
+ call DisableSRAMAndPrepareClockData
ret
LoadSAVIgnoreBadCheckSum:
@@ -139,12 +131,16 @@ LoadSAVIgnoreBadCheckSum:
SaveSAV:
callba PrintSaveScreenText
+ ld c, 10
+ call DelayFrames
ld hl, WouldYouLikeToSaveText
call SaveSAVConfirm
and a ;|0 = Yes|1 = No|
ret nz
+ ld c, 10
+ call DelayFrames
ld a, [wSaveFileStatus]
- dec a
+ cp $1
jr z, .save
call SAVCheckRandomID
jr z, .save
@@ -154,24 +150,20 @@ SaveSAV:
ret nz
.save
call SaveSAVtoSRAM
- coord hl, 1, 13
- lb bc, 4, 18
- call ClearScreenArea
- coord hl, 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
SaveSAVConfirm:
call PrintText
@@ -187,6 +179,10 @@ WouldYouLikeToSaveText:
TX_FAR _WouldYouLikeToSaveText
db "@"
+SavingText:
+ TX_FAR _SavingText
+ db "@"
+
GameSavedText:
TX_FAR _GameSavedText
db "@"
@@ -196,10 +192,8 @@ OlderFileWillBeErasedText:
db "@"
SaveSAVtoSRAM0:
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
+ call EnableSRAMAndLatchClockData
ld a, $1
- ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], a
ld hl, wPlayerName
ld de, sPlayerName
@@ -223,17 +217,13 @@ SaveSAVtoSRAM0:
ld bc, sMainDataCheckSum - sPlayerName
call SAVCheckSum
ld [sMainDataCheckSum], a
- xor a
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
+ call DisableSRAMAndPrepareClockData
ret
SaveSAVtoSRAM1:
; stored pokémon
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
+ call EnableSRAMAndLatchClockData
ld a, $1
- ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], a
ld hl, wBoxDataStart
ld de, sCurBoxData
@@ -243,16 +233,12 @@ SaveSAVtoSRAM1:
ld bc, sMainDataCheckSum - sPlayerName
call SAVCheckSum
ld [sMainDataCheckSum], a
- xor a
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
+ call DisableSRAMAndPrepareClockData
ret
SaveSAVtoSRAM2:
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
+ call EnableSRAMAndLatchClockData
ld a, $1
- ld [MBC1SRamBankingMode], a
ld [MBC1SRamBank], a
ld hl, wPartyDataStart
ld de, sPartyData
@@ -262,13 +248,18 @@ SaveSAVtoSRAM2:
ld de, sMainData
ld bc, wPokedexSeenEnd - wPokedexOwned
call CopyData
+ ld hl, wPikachuHappiness
+ ld de, sMainData + $179
+ ld a, [hli]
+ ld [de], a
+ inc de
+ ld a, [hl]
+ ld [de], a
ld hl, sPlayerName
ld bc, sMainDataCheckSum - sPlayerName
call SAVCheckSum
ld [sMainDataCheckSum], a
- xor a
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
+ call DisableSRAMAndPrepareClockData
ret
SaveSAVtoSRAM:
@@ -351,13 +342,16 @@ ChangeBox::
call z, EmptyAllSRAMBoxes ; if so, empty all boxes in SRAM
call DisplayChangeBoxMenu
call UpdateSprites
- ld hl, hFlags_0xFFF6
+ ld hl, hFlags_0xFFFA
set 1, [hl]
call HandleMenuInput
- ld hl, hFlags_0xFFF6
+ ld hl, hFlags_0xFFFA
res 1, [hl]
bit 1, a ; pressed b
ret nz
+ ld a, $b6
+ call PlaySoundWaitForCurrent
+ call WaitForSoundToFinish
call GetBoxSRAMLocation
ld e, l
ld d, h
@@ -380,9 +374,6 @@ ChangeBox::
call SaveSAVtoSRAM
ld hl, wChangeBoxSavedMapTextPointer
call SetMapTextPointer
- ld a, SFX_SAVE
- call PlaySoundWaitForCurrent
- call WaitForSoundToFinish
ret
WhenYouChangeBoxText:
@@ -392,10 +383,7 @@ WhenYouChangeBoxText:
CopyBoxToOrFromSRAM:
; copy an entire box from hl to de with b as the SRAM bank
push hl
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
+ call EnableSRAMAndLatchClockData
ld a, b
ld [MBC1SRamBank], a
ld bc, wBoxDataEnd - wBoxDataStart
@@ -413,9 +401,7 @@ CopyBoxToOrFromSRAM:
call SAVCheckSum
ld [sBank2AllBoxesChecksum], a ; sBank3AllBoxesChecksum
call CalcIndividualBoxCheckSums
- xor a
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
+ call DisableSRAMAndPrepareClockData
ret
DisplayChangeBoxMenu:
@@ -436,21 +422,19 @@ DisplayChangeBoxMenu:
ld [wCurrentMenuItem], a
ld [wLastMenuItem], a
coord hl, 0, 0
- ld b, 2
- ld c, 9
+ lb bc, 2, 9
call TextBoxBorder
ld hl, ChooseABoxText
call PrintText
coord hl, 11, 0
- ld b, 12
- ld c, 7
+ lb bc, 12, 7
call TextBoxBorder
- ld hl, hFlags_0xFFF6
+ ld hl, hFlags_0xFFFA
set 2, [hl]
ld de, BoxNames
coord hl, 13, 1
call PlaceString
- ld hl, hFlags_0xFFF6
+ ld hl, hFlags_0xFFFA
res 2, [hl]
ld a, [wCurrentBoxNum]
and $7f
@@ -513,19 +497,14 @@ BoxNoText:
EmptyAllSRAMBoxes:
; marks all boxes in SRAM as empty (initialisation for the first time the
; player changes the box)
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
+ call EnableSRAMAndLatchClockData
ld a, 2
ld [MBC1SRamBank], a
call EmptySRAMBoxesInBank
ld a, 3
ld [MBC1SRamBank], a
call EmptySRAMBoxesInBank
- xor a
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
+ call DisableSRAMAndPrepareClockData
ret
EmptySRAMBoxesInBank:
@@ -559,19 +538,14 @@ EmptySRAMBox:
GetMonCountsForAllBoxes:
ld hl, wBoxMonCounts
push hl
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
+ call EnableSRAMAndLatchClockData
ld a, $2
ld [MBC1SRamBank], a
call GetMonCountsForBoxesInBank
ld a, $3
ld [MBC1SRamBank], a
call GetMonCountsForBoxesInBank
- xor a
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
+ call DisableSRAMAndPrepareClockData
pop hl
; copy the count for the current box from WRAM
@@ -604,10 +578,8 @@ SAVCheckRandomID:
;checks if Sav file is the same by checking player's name 1st letter ($a598)
; and the two random numbers generated at game beginning
;(which are stored at wPlayerID)s
- ld a, $0a
- ld [MBC1SRamEnable], a
- ld a, $01
- ld [MBC1SRamBankingMode], a
+ call EnableSRAMAndLatchClockData
+ ld a, $1
ld [MBC1SRamBank], a
ld a, [sPlayerName]
and a
@@ -670,34 +642,23 @@ LoadHallOfFameTeams:
; fallthrough
HallOfFame_Copy:
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
+ call EnableSRAMAndLatchClockData
xor a
ld [MBC1SRamBank], a
call CopyData
- xor a
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
+ call DisableSRAMAndPrepareClockData
ret
ClearSAV:
- ld a, SRAM_ENABLE
- ld [MBC1SRamEnable], a
- ld a, $1
- ld [MBC1SRamBankingMode], a
- xor a
- call PadSRAM_FF
- ld a, $1
- call PadSRAM_FF
- ld a, $2
- call PadSRAM_FF
- ld a, $3
+ call EnableSRAMAndLatchClockData
+ ld a, $4
+.loop
+ dec a
+ push af
call PadSRAM_FF
- xor a
- ld [MBC1SRamBankingMode], a
- ld [MBC1SRamEnable], a
+ pop af
+ jr nz, .loop
+ call DisableSRAMAndPrepareClockData
ret
PadSRAM_FF:
@@ -706,3 +667,16 @@ PadSRAM_FF:
ld bc, $2000
ld a, $ff
jp FillMemory
+
+EnableSRAMAndLatchClockData:
+ ld a, $1
+ ld [MBC1SRamBankingMode], a
+ ld a, SRAM_ENABLE
+ ld [MBC1SRamEnable], a
+ ret
+
+DisableSRAMAndPrepareClockData:
+ ld a, SRAM_DISABLE
+ ld [MBC1SRamBankingMode], a
+ ld [MBC1SRamEnable], a
+ ret
diff --git a/engine/slot_machine.asm b/engine/slot_machine.asm
index 3a46687f..b4514618 100755
--- a/engine/slot_machine.asm
+++ b/engine/slot_machine.asm
@@ -23,9 +23,11 @@ PromptUserToPlaySlots:
call LoadFontTilePatterns
ld b, SET_PAL_SLOTS
call RunPaletteCommand
+ call Delay3
call GBPalNormal
ld a, $e4
ld [rOBP0], a
+ call UpdateGBCPal_OBP0
ld hl, wd730
set 6, [hl]
xor a
@@ -80,8 +82,7 @@ MainSlotMachineLoop:
ld [wLastMenuItem], a
ld [wMenuWatchMovingOutOfBounds], a
coord hl, 14, 11
- ld b, 5
- ld c, 4
+ lb bc, 5, 4
call TextBoxBorder
coord hl, 16, 12
ld de, CoinMultiplierSlotMachineText
@@ -457,6 +458,7 @@ SlotMachine_CheckForMatches:
ld a, [rBGP]
xor $40
ld [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 5
call DelayFrames
dec b
@@ -473,6 +475,7 @@ SlotMachine_CheckForMatches:
call SlotMachine_PrintPayoutCoins
ld a, $e4
ld [rOBP0], a
+ call UpdateGBCPal_OBP0
jp .done
SymbolLinedUpSlotMachineText:
@@ -698,6 +701,7 @@ SlotMachine_PayCoinsToPlayer:
ld a, [rOBP0]
xor $40 ; make the slot wheel symbols flash
ld [rOBP0], a
+ call UpdateGBCPal_OBP0
ld a, 5
.skip1
ld [wAnimCounter], a
@@ -852,17 +856,17 @@ LoadSlotMachineTiles:
ld de, vChars0
ld bc, $1c0
ld a, BANK(SlotMachineTiles2)
- call FarCopyData2
+ call FarCopyData
ld hl, SlotMachineTiles1
ld de, vChars2
ld bc, $250
ld a, BANK(SlotMachineTiles1)
- call FarCopyData2
+ call FarCopyData
ld hl, SlotMachineTiles2
ld de, vChars2 + $250
ld bc, $1c0
ld a, BANK(SlotMachineTiles2)
- call FarCopyData2
+ call FarCopyData
ld hl, SlotMachineMap
coord de, 0, 0
ld bc, SlotMachineMapEnd - SlotMachineMap
@@ -884,9 +888,4 @@ SlotMachineMapEnd:
INCLUDE "data/slot_machine_wheels.asm"
SlotMachineTiles1:
-IF DEF(_RED)
- INCBIN "gfx/red/slotmachine1.2bpp"
-ENDC
-IF DEF(_BLUE)
- INCBIN "gfx/blue/slotmachine1.2bpp"
-ENDC
+ INCBIN "gfx/slotmachine1.2bpp"
diff --git a/engine/surfing_minigame.asm b/engine/surfing_minigame.asm
new file mode 100755
index 00000000..81e5296d
--- /dev/null
+++ b/engine/surfing_minigame.asm
@@ -0,0 +1,2862 @@
+SurfingPikachuMinigame:
+ call SurfingPikachuMinigame_BlankPals
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ ld a, [hTilesetType]
+ push af
+ xor a
+ ld [hTilesetType], a
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ ld a, [rIE]
+ push af
+ xor a
+ ld [rIF], a
+ ld a, $f
+ ld [rIE], a
+ ld a, $8
+ ld [rSTAT], a
+ ld a, [H_AUTOBGTRANSFERDEST + 1]
+ push af
+ ld a, $98
+ ld [H_AUTOBGTRANSFERDEST + 1], a
+ call SurfingPikachuMinigameIntro
+ call SurfingPikachuLoop
+ xor a
+ ld [rBGP], a
+ ld [rOBP0], a
+ ld [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
+ call ClearObjectAnimationBuffers
+ call ClearSprites
+ xor a
+ ld [hLCDCPointer], a
+ ld [hSCX], a
+ ld [hSCY], a
+ ld a, $90
+ ld [hWY], a
+ call DelayFrame
+ pop af
+ ld [H_AUTOBGTRANSFERDEST + 1], a
+ xor a
+ ld [rIF], a
+ pop af
+ ld [rIE], a
+ xor a
+ ld [rSTAT], a
+ call RunDefaultPaletteCommand
+ call ReloadMapAfterSurfingMinigame
+ call PlayDefaultMusic
+ call GBPalNormal
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ pop af
+ ld [hTilesetType], a
+ ret
+
+SurfingPikachuLoop:
+ call SurfingPikachuMinigame_LoadGFXAndLayout
+ call DelayFrame
+ ld b, $e
+ 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
+ ld a, [hJoyPressed]
+ and SELECT
+ ret
+
+Func_f80b7:
+ ld a, [hJoyPressed]
+ and 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
+ ld [H_AUTOBGTRANSFERENABLED], 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, SurfingPikachuSpawnStateDataPointer % $100
+ ld [wAnimatedObjectSpawnStateDataPointer], a
+ ld a, SurfingPikachuSpawnStateDataPointer / $100
+ ld [wAnimatedObjectSpawnStateDataPointer + 1], a
+
+ ld a, SurfingPikachuObjectJumptable % $100
+ ld [wAnimatedObjectJumptablePointer], a
+ ld a, SurfingPikachuObjectJumptable / $100
+ ld [wAnimatedObjectJumptablePointer + 1], a
+
+ ld a, SurfingPikachuOAMData % $100
+ ld [wAnimatedObjectOAMDataPointer], a
+ ld a, SurfingPikachuOAMData / $100
+ ld [wAnimatedObjectOAMDataPointer + 1], a
+
+ ld a, SurfingPikachuFrames % $100
+ ld [wAnimatedObjectFramesDataPointer], a
+ ld a, SurfingPikachuFrames / $100
+ ld [wAnimatedObjectFramesDataPointer + 1], a
+
+ ld hl, vBGMap0
+ ld bc, $800
+ ld a, $0
+ call FillMemory
+
+ ld hl, $98c0
+ ld bc, $180
+ 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
+ ld [hSCX], a
+ ld [hSCY], a
+ ld a, $7e
+ ld [hWY], a
+ ld a, rSCY - $ff00
+ ld [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
+ ld [rLCDC], a
+ call SurfingPikachuMinigame_SetBGPals
+ ld a, $e4
+ ld [rOBP0], a
+ ld a, $e0
+ ld [rOBP1], a
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
+ ret
+
+SurfingPikachuMinigame_SetBGPals:
+ ld a, [wOnSGB]
+ and a
+ jr nz, .sgb
+ ld a, $d0
+ ld [rBGP], a
+ call UpdateGBCPal_BGP
+ ret
+
+.sgb
+ ld a, $e4
+ ld [rBGP], a
+ call UpdateGBCPal_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
+ ld [hSCX], a
+ ld a, $72
+ ld [wSurfingMinigameWaveFunctionNumber], a
+ ld a, $4
+ ld [wc5d2], a
+ xor a
+ ld [hLCDCPointer], a
+ ld [wSurfingMinigameSCX], a
+ ld [wSurfingMinigameSCX + 1], a
+ ld [wSurfingMinigameSCX + 2], a
+ ret
+
+Func_f835c:
+ ld a, [hSCX]
+ and a
+ jr z, .asm_f837b
+ call SurfingMinigame_UpdateLYOverrides
+ call SurfingMinigame_SetPikachuHeight
+ call SurfingMinigame_ReadBGMapBuffer
+ ld a, [hSCX]
+ dec a
+ dec a
+ dec a
+ dec a
+ ld [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
+ ld a, [hJoyPressed]
+ and A_BUTTON
+ 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
+ ld a, [hJoyPressed]
+ and A_BUTTON
+ 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, wOAMBuffer + 4 * 4 + 1
+ 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 + Ch8], 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 + Ch8], a
+ ld a, SFX_SURFING_LAND
+ 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 D_LEFT
+ jr nz, .d_left
+ ld a, [de]
+ and D_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 + Ch8], a
+ ld a, SFX_SURFING_CRASH
+ 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:
+ ld 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:
+ ld 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:
+ ld 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
+ ld a, [hSCX]
+ and $7
+ ld e, a
+ ld a, [hl]
+ sub e
+ ret
+
+.seven
+ ld 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, wOAMBuffer + 5 * 4 + 1
+ 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] ; ???
+ ld 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
+ ld [H_VBCOPYDEST], a
+ ld a, d
+ ld [H_VBCOPYDEST + 1], a
+ ld a, l
+ ld [H_VBCOPYSRC], a
+ ld a, h
+ ld [H_VBCOPYSRC + 1], a
+ ld a, 16 / $10
+ ld [H_VBCOPYSIZE], a
+ ret
+
+SurfingMinigame_SetPikachuHeight:
+ ld 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
+ ld a, [hSCX]
+ and $7
+ ld e, a
+ ld a, [hl]
+ sub e
+ ld [wSurfingMinigamePikachuObjectHeight], a
+ ret
+
+.asm_f88db
+ ld 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, wOAMBuffer + 0 * 4 + 2
+ ld a, [de]
+ call .PlaceBCDNumber
+ ld hl, wOAMBuffer + 2 * 4 + 2
+ 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_WIDTH * SCREEN_HEIGHT
+ xor a
+ call FillMemory
+ ld hl, .BeachTilemap
+ coord de, 0, 6
+ ld bc, .BeachTilemapEnd - .BeachTilemap
+ call CopyData
+ call .PlaceTextbox
+ ld hl, wOAMBuffer + 5 * 4 + 1
+ ld bc, 9 * 4
+ xor a
+ call FillMemory
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ret
+
+.BeachTilemap:
+INCBIN "gfx/unknown_f8946.map"
+.BeachTilemapEnd:
+
+.PlaceTextbox:
+ coord hl, 1, 1
+ lb de, $3b, $3c
+ ld a, $40
+ call .place_row
+ coord hl, 1, 2
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ coord hl, 1, 3
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ coord hl, 1, 4
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ coord hl, 1, 5
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ coord hl, 1, 6
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ coord hl, 1, 7
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ coord hl, 1, 8
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ coord hl, 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
+ coord de, 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
+ coord de, 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_SURFING_ADD_POINTS
+ call PlaySound
+ and a
+ ret
+
+.dead
+ pop bc
+ scf
+ ret
+
+SurfingMinigame_BCDPrintHPLeft:
+ coord hl, 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
+ coord de, 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_SURFING_ADD_POINTS
+ call PlaySound
+ and a
+ ret
+
+.done
+ pop bc
+ scf
+ ret
+
+SurfingMinigame_BCDPrintRadness:
+ ld a, [wSurfingMinigameRadnessScore + 1]
+ coord hl, 10, 4
+ call SurfingPikachu_PlaceBCDNumber
+ ld a, [wSurfingMinigameRadnessScore]
+ coord hl, 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]
+ coord hl, 10, 6
+ call SurfingPikachu_PlaceBCDNumber
+ ld a, [wSurfingMinigameTotalScore]
+ coord hl, 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
+ coord de, 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
+ callab IsSurfingPikachuInThePlayersParty
+ pop de
+ ret nc
+ callab 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
+ ld 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
+ ld [hSCX], a
+ jr SurfingMinigame_GenerateBGMap
+
+SurfingMinigame_ScrollAndGenerateBGMap:
+ ld a, $a0
+ ld [wSurfingMinigameXOffset], a
+ ld 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
+ ld [hSCX], a
+SurfingMinigame_GenerateBGMap:
+ ld hl, wSurfingMinigameSCX + 1
+ ld a, [hSCX]
+ cp [hl]
+ ret z
+ ld [hl], a
+ and $f0
+ ld hl, wSurfingMinigameSCX + 2
+ 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
+ ld 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
+ ld [hRedrawRowOrColumnDest], a
+ ld a, h
+ ld [hRedrawRowOrColumnDest + 1], a
+ ld a, $1
+ ld [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
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call ClearObjectAnimationBuffers
+ ld hl, SurfingPikachu1Graphics3
+ ld de, $8800
+ ld bc, $900
+ ld a, BANK(SurfingPikachu1Graphics3)
+ call FarCopyData
+ ld a, SurfingPikachuSpawnStateDataPointer % $100
+ ld [wAnimatedObjectSpawnStateDataPointer], a
+ ld a, SurfingPikachuSpawnStateDataPointer / $100
+ ld [wAnimatedObjectSpawnStateDataPointer + 1], a
+ ld a, SurfingPikachuObjectJumptable % $100
+ ld [wAnimatedObjectJumptablePointer], a
+ ld a, SurfingPikachuObjectJumptable / $100
+ ld [wAnimatedObjectJumptablePointer + 1], a
+ ld a, SurfingPikachuOAMData % $100
+ ld [wAnimatedObjectOAMDataPointer], a
+ ld a, SurfingPikachuOAMData / $100
+ ld [wAnimatedObjectOAMDataPointer + 1], a
+ ld a, SurfingPikachuFrames % $100
+ ld [wAnimatedObjectFramesDataPointer], a
+ ld a, SurfingPikachuFrames / $100
+ ld [wAnimatedObjectFramesDataPointer + 1], a
+ ld a, $c
+ lb de, $74, $58
+ call SpawnAnimatedObject
+ call DrawSurfingPikachuMinigameIntroBackground
+ xor a
+ ld [hSCX], a
+ ld [hSCY], a
+ ld a, $90
+ ld [hWY], a
+ ld b, $f
+ call RunPaletteCommand
+ ld a, $e3
+ ld [rLCDC], a
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ call SurfingPikachuMinigame_SetBGPals
+ ld a, $e4
+ ld [rOBP0], a
+ ld a, $e0
+ ld [rOBP1], a
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_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_WIDTH * SCREEN_HEIGHT
+ ld a, $ff
+ call FillMemory
+ ld hl, Tilemap_f90bc
+ coord de, 0, 6
+ ld bc, 12 * SCREEN_WIDTH
+ call CopyData
+ ld de, Tilemap_f91c8
+ coord hl, 4, 0
+ lb bc, 6, 12
+ call .CopyBox
+ coord hl, 3, 7
+ lb bc, 3, 15
+ call .FillBoxWithFF
+ ld hl, Tilemap_f91ac
+ coord de, 3, 7
+ ld bc, 15
+ call CopyData
+ ld hl, Tilemap_f91bb
+ coord de, 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/unknown_f90bc.map"
+Tilemap_f91ac: INCBIN "gfx/unknown_f91ac.map"
+Tilemap_f91bb: INCBIN "gfx/unknown_f91bb.map"
+Tilemap_f91c8: INCBIN "gfx/unknown_f91c8.map"
+
+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
+ ld a, [H_FRAMECOUNTER]
+ and a
+ jr nz, .delayed
+ ld a, [hJoyHeld]
+ ld [hJoy5], a
+ ld a, $2
+ ld [H_FRAMECOUNTER], a
+ ret
+
+.delayed
+ xor a
+ ld [hJoy5], a
+ ret
+
+SurfingPikachuMinigame_BlankPals:
+ xor a
+ ld [rBGP], a
+ ld [rOBP0], a
+ ld [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
+ ret
+
+SurfingPikachuMinigame_NormalPals:
+ ld a, $e4
+ ld [rBGP], a
+ ld [rOBP0], a
+ ld a, $e0
+ ld [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
+ ret
+
+SurfingPikachu_ClearTileMap:
+ ld hl, wTileMap
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ 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_wave $100
+
+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/animated_objects_3e_1.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/titlescreen.asm b/engine/titlescreen.asm
index 03a5832d..d4dd0fd3 100755
--- a/engine/titlescreen.asm
+++ b/engine/titlescreen.asm
@@ -1,8 +1,3 @@
-; copy text of fixed length NAME_LENGTH (like player name, rival name, mon names, ...)
-CopyFixedLengthText:
- ld bc, NAME_LENGTH
- jp CopyData
-
SetDefaultNamesBeforeTitlescreen:
ld hl, NintenText
ld de, wPlayerName
@@ -35,98 +30,35 @@ DisplayTitleScreen:
call ClearScreen
call DisableLCD
call LoadFontTilePatterns
+; todo: fix hl pointers
ld hl, NintendoCopyrightLogoGraphics
- ld de, vTitleLogo2 + $100
+ ld de, vTitleLogo + $600
ld bc, $50
ld a, BANK(NintendoCopyrightLogoGraphics)
- call FarCopyData2
+ call FarCopyData
+ ld hl, NineTile
+ ld de, vTitleLogo + $6e0
+ ld bc, $10
+ ld a, BANK(NineTile)
+ call FarCopyData
ld hl, GamefreakLogoGraphics
- ld de, vTitleLogo2 + $100 + $50
- ld bc, $90
+ ld de, vTitleLogo + 101 * $10
+ ld bc, 9 * $10
ld a, BANK(GamefreakLogoGraphics)
- call FarCopyData2
- ld hl, PokemonLogoGraphics
- ld de, vTitleLogo
- ld bc, $600
- ld a, BANK(PokemonLogoGraphics)
- call FarCopyData2 ; first chunk
- ld hl, PokemonLogoGraphics+$600
- ld de, vTitleLogo2
- ld bc, $100
- ld a, BANK(PokemonLogoGraphics)
- call FarCopyData2 ; second chunk
- ld hl, Version_GFX
- ld de, vChars2 + $600 - (Version_GFXEnd - Version_GFX - $50)
- 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)
- coord hl, 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
- coord hl, 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, wOAMBuffer + $28
- ld a, $74
- ld [hl], a
-
-; place tiles for title screen copyright
- coord hl, 2, 17
- ld de, .tileScreenCopyrightTiles
- ld b, $10
-.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.
-
-.next
+ call FarCopyData
+ callab LoadYellowTitleScreenGFX
+ ld hl, vBGMap0
+ ld bc, (vBGMap1 + $400) - vBGMap0
+ ld a, " "
+ call FillMemory
+ callab TitleScreen_PlacePokemonLogo
+ call FillSpriteBuffer0WithAA
+ call .WriteCopyrightTiles
call SaveScreenTilesToBuffer2
call LoadScreenTilesFromBuffer2
call EnableLCD
-IF DEF(_RED)
- ld a, CHARMANDER ; which Pokemon to show first on the title screen
-ENDC
-IF DEF(_BLUE)
- ld a, SQUIRTLE ; which Pokemon to show first on the title screen
-ENDC
-
- ld [wTitleMonSpecies], a
- call LoadTitleMonSprite
- ld a, (vBGMap0 + $300) / $100
+ callab TitleScreen_PlacePikachu
+ ld a, $9b
call TitleScreenCopyTileMapToVRAM
call SaveScreenTilesToBuffer1
ld a, $40
@@ -137,8 +69,9 @@ ENDC
ld b, SET_PAL_TITLE_SCREEN
call RunPaletteCommand
call GBPalNormal
- ld a, %11100100
+ ld a, %11100000
ld [rOBP0], a
+ call UpdateGBCPal_OBP0
; make pokemon logo bounce up and down
ld bc, hSCY ; background scroll Y
@@ -180,6 +113,21 @@ ENDC
jr nz, .ScrollTitleScreenPokemonLogo
ret
+; place tiles for title screen copyright
+.WriteCopyrightTiles
+ coord hl, 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
@@ -188,52 +136,42 @@ ENDC
call PlaySound
; scroll game version in from the right
- call PrintGameVersionOnTitleScreen
+ callab TitleScreen_PlacePikaSpeechBubble
ld a, SCREEN_HEIGHT_PIXELS
ld [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, vBGMap1 / $100
- call TitleScreenCopyTileMapToVRAM
- call LoadScreenTilesFromBuffer2
- call PrintGameVersionOnTitleScreen
call Delay3
+ ld e, 0
+ call TitleScreen_PlayPikachuPCM
call WaitForSoundToFinish
+ call StopAllMusic
ld a, MUSIC_TITLE_SCREEN
ld [wNewSoundID], a
call PlaySound
+.loop
xor a
ld [wUnusedCC5B], a
-
-; 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
- callba TitleScreenAnimateBallIfStarterOut
- call TitleScreenPickNewMon
- jr .awaitUserInterruptionLoop
-
-.finishedWaiting
- ld a, [wTitleMonSpecies]
- call PlayCry
- call WaitForSoundToFinish
+ 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
+ ld a, [hJoyHeld]
+ cp D_UP | SELECT | B_BUTTON
+ jr z, .go_to_main_menu
+ and A_BUTTON | START
+ jr nz, .go_to_main_menu
+ call DoTitleScreenFunction
+ jr .titleScreenLoop
+
+.go_to_main_menu
+ ld e, $a
+ call TitleScreen_PlayPikachuPCM
call GBPalWhiteOutWithDelay3
call ClearSprites
xor a
@@ -254,108 +192,39 @@ ENDC
jp z, .doClearSaveDialogue
jp MainMenu
-.doClearSaveDialogue
- jpba DoClearSaveDialogue
-
-TitleScreenPickNewMon:
- ld a, vBGMap0 / $100
- 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
- ld [hWY], a
- ld d, 1 ; scroll out
- callba TitleScroll
- ret
-
-TitleScreenScrollInMon:
- ld d, 0 ; scroll in
- callba TitleScroll
- xor a
- ld [hWY], a
- ret
-
-ScrollTitleScreenGameVersion:
-.wait
- ld a, [rLY]
- cp l
- jr nz, .wait
-
- ld a, h
- ld [rSCX], a
+.asm_42f0
+; unreferenced
+ callab PrinterDebug
+ jp .loop
-.wait2
- ld a, [rLY]
- cp h
- jr z, .wait2
- ret
-
-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, wOAMBuffer
- ld de, $605a
- 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 $2a
+ jr c, .asm_4305
+ ld a, $f
+.asm_4305
+ ld [wTitleScreenScene + 4], a
+ ld e, a
+ callab PlayPikachuSoundClip
+ xor a
+ ld [wTitleScreenScene + 2], a
+ ld [wTitleScreenScene + 3], a
+ jp .titleScreenLoop
+
+.doTitlescreenReset
+ ld [wAudioFadeOutControl], a
+ call StopAllMusic
+.audioFadeLoop
+ ld a, [wAudioFadeOutControl]
+ and a
+ jr nz, .audioFadeLoop
+ jp Init
-ClearBothBGMaps:
- ld hl, vBGMap0
- ld bc, $400 * 2
- ld a, " "
- jp FillMemory
+.doClearSaveDialogue
+ jpba DoClearSaveDialogue
-LoadTitleMonSprite:
- ld [wcf91], a
- ld [wd0b5], a
- coord hl, 5, 10
- call GetMonHeader
- jp LoadFrontSpriteByMonIndex
TitleScreenCopyTileMapToVRAM:
ld [H_AUTOBGTRANSFERDEST + 1], a
@@ -370,34 +239,132 @@ LoadCopyrightAndTextBoxTiles:
LoadCopyrightTiles:
ld de, NintendoCopyrightLogoGraphics
ld hl, vChars2 + $600
- lb bc, BANK(NintendoCopyrightLogoGraphics), (GamefreakLogoGraphicsEnd - NintendoCopyrightLogoGraphics) / $10
+ lb bc, BANK(NintendoCopyrightLogoGraphics), (TextBoxGraphics + $10 - NintendoCopyrightLogoGraphics) / $10 ; bug: overflows into text box graphics and copies the "A" tile
call CopyVideoData
coord hl, 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/title_mons.asm"
-
-; prints version text (red, blue)
-PrintGameVersionOnTitleScreen:
- coord hl, 7, 8
- ld de, VersionOnTitleScreenText
- jp PlaceString
+TitleScreen_PlayPikachuPCM:
+ callab PlayPikachuSoundClip
+ ret
+
+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
+
+
+.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, wOAMBuffer + 2
+ 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
-; 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
+; copy text of fixed length NAME_LENGTH (like player name, rival name, mon names, ...)
+CopyFixedLengthText:
+ ld bc, NAME_LENGTH
+ jp CopyData
NintenText: db "NINTEN@"
SonyText: 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 SwitchSRAMBankAndLatchClockData
+ ld hl, sSpriteBuffer0
+ ld bc, $20
+ ld a, $aa
+ call FillMemory
+ call PrepareRTCDataAndDisableSRAM
+ ret
diff --git a/engine/titlescreen2.asm b/engine/titlescreen2.asm
index 2346fcc5..8b4bc4de 100755
--- a/engine/titlescreen2.asm
+++ b/engine/titlescreen2.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,7 +91,7 @@ TitleBallYTable:
TitleScreenAnimateBallIfStarterOut:
; Animate the TitleBall if a starter just got scrolled out.
- ld a, [wTitleMonSpecies]
+ ld a, [wTitleScreenScene]
cp STARTER1
jr z, .ok
cp STARTER2
diff --git a/engine/town_map.asm b/engine/town_map.asm
index d417e0a3..7d32b5fe 100755
--- a/engine/town_map.asm
+++ b/engine/town_map.asm
@@ -103,6 +103,13 @@ DisplayTownMap:
ld [wWhichTownMapLocation], a
jp .townMapLoop
+.asm_70f87
+ ld a,[hJoy5]
+ and D_DOWN | D_UP
+ ret z
+ callab PlayPikachuSoundClip
+ ret
+
INCLUDE "data/town_map_order.asm"
TownMapCursor:
@@ -137,11 +144,14 @@ MonsNestText:
LoadTownMap_Fly:
call ClearSprites
call LoadTownMap
+ ld a, $1
+ ld [hJoy7], a
call LoadPlayerSpriteGraphics
call LoadFontTilePatterns
ld de, BirdSprite
+ ld b, BANK(BirdSprite)
+ ld c, $c
ld hl, vSprites + $40
- lb bc, BANK(BirdSprite), $c
call CopyVideoData
ld de, TownMapUpArrow
ld hl, vChars1 + $6d0
@@ -179,7 +189,7 @@ LoadTownMap_Fly:
ld c, 15
call DelayFrames
coord hl, 18, 0
- ld [hl], "▲"
+ ld [hl], "▶"
coord hl, 19, 0
ld [hl], "▼"
pop hl
@@ -213,6 +223,7 @@ LoadTownMap_Fly:
.pressedB
xor a
ld [wTownMapSpriteBlinkingEnabled], a
+ ld [hJoy7], a
call GBPalWhiteOutWithDelay3
pop hl
pop af
@@ -279,15 +290,14 @@ LoadTownMap:
call ClearScreen
call UpdateSprites
coord hl, 0, 0
- ld b, $12
- ld c, $12
+ lb bc, $12, $12
call TextBoxBorder
call DisableLCD
ld hl, WorldMapTileGraphics
ld de, vChars2 + $600
ld bc, WorldMapTileGraphicsEnd - WorldMapTileGraphics
ld a, BANK(WorldMapTileGraphics)
- call FarCopyData2
+ call FarCopyData
ld hl, MonNestIcon
ld de, vSprites + $40
ld bc, MonNestIconEnd - MonNestIcon
@@ -397,8 +407,7 @@ DisplayWildLocations:
jr nz, .drawPlayerSprite
; if no OAM entries were written, print area unknown text
coord hl, 1, 7
- ld b, 2
- ld c, 15
+ lb bc, 2, 15
call TextBoxBorder
coord hl, 2, 9
ld de, AreaUnknownText
diff --git a/engine/trade.asm b/engine/trade.asm
index 8bc8e3bc..e4bc0768 100755
--- a/engine/trade.asm
+++ b/engine/trade.asm
@@ -20,12 +20,13 @@ ExternalClockTradeAnim:
TradeAnimCommon:
ld a, [wOptions]
push af
+ and %110000 ; preserve speaker options
+ ld [wOptions], a
ld a, [hSCY]
push af
ld a, [hSCX]
push af
xor a
- ld [wOptions], a
ld [hSCY], a
ld [hSCX], a
push de
@@ -160,12 +161,12 @@ LoadTradingGFXAndMonNames:
ld de, vChars2 + $310
ld bc, TradingAnimationGraphicsEnd - TradingAnimationGraphics
ld a, BANK(TradingAnimationGraphics)
- call FarCopyData2
+ call FarCopyData
ld hl, TradingAnimationGraphics2
ld de, vSprites + $7c0
ld bc, TradingAnimationGraphics2End - TradingAnimationGraphics2
ld a, BANK(TradingAnimationGraphics2)
- call FarCopyData2
+ call FarCopyData
ld hl, vBGMap0
ld bc, $800
ld a, " "
@@ -182,6 +183,7 @@ LoadTradingGFXAndMonNames:
ld a, $f0 ; SGB OBP0
.next
ld [rOBP0], a
+ call UpdateGBCPal_OBP0
call EnableLCD
xor a
ld [H_AUTOBGTRANSFERENABLED], a
@@ -199,6 +201,7 @@ LoadTradingGFXAndMonNames:
Trade_LoadMonPartySpriteGfx:
ld a, %11010000
ld [rOBP1], a
+ call UpdateGBCPal_OBP1
jpba LoadMonPartySpriteGfx
Trade_SwapNames:
@@ -233,8 +236,7 @@ Trade_ShowPlayerMon:
xor a
ld [H_AUTOBGTRANSFERENABLED], a
coord hl, 4, 0
- ld b, 6
- ld c, 10
+ lb bc, 6, 10
call TextBoxBorder
call Trade_PrintPlayerMonInfoText
ld b, vBGMap0 / $100
@@ -303,6 +305,7 @@ Trade_AnimateBallEnteringLinkCable:
call DelayFrames
ld a, %11100100
ld [rOBP0], a
+ call UpdateGBCPal_OBP0
xor a
ld [wLinkCableAnimBulgeToggle], a
lb bc, $20, $60
@@ -354,8 +357,7 @@ Trade_ShowEnemyMon:
call Trade_ShowAnimation
call Trade_ShowClearedWindow
coord hl, 4, 10
- ld b, 6
- ld c, 10
+ lb bc, 6, 10
call TextBoxBorder
call Trade_PrintEnemyMonInfoText
call Trade_CopyTileMapToVRAM
@@ -382,6 +384,7 @@ Trade_AnimLeftToRight:
ld [wTradedMonMovingRight], a
ld a, %11100100
ld [rOBP0], a
+ call UpdateGBCPal_OBP0
ld a, $54
ld [wBaseCoordX], a
ld a, $1c
@@ -446,6 +449,8 @@ Trade_InitGameboyTransferGfx:
ld a, $1
ld [H_AUTOBGTRANSFERENABLED], a
call ClearScreen
+ ld b, SET_PAL_GENERIC
+ call RunPaletteCommand
xor a
ld [H_AUTOBGTRANSFERENABLED], a
call Trade_LoadMonPartySpriteGfx
@@ -479,8 +484,7 @@ Trade_DrawLeftGameboy:
; draw text box with player name below gameboy pic
coord hl, 4, 12
- ld b, 2
- ld c, 7
+ lb bc, 2, 7
call TextBoxBorder
coord hl, 5, 14
ld de, wPlayerName
@@ -526,8 +530,7 @@ Trade_DrawRightGameboy:
; draw text box with enemy name above link cable
coord hl, 6, 0
- ld b, 2
- ld c, 7
+ lb bc, 2, 7
call TextBoxBorder
coord hl, 7, 2
ld de, wLinkEnemyTrainerName
@@ -599,6 +602,7 @@ Trade_AnimCircledMon:
ld a, [rBGP]
xor $3c ; make link cable flash
ld [rBGP], a
+ call UpdateGBCPal_BGP
ld hl, wOAMBuffer + $02
ld de, $4
ld c, $14
@@ -620,7 +624,7 @@ Trade_WriteCircledMonOAM:
Trade_AddOffsetsToOAMCoords:
ld hl, wOAMBuffer
- ld c, $14
+ ld c, $14 ; SCREEN_WIDTH?
.loop
ld a, [wBaseCoordY]
add [hl]
diff --git a/engine/turn_sprite.asm b/engine/turn_sprite.asm
deleted file mode 100755
index e8a47a8f..00000000
--- a/engine/turn_sprite.asm
+++ /dev/null
@@ -1,25 +0,0 @@
-UpdateSpriteFacingOffsetAndDelayMovement:
- ld h, $c2
- ld a, [H_CURRENTSPRITEOFFSET]
- add $8
- ld l, a
- ld a, $7f ; maximum movement delay
- ld [hl], a ; c2x8 (movement delay)
- dec h
- ld a, [H_CURRENTSPRITEOFFSET]
- add $9
- ld l, a
- ld a, [hld] ; c1x9 (facing direction)
- ld b, a
- xor a
- ld [hld], a
- ld [hl], a ; c1x8 (walk animation frame)
- ld a, [H_CURRENTSPRITEOFFSET]
- add $2
- ld l, a
- ld a, [hl] ; c1x2 (facing and animation table offset)
- or b ; or in the facing direction
- ld [hld], a
- ld a, $2 ; delayed movement status
- ld [hl], a ; c1x1 (movement status)
- ret
diff --git a/engine/unknown_ea3ea.asm b/engine/unknown_ea3ea.asm
new file mode 100755
index 00000000..1908809b
--- /dev/null
+++ b/engine/unknown_ea3ea.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
+ ld [H_AUTOBGTRANSFERENABLED], a
+ xor a
+ ld [wWhichTradeMonSelectionMenu], a
+ call LoadMonData
+
+ ld hl, wTileMap
+ lb bc, 16, 18
+ call TextBoxBorder
+
+ coord hl, 0, 12
+ lb bc, 4, 18
+ call TextBoxBorder
+
+ coord hl, 3, 10
+ call PrintLevelFull
+
+ coord hl, 2, 10
+ ld a, $6e
+ ld [hli], a
+ ld [hl], " "
+
+ coord hl, 2, 11
+ ld [hl], "′"
+
+ coord hl, 4, 11
+ ld de, wLoadedMonMaxHP
+ lb bc, 2, 3
+ call PrintNumber
+
+ ld a, [wMonHeader]
+ ld [wPokeBallAnimData], a
+ ld [wd0b5], a
+ ld hl, wPartyMonNicks
+ call .GetNamePointer
+ coord hl, 8, 2
+ call PlaceString
+
+ call GetMonName
+ coord hl, 9, 3
+ call PlaceString
+
+ predef IndexToPokedex
+ coord hl, 2, 8
+ ld [hl], "№"
+ inc hl
+ ld [hl], $f2
+ inc hl
+ ld de, wPokeBallAnimData
+ lb bc, $80 | 1, 3
+ call PrintNumber
+
+ coord hl, 8, 4
+ ld de, .OT
+ call PlaceString
+
+ ld hl, wPartyMonOT
+ call .GetNamePointer
+ coord hl, 9, 5
+ call PlaceString
+
+ coord hl, 9, 6
+ ld de, .IDNo
+ call PlaceString
+
+ coord hl, 13, 6
+ ld de, wLoadedMonOTID
+ lb bc, $80 | 2, 5
+ call PrintNumber
+
+ coord hl, 9, 8
+ ld de, .Stats
+ ld a, [hFlags_0xFFFA]
+ set 2, a
+ ld [hFlags_0xFFFA], a
+ call PlaceString
+ ld a, [hFlags_0xFFFA]
+ res 2, a
+ ld [hFlags_0xFFFA], a
+
+ coord hl, 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
+
+ coord hl, 1, 13
+ ld a, [wLoadedMonMoves]
+ call .PlaceMoveName
+
+ coord hl, 1, 14
+ ld a, [wLoadedMonMoves + 1]
+ call .PlaceMoveName
+
+ coord hl, 1, 15
+ ld a, [wLoadedMonMoves + 2]
+ call .PlaceMoveName
+
+ coord hl, 1, 16
+ ld a, [wLoadedMonMoves + 3]
+ call .PlaceMoveName
+
+ ld b, $4 ; SET_PAL_STATUS_SCREEN
+ call RunPaletteCommand
+
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call Delay3
+ call GBPalNormal
+ coord hl, 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 [wPokeBallAnimData], a
+ call GetMoveName
+ jr .place_string
+
+.no_move
+ ld de, .Blank
+.place_string
+ call PlaceString
+ ret
+
+.OT:
+ db "OT/@"
+
+.IDNo:
+ db $73, "№/@"
+
+.Stats:
+ db "ATTACK"
+ next "DEFENSE"
+ next "SPEED"
+ next "SPECIAL@"
+
+.Blank:
+ db "--------------@"
+
+GFX_ea563:
+INCBIN "gfx/stats_screen_hp.1bpp"
+GFX_ea563End:
+
+GFX_ea56b:
+INCBIN "gfx/stats_screen_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, wOAMBuffer + 32 * 4
+ 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/zero_one_ea597.2bpp"
+GFX_ea597End:
+
+PrinterDebug_ConvertStatusFlagsToTiles:
+ ld hl, wOAMBuffer + 32 * 4 + 2
+ 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 a, $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 a, $ff
+ jr nz, .asm_ea6e4
+ ld a, [wPrinterStatusFlags]
+ cp a, $ff
+ jr z, .asm_ea6fb
+.asm_ea6e4
+ ld a, [wPrinterHandshake]
+ cp a, $81
+ jr nz, .asm_ea6fb
+ ld a, [wPrinterStatusFlags]
+ cp a, $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
+ ld [rSB], a
+ ld a, $1
+ ld [rSC], a
+ ld a, $81
+ ld [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, wOAMBuffer
+ 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:
+ ld a, [rOBP0]
+ and $3
+ ret
+
+.Pal2:
+ ld a, [rOBP0]
+ and $c
+ srl a
+ srl a
+ ret
+
+.Pal1:
+ ld a, [rOBP0]
+ and $30
+ swap a
+ ret
+
+.Pal3:
+ ld 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/vermilion_gym_trash_cans.asm b/engine/vermilion_gym_trash_cans.asm
new file mode 100755
index 00000000..49dee50c
--- /dev/null
+++ b/engine/vermilion_gym_trash_cans.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]
+ ld [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/yellow_intro.asm b/engine/yellow_intro.asm
new file mode 100755
index 00000000..9c9e26b3
--- /dev/null
+++ b/engine/yellow_intro.asm
@@ -0,0 +1,1081 @@
+PlayIntroScene:
+ ld a, [rIE]
+ push af
+ xor a
+ ld [rIF], a
+ ld a, $f
+ ld [rIE], a
+ ld a, $8
+ ld [rSTAT], a
+ call InitYellowIntroGFXAndMusic
+ call DelayFrame
+.loop
+ ld a, [wYellowIntroCurrentScene]
+ bit 7, a
+ jr nz, .go_to_title_screen
+ call JoypadLowSensitivity
+ ld a, [hJoyPressed]
+ and A_BUTTON | B_BUTTON | 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
+ call YellowIntro_BlankPalettes
+ xor a
+ ld [hLCDCPointer], a
+ call DelayFrame
+ xor a
+ ld [rIF], a
+ pop af
+ ld [rIE], a
+ ld a, $90
+ ld [hWY], a
+ call ClearObjectAnimationBuffers
+ ld hl, wTileMap
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ xor a
+ call Bank3E_FillMemory
+ call YellowIntro_BlankOAMBuffer
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ret
+
+Func_f98a2:
+ ld a, [wOAMBuffer + 8 * 4 + 3]
+ or $1
+ ld [wOAMBuffer + 8 * 4 + 3], a
+ ld a, [wOAMBuffer + 14 * 4 + 3]
+ or $1
+ ld [wOAMBuffer + 14 * 4 + 3], a
+ ld a, [wOAMBuffer + 16 * 4 + 3]
+ or $1
+ ld [wOAMBuffer + 16 * 4 + 3], a
+ ld a, [wOAMBuffer + 18 * 4 + 3]
+ or $1
+ ld [wOAMBuffer + 18 * 4 + 3], a
+ ld a, [wOAMBuffer + 19 * 4 + 3]
+ or $1
+ ld [wOAMBuffer + 19 * 4 + 3], a
+ ret
+
+Func_f98cb:
+ ld a, [wOAMBuffer + 18 * 4 + 3]
+ or $1
+ ld [wOAMBuffer + 18 * 4 + 3], a
+ ld a, [wOAMBuffer + 19 * 4 + 3]
+ or $1
+ ld [wOAMBuffer + 19 * 4 + 3], a
+ ld a, [wOAMBuffer + 20 * 4 + 3]
+ or $1
+ ld [wOAMBuffer + 20 * 4 + 3], a
+ ld a, [wOAMBuffer + 25 * 4 + 3]
+ or $1
+ ld [wOAMBuffer + 25 * 4 + 3], a
+ ld a, [wOAMBuffer + 26 * 4 + 3]
+ or $1
+ ld [wOAMBuffer + 26 * 4 + 3], a
+ ld a, [wOAMBuffer + 28 * 4 + 3]
+ or $1
+ ld [wOAMBuffer + 28 * 4 + 3], 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]
+ ret
+
+YellowIntroScene0:
+ xor a
+ ld [hLCDCPointer], a
+ lb de, $58, $58
+ ld a, $1
+ call YellowIntro_SpawnAnimatedObjectAndSavePointer
+ xor a
+ ld [hSCX], a
+ ld [hSCY], a
+ ld a, $90
+ ld [hWY], a
+ ld a, $e4
+ ld [rBGP], a
+ ld [rOBP0], a
+ ld a, $c4
+ ld [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_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
+ ld [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
+ ld a, [hGBC]
+ 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
+ ld [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
+ ld [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
+ ld a, [hSCX]
+ cp $68
+ ret z
+ add $4
+ ld [hSCX], a
+ ret
+
+.expired
+ call MaskAllAnimatedObjectStructs
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene4:
+ call YellowIntro_BlankPalsDelay2AndDisableLCD
+ ld c, $5
+ call UpdateMusicCTimes
+ ld a, [hGBC]
+ and a
+ jr z, .dmg_sgb
+ ; We can actually set palettes!
+ ld hl, $98d4
+ ld de, $20
+ ld b, $6
+ ld a, $1
+ ld [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
+ ld [rVBK], a
+.dmg_sgb
+ xor a
+ ld [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, rSCY - $ff00
+ ld [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
+ ld [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
+ ld [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/unknown_f9b6e.map"
+Unkn_f9be6: INCBIN "gfx/unknown_f9be6.map"
+Unkn_f9bf2: INCBIN "gfx/unknown_f9bf2.map"
+
+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, YellowIntroCloudGFX1
+ add hl, de
+ ld a, l
+ ld [H_VBCOPYSRC], a
+ ld a, h
+ ld [H_VBCOPYSRC + 1], a
+ xor a
+ ld [H_VBCOPYDEST], a
+ ld a, $96
+ ld [H_VBCOPYDEST + 1], a
+ ld a, $4
+ ld [H_VBCOPYSIZE], a
+ ret
+
+.expired
+ call YellowIntro_MaskCurrentAnimatedObjectStruct
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroCloudGFX1: INCBIN "gfx/unknown_f9c2c.2bpp"
+YellowIntroCloudGFX2: INCBIN "gfx/unknown_f9c6c.2bpp" ; indirectly referenced
+
+YellowIntroScene12:
+ call YellowIntro_BlankPalsDelay2AndDisableLCD
+ ld c, $5
+ call UpdateMusicCTimes
+ xor a
+ ld [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
+ ld [rBGP], a
+ ld [rOBP0], a
+ and $f0
+ ld [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
+ ret
+
+.expired
+ call MaskAllAnimatedObjectStructs
+ call YellowIntro_BlankOAMBuffer
+ ld hl, wTileMap
+ ld bc, $50
+ ld a, $1
+ call Bank3E_FillMemory
+ coord hl, 0, 4
+ ld bc, CopyVideoDataAlternate
+ xor a
+ call Bank3E_FillMemory
+ coord hl, 0, 14
+ ld bc, $50
+ ld a, $1
+ call Bank3E_FillMemory
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld a, $e4
+ ld [rOBP0], a
+ ld [rBGP], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ lb de, $58, $58
+ ld a, $7
+ call YellowIntro_SpawnAnimatedObjectAndSavePointer
+ call YellowIntro_NextScene
+ ld a, $28
+ ld [wYellowIntroSceneTimer], a
+ ret
+
+YellowIntroScene15:
+ call YellowIntro_CheckFrameTimerDecrement
+ jr c, .expired
+ ld a, [wYellowIntroSceneTimer]
+ and $3
+ ret nz
+ ld a, [rOBP0]
+ xor $ff
+ ld [rOBP0], a
+ ld a, [rBGP]
+ xor $3
+ ld [rBGP], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ ret
+
+.expired
+ xor a
+ ld [hLCDCPointer], a
+ ld a, $e4
+ ld [rBGP], a
+ ld [rOBP0], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call YellowIntro_NextScene
+YellowIntroScene16:
+ ld de, YellowIntroPalSequence_f9e0a
+ call YellowIntro_LoadDMGPalAndIncrementCounter
+ jr c, .expired
+ ld [rOBP0], a
+ ld [rBGP], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_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
+ scf
+ ret
+
+YellowIntro_LoadDMGPalAndIncrementCounter:
+ ld hl, wYellowIntroSceneTimer
+ ld a, [hl]
+ 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
+ ld [rBGP], a
+ ld [rOBP0], a
+ ld [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
+ call DelayFrame
+ call DelayFrame
+ call DisableLCD
+ ret
+
+Func_f9e9a:
+ ld e, a
+ callab YellowIntroPaletteAction
+ xor a
+ ld [hSCX], a
+ ld [hSCY], a
+ ld a, $90
+ ld [hWY], a
+ ld a, $e3
+ ld [rLCDC], a
+ ld a, $e4
+ ld [rBGP], a
+ ld [rOBP0], a
+ ld a, $e0
+ ld [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_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
+ ld [H_VBCOPYSRC], a
+ ld a, wLYOverridesBuffer / $100
+ ld [H_VBCOPYSRC + 1], a
+ ld a, $10
+ ld [H_VBCOPYDEST], a
+ ld a, wLYOverrides / $100
+ ld [H_VBCOPYDEST + 1], a
+ ld a, $7
+ ld [H_VBCOPYSIZE], a
+ ret
+
+InitYellowIntroGFXAndMusic:
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld [hSCX], a
+ ld [hSCY], a
+ ld [H_AUTOBGTRANSFERDEST], a
+ ld a, $98
+ ld [H_AUTOBGTRANSFERDEST + 1], a
+ call YellowIntro_BlankTileMap
+ ld hl, wTileMap
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ ld a, $1
+ call Bank3E_FillMemory
+ coord hl, 0, 4
+ ld bc, CopyVideoDataAlternate
+ xor a
+ call Bank3E_FillMemory
+ ld a, $1
+ ld [H_AUTOBGTRANSFERENABLED], a
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ xor a
+ ld [H_AUTOBGTRANSFERENABLED], a
+ ld de, $6b5a
+ ld hl, $8000
+ ld bc, $3eff
+ call CopyVideoData
+ ld de, $635a
+ ld hl, $9000
+ ld bc, $3e80
+ call CopyVideoData
+ call ClearObjectAnimationBuffers
+ call LoadYellowIntroObjectAnimationDataPointers
+ ld b, $8
+ 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, YellowIntro_AnimatedObjectSpawnStateData % $100
+ ld [wAnimatedObjectSpawnStateDataPointer], a
+ ld a, YellowIntro_AnimatedObjectSpawnStateData / $100
+ ld [wAnimatedObjectSpawnStateDataPointer + 1], a
+ ld a, YellowIntro_AnimatedObjectJumptable % $100
+ ld [wAnimatedObjectJumptablePointer], a
+ ld a, YellowIntro_AnimatedObjectJumptable / $100
+ ld [wAnimatedObjectJumptablePointer + 1], a
+ ld a, YellowIntro_AnimatedObjectOAMData % $100
+ ld [wAnimatedObjectOAMDataPointer], a
+ ld a, YellowIntro_AnimatedObjectOAMData / $100
+ ld [wAnimatedObjectOAMDataPointer + 1], a
+ ld a, YellowIntro_AnimatedObjectFramesData % $100
+ ld [wAnimatedObjectFramesDataPointer], a
+ ld a, YellowIntro_AnimatedObjectFramesData / $100
+ ld [wAnimatedObjectFramesDataPointer + 1], a
+ ret
+
+YellowIntro_BlankTileMap:
+ ld hl, wTileMap
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ 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, wOAMBuffer
+ ld bc, wOAMBufferEnd - wOAMBuffer
+ xor a
+ call Bank3E_FillMemory
+ ret
+
+YellowIntro_BlankPalettes:
+ xor a
+ ld [rBGP], a
+ ld [rOBP0], a
+ ld [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_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_wave $100