summaryrefslogtreecommitdiff
path: root/engine
diff options
context:
space:
mode:
Diffstat (limited to 'engine')
-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.asm491
-rw-r--r--engine/bank3e.asm5
-rw-r--r--engine/bank3f.asm23
-rwxr-xr-xengine/battle/animations.asm272
-rw-r--r--engine/battle/bank3d_battle.asm292
-rw-r--r--engine/battle/battle_transitions.asm8
-rw-r--r--engine/battle/common_text.asm16
-rwxr-xr-xengine/battle/core.asm579
-rw-r--r--engine/battle/decrement_pp.asm2
-rw-r--r--engine/battle/draw_hud_pokeball_gfx.asm10
-rw-r--r--engine/battle/effects.asm95
-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
-rwxr-xr-xengine/battle/misc.asm19
-rw-r--r--engine/battle/move_effects/heal.asm6
-rw-r--r--engine/battle/move_effects/reflect_light_screen.asm6
-rw-r--r--engine/battle/move_effects/transform.asm11
-rwxr-xr-xengine/battle/read_trainer_party.asm101
-rwxr-xr-xengine/battle/safari_zone.asm10
-rw-r--r--engine/battle/scale_sprites.asm7
-rw-r--r--engine/battle/trainer_ai.asm27
-rw-r--r--engine/battle/wild_encounters.asm7
-rw-r--r--engine/bg_map_attributes.asm219
-rw-r--r--engine/debug/debug_menu.asm69
-rw-r--r--engine/debug/debug_party.asm149
-rwxr-xr-xengine/diploma_3a.asm168
-rw-r--r--engine/events/black_out.asm2
-rwxr-xr-xengine/events/card_key.asm9
-rw-r--r--[-rwxr-xr-x]engine/events/diploma.asm103
-rwxr-xr-xengine/events/elevator.asm6
-rwxr-xr-xengine/events/evolve_trade.asm44
-rwxr-xr-xengine/events/give_pokemon.asm5
-rwxr-xr-xengine/events/hidden_items.asm17
-rw-r--r--engine/events/hidden_objects/bills_house_pc.asm7
-rw-r--r--engine/events/hidden_objects/cinnabar_gym_quiz.asm56
-rw-r--r--engine/events/hidden_objects/fanclub_pictures.asm23
-rw-r--r--engine/events/hidden_objects/museum_fossils.asm29
-rw-r--r--engine/events/hidden_objects/museum_fossils2.asm28
-rw-r--r--engine/events/hidden_objects/oaks_lab_email.asm3
-rw-r--r--engine/events/hidden_objects/route_15_binoculars.asm5
-rw-r--r--engine/events/hidden_objects/safari_game.asm7
-rw-r--r--engine/events/hidden_objects/school_blackboard.asm3
-rw-r--r--engine/events/hidden_objects/vermilion_gym_trash.asm77
-rwxr-xr-xengine/events/in_game_trades.asm58
-rw-r--r--engine/events/poison.asm41
-rwxr-xr-xengine/events/pokecenter.asm101
-rwxr-xr-xengine/events/pokedex_rating.asm102
-rwxr-xr-xengine/events/prize_menu.asm9
-rwxr-xr-xengine/events/vending_machine.asm3
-rwxr-xr-xengine/gfx/hp_bar.asm8
-rwxr-xr-xengine/gfx/mon_icons.asm20
-rwxr-xr-xengine/gfx/palettes.asm579
-rw-r--r--[-rwxr-xr-x]engine/gfx/screen_effects.asm10
-rw-r--r--engine/gfx/sprite_oam.asm163
-rw-r--r--engine/items/inventory.asm9
-rwxr-xr-xengine/items/item_effects.asm534
-rwxr-xr-xengine/items/tms.asm6
-rwxr-xr-xengine/items/town_map.asm23
-rw-r--r--engine/joypad.asm38
-rwxr-xr-xengine/link/cable_club.asm59
-rwxr-xr-xengine/link/cable_club_npc.asm59
-rw-r--r--engine/link/print_waiting_text.asm11
-rw-r--r--engine/math/bcd.asm10
-rw-r--r--engine/menus/display_text_id_init.asm9
-rw-r--r--engine/menus/draw_start_menu.asm8
-rwxr-xr-xengine/menus/league_pc.asm5
-rw-r--r--engine/menus/link_menu.asm910
-rwxr-xr-xengine/menus/main_menu.asm451
-rwxr-xr-xengine/menus/naming_screen.asm30
-rw-r--r--engine/menus/options.asm443
-rwxr-xr-xengine/menus/party_menu.asm22
-rwxr-xr-xengine/menus/players_pc.asm7
-rwxr-xr-xengine/menus/pokedex.asm354
-rwxr-xr-xengine/menus/save.asm170
-rwxr-xr-xengine/menus/start_sub_menus.asm37
-rw-r--r--engine/menus/text_box.asm36
-rwxr-xr-xengine/movie/credits.asm282
-rwxr-xr-xengine/movie/evolution.asm8
-rwxr-xr-xengine/movie/hall_of_fame.asm37
-rwxr-xr-xengine/movie/intro.asm355
-rwxr-xr-xengine/movie/oak_speech/clear_save.asm4
-rw-r--r--engine/movie/oak_speech/init_player_data.asm5
-rwxr-xr-xengine/movie/oak_speech/oak_speech.asm45
-rwxr-xr-xengine/movie/oak_speech/oak_speech2.asm6
-rwxr-xr-xengine/movie/splash.asm52
-rwxr-xr-xengine/movie/title.asm457
-rwxr-xr-xengine/movie/title2.asm4
-rwxr-xr-xengine/movie/trade.asm28
-rw-r--r--engine/overworld/advance_player_sprite.asm244
-rwxr-xr-xengine/overworld/auto_movement.asm52
-rwxr-xr-xengine/overworld/cut.asm5
-rwxr-xr-xengine/overworld/cut2.asm2
-rw-r--r--engine/overworld/dungeon_warps.asm15
-rwxr-xr-xengine/overworld/dust_smoke.asm2
-rwxr-xr-xengine/overworld/elevator.asm6
-rwxr-xr-xengine/overworld/emotion_bubbles.asm24
-rwxr-xr-xengine/overworld/healing_machine.asm27
-rwxr-xr-xengine/overworld/hidden_objects.asm34
-rwxr-xr-xengine/overworld/ledges.asm16
-rwxr-xr-xengine/overworld/map_sprites.asm604
-rw-r--r--engine/overworld/missable_objects.asm11
-rw-r--r--engine/overworld/movement.asm385
-rwxr-xr-xengine/overworld/npc_movement_2.asm24
-rw-r--r--engine/overworld/pathfinding.asm8
-rwxr-xr-xengine/overworld/player_animations.asm26
-rw-r--r--engine/overworld/player_state.asm29
-rw-r--r--engine/overworld/push_boulder.asm2
-rw-r--r--engine/overworld/sprite_collisions.asm46
-rw-r--r--engine/overworld/tilesets.asm21
-rwxr-xr-xengine/overworld/turn_sprite.asm25
-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
-rw-r--r--engine/pokemon/add_mon.asm6
-rw-r--r--engine/pokemon/bills_pc.asm82
-rwxr-xr-xengine/pokemon/evos_moves.asm219
-rwxr-xr-xengine/pokemon/learn_move.asm42
-rw-r--r--engine/pokemon/load_mon_data.asm21
-rwxr-xr-xengine/pokemon/status_screen.asm28
-rwxr-xr-xengine/predefs.asm8
-rw-r--r--engine/printer.asm999
-rwxr-xr-xengine/printer/serial.asm621
-rwxr-xr-xengine/slots/slot_machine.asm21
-rwxr-xr-xengine/surfing_minigame.asm2862
-rwxr-xr-xengine/unknown_ea3ea.asm973
-rwxr-xr-xengine/vermilion_gym_trash_cans.asm108
-rwxr-xr-xengine/yellow_intro.asm1081
136 files changed, 18619 insertions, 3672 deletions
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..8eb32837
--- /dev/null
+++ b/engine/bank3c.asm
@@ -0,0 +1,189 @@
+INCLUDE "engine/pikachu_pcm.asm"
+INCLUDE "engine/overworld/advance_player_sprite.asm"
+
+INCLUDE "engine/events/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
+ callfar GetPikachuFacingDirectionAndReturnToE
+ pop bc
+ pop hl
+ ld a, b
+ cp e
+ ret nz
+ push hl
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ callfar LoadPikachuShadowIntoVRAM
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ pop hl
+ call ApplyPikachuMovementData
+ callfar RefreshPikachuFollow
+ ret
+
+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:
+ text_far _NurseChanseyText
+ text_end
+
+INCLUDE "engine/movie/credits.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/maps/headers/BeachHouse.asm"
+INCLUDE "scripts/BeachHouse.asm"
+BeachHouse_Blocks:
+INCBIN "maps/BeachHouse.blk"
+INCLUDE "data/maps/objects/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..e929e44e
--- /dev/null
+++ b/engine/bank3d.asm
@@ -0,0 +1,491 @@
+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:
+ hlcoord 0, 5
+ ld c, 0
+.loop1
+ inc c
+ ld a, c
+ cp 9
+ ret z
+ ld d, 7 * 13
+ push bc
+ push hl
+.loop2
+ call .PlaceColumn
+ dec hl
+ ld a, d
+ sub 7
+ ld d, a
+ dec c
+ jr nz, .loop2
+ ld c, 2
+ call DelayFrames
+ pop hl
+ pop bc
+ inc hl
+ jr .loop1
+
+.PlaceColumn:
+ push hl
+ push de
+ push bc
+ ld e, 7
+.loop3
+ ld a, d
+ cp 7 * 7
+ jr nc, .okay
+ ld a, $7f
+.okay
+ ld [hl], a
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ inc d
+ dec e
+ jr nz, .loop3
+ pop bc
+ pop de
+ pop hl
+ ret
+
+INCLUDE "engine/battle/decrement_pp.asm"
+
+ModifyPikachuHappiness::
+ ld a, d
+ cp PIKAHAPPY_GYMLEADER
+ jr z, .checkanywhereinparty
+ cp PIKAHAPPY_WALKING
+ jr z, .checkanywhereinparty
+ push de
+ callfar IsThisPartymonStarterPikachu_Party
+ pop de
+ ret nc
+ jr .proceed
+
+.checkanywhereinparty
+ push de
+ callfar 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 ; Fainted to opponent at least 30 levels higher
+ db -10, -10, -20 ; Traded away
+
+PikachuMoods:
+ ; Increase
+ db $8a ; Gained a level
+ db $83 ; HP restore
+ db $80 ; Teach TM/HM
+ db $80 ; Challenged Gym Leader
+ db $94 ; Unknown (d = 5)
+ db $80 ; Unknown (d = 6)
+ ; Decrease
+ db $62 ; Deposited
+ db $6c ; Fainted
+ db $62 ; Unknown (d = 9)
+ db $6c ; Unknown (d = 10)
+ db $00 ; Unknown (d = 11)
+
+RedPicBack: INCBIN "gfx/player/redb.pic"
+OldManPic: INCBIN "gfx/battle/oldman.pic"
+ProfOakPicBack: INCBIN "gfx/battle/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:
+ hlcoord 2, 1
+ ld de, TitleScreenPokemonLogoTilemap
+ lb bc, 7, 16
+ call Bank3D_CopyBox
+ ret
+
+TitleScreen_PlacePikaSpeechBubble:
+ hlcoord 6, 4
+ ld de, TitleScreenPikaBubbleTilemap
+ lb bc, 4, 7
+ call Bank3D_CopyBox
+ hlcoord 9, 8
+ ld [hl], $64
+ inc hl
+ ld [hl], $65
+ ret
+
+TitleScreen_PlacePikachu:
+ hlcoord 4, 8
+ ld de, TitleScreenPikachuTilemap
+ lb bc, 9, 12
+ call Bank3D_CopyBox
+ hlcoord 16, 10
+ ld [hl], $96
+ hlcoord 16, 11
+ ld [hl], $9d
+ hlcoord 16, 12
+ ld [hl], $a7
+ hlcoord 16, 13
+ ld [hl], $b1
+ ld hl, TitleScreenPikachuEyesOAMData
+ ld de, 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/title/pokemon_logo.2bpp"
+PokemonLogoGraphicsEnd:
+YellowLogoGraphics: INCBIN "gfx/yellow_titlescreen.2bpp"
+YellowLogoGraphicsEnd:
+
+INCLUDE "engine/menus/link_menu.asm"
+
+HandleMenuInputDouble:
+ xor a
+ ld [wPartyMenuAnimMonEnabled], a
+
+HandleMenuInputPokemonSelectionDouble:
+ ldh a, [hDownArrowBlinkCount1]
+ push af
+ ldh a, [hDownArrowBlinkCount2]
+ push af ; save existing values on stack
+ xor a
+ ldh [hDownArrowBlinkCount1], a ; blinking down arrow timing value 1
+ ld a, $06
+ ldh [hDownArrowBlinkCount2], a ; blinking down arrow timing value 2
+.loop1
+ xor a
+ ld [wAnimCounter], a ; counter for pokemon shaking animation
+ call .UpdateCursorTile
+ call JoypadLowSensitivity
+ ldh a, [hJoy5]
+ and a ; was a key pressed?
+ jr nz, .keyPressed
+ pop af
+ ldh [hDownArrowBlinkCount2], a
+ pop af
+ ldh [hDownArrowBlinkCount1], a ; restore previous values
+ xor a
+ ld [wMenuWrappingEnabled], a ; disable menu wrapping
+ ret
+.keyPressed
+ xor a
+ ld [wCheckFor180DegreeTurn], a
+ ldh a, [hJoy5]
+ ld b, a
+ bit 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
+ ldh a, [hJoy5]
+ and A_BUTTON | B_BUTTON
+ jr z, .skipPlayingSound
+.AButtonOrBButtonPressed
+ ld a, SFX_PRESS_AB
+ call PlaySound ; play sound
+.skipPlayingSound
+ pop af
+ ldh [hDownArrowBlinkCount2], a
+ pop af
+ ldh [hDownArrowBlinkCount1], a ; restore previous values
+ ldh a, [hJoy5]
+ ret
+
+.UpdateCursorTile:
+ ld a, [wTopMenuItemY]
+ and a
+ jr z, .asm_f5ac0
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH
+.loop
+ add hl, bc
+ dec a
+ jr nz, .loop
+.asm_f5ac0
+ ld a, [wTopMenuItemX]
+ ld b, $0
+ ld c, a
+ add hl, bc
+ push hl
+ ld a, [wLastMenuItem]
+ and a
+ jr z, .asm_f5ad5
+ ld bc, $28
+.loop2
+ add hl, bc
+ dec a
+ jr nz, .loop2
+.asm_f5ad5
+ ld a, [hl]
+ cp "▶"
+ jr nz, .asm_f5ade
+ ld a, [wTileBehindCursor]
+ ld [hl], a
+.asm_f5ade
+ pop hl
+ ld a, [wCurrentMenuItem]
+ and a
+ jr z, .asm_f5aec
+ ld bc, $28
+.loop3
+ add hl, bc
+ dec a
+ jr nz, .loop3
+.asm_f5aec
+ ld a, [hl]
+ cp "▶"
+ jr z, .asm_f5af4
+ ld [wTileBehindCursor], a
+.asm_f5af4
+ ld a, "▶"
+ ld [hl], a
+ ld a, l
+ ld [wMenuCursorLocation], a
+ ld a, h
+ ld [wMenuCursorLocation + 1], a
+ ld a, [wCurrentMenuItem]
+ ld [wLastMenuItem], a
+ ret
+
+INCLUDE "engine/overworld/field_move_messages.asm"
+
+INCLUDE "engine/items/inventory.asm"
+
+INCLUDE "gfx/trainer_card.asm"
+
+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/wild/super_rod.asm"
+INCLUDE "engine/battle/bank3d_battle.asm"
+INCLUDE "engine/items/tm_prices.asm"
+INCLUDE "engine/math/multiply_divide.asm"
+INCLUDE "engine/events/give_pokemon.asm"
+INCLUDE "engine/battle/get_trainer_name.asm"
+INCLUDE "engine/math/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..c26e9834
--- /dev/null
+++ b/engine/bank3f.asm
@@ -0,0 +1,23 @@
+INCLUDE "data/maps/songs.asm"
+INCLUDE "data/maps/map_header_pointers.asm"
+INCLUDE "data/maps/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"
+ClefairySprite: INCBIN "gfx/sprites/clefairy.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 e10b5e0d..4508dbaa 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 ; SUBANIMTYPE_HVFLIP
@@ -46,13 +48,22 @@ DrawFrameBlock:
.finishCopying ; finish copying values to OAM (when subanimation not transformed)
add [hl] ; X offset
ld [de], a ; store X
+ cp 88
+ jr c, .asm_78056
+ ld a, [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]
ldh [rOBP0], a
+ call UpdateGBCPal_OBP0
call LoadAnimationTileset
call LoadSubanimation
call PlaySubanimation
pop af
ldh [rOBP0], a
+ call UpdateGBCPal_OBP0
.nextAnimationCommand
pop hl
jr .animationLoop
@@ -366,12 +395,7 @@ AnimationTileset2:
INCBIN "gfx/battle/attack_anim_2.2bpp"
SlotMachineTiles2:
-IF DEF(_RED)
- INCBIN "gfx/slots/red_slots_2.2bpp"
-ENDC
-IF DEF(_BLUE)
- INCBIN "gfx/slots/blue_slots_2.2bpp"
-ENDC
+ INCBIN "gfx/slots/slots_2.2bpp"
SlotMachineTiles2End:
MoveAnimation:
@@ -537,6 +561,8 @@ SetAnimationPalette:
ldh [rOBP0], a
ld a, $6c
ldh [rOBP1], a
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
ret
.notSGB
ld a, $e4
@@ -544,6 +570,28 @@ SetAnimationPalette:
ldh [rOBP0], a
ld a, $6c
ldh [rOBP1], a
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
+ ret
+
+Func_78e98:
+ call SaveScreenTilesToBuffer2
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call ClearScreen
+ ld h, vBGMap0 / $100
+ call WriteLowerByteOfBGMapAndEnableBGTransfer
+ call Delay3
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call LoadScreenTilesFromBuffer2
+ ld h, vBGMap1 / $100
+
+WriteLowerByteOfBGMapAndEnableBGTransfer:
+ ld l, vBGMap0 & $ff
+ call BattleAnimCopyTileMapToVRAM
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
ret
PlaySubanimation:
@@ -659,6 +707,7 @@ DoBallTossSpecialEffects:
ldh a, [rOBP0]
xor %00111100 ; complement colors 1 and 2
ldh [rOBP0], a
+ call UpdateGBCPal_OBP0
.skipFlashingEffect
ld a, [wSubAnimCounter]
cp 11 ; is it the beginning of the subanimation?
@@ -948,6 +997,7 @@ AnimationFlashScreenLong:
cp $01 ; is it the end of the palettes?
jr z, .endOfPalettes
ldh [rBGP], a
+ call UpdateGBCPal_BGP
call FlashScreenLongDelay
jr .innerLoop
.endOfPalettes
@@ -1010,14 +1060,17 @@ AnimationFlashScreen:
push af ; save initial palette
ld a, %00011011 ; 0, 1, 2, 3 (inverted colors)
ldh [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 2
call DelayFrames
xor a ; white out background
ldh [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 2
call DelayFrames
pop af
ldh [rBGP], a ; restore initial palette
+ call UpdateGBCPal_BGP
ret
AnimationDarkScreenPalette:
@@ -1063,6 +1116,7 @@ SetAnimationBGPalette:
ld a, c
.next
ldh [rBGP], a
+ call UpdateGBCPal_BGP
ret
ld b, $5
@@ -1107,15 +1161,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
@@ -1258,16 +1327,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
@@ -1319,7 +1402,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
@@ -1472,6 +1555,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
@@ -1480,9 +1565,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
@@ -1784,7 +1880,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
@@ -1794,10 +1890,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
@@ -1934,18 +2028,24 @@ AnimationSubstitute:
CopyMonsterSpriteData:
ld bc, 1 tiles
ld a, BANK(MonsterSprite)
- jp FarCopyData2
+ jp FarCopyData
HideSubstituteShowMonAnim:
ldh a, [hWhoseTurn]
and a
ld hl, wPlayerMonMinimized
+ ld de, wPlayerBattleStatus1
+ ld bc, wPlayerMoveNum
ld a, [wPlayerBattleStatus2]
jr z, .next1
ld hl, wEnemyMonMinimized
+ ld de, wEnemyBattleStatus1
+ ld bc, wEnemyMoveNum
ld a, [wEnemyBattleStatus2]
.next1
push hl
+ push de
+ push bc
; if the substitute broke, slide it down, else slide it offscreen horizontally
bit HAS_SUBSTITUTE_UP, a
jr nz, .substituteStillUp
@@ -1954,12 +2054,65 @@ HideSubstituteShowMonAnim:
.substituteStillUp
call AnimationSlideMonOff
.next2
+ pop bc
+ pop de
+ ld a, [de]
+ bit INVULNERABLE, a
pop hl
+ jr nz, .invulnerable
+ ld a, [bc]
+ cp FLY
+ jr z, .flyOrDig
+ cp DIG
+ jr z, .flyOrDig
+.invulnerable
ld a, [hl]
and a
jp nz, AnimationMinimizeMon
call AnimationFlashMonPic
jp AnimationShowMonPic
+.flyOrDig
+ ldh a, [hWhoseTurn]
+ and a
+ jr nz, .enemy
+ ld a, [wPlayerMonMinimized]
+ and a
+ jr nz, .monIsMinimized
+ ld a, [wBattleMonSpecies]
+ ld [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
@@ -2027,6 +2180,23 @@ AnimationHideEnemyMonPic:
ldh [hAutoBGTransferEnabled], a
jp Delay3
+Func_79929:
+ ld hl, wPlayerMonMinimized
+ ldh a, [hWhoseTurn]
+ and a
+ jr z, .playerTurn
+ ld hl, wEnemyMonMinimized
+.playerTurn
+ ld a, [hl]
+ and a
+ jr z, .notMinimized
+ call AnimationMinimizeMon
+ ret
+.notMinimized
+ call AnimationFlashMonPic
+ call AnimationShowMonPic
+ ret
+
InitMultipleObjectsOAM:
; Writes c OAM entries with tile d.
; Sets their Y coordinates to sequential multiples of 8, starting from 0.
@@ -2048,6 +2218,8 @@ InitMultipleObjectsOAM:
jr nz, .loop
ret
+ ret ; unreferenced
+
AnimationHideMonPic:
; Hides the mon's sprite.
ldh a, [hWhoseTurn]
@@ -2074,7 +2246,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
@@ -2270,17 +2442,13 @@ INCLUDE "data/tilemaps.asm"
AnimationLeavesFalling:
; Makes leaves float down from the top of the screen. This is used
; in Razor Leaf's animation.
- ldh a, [rOBP0]
- push af
ld a, [wAnimPalette]
ldh [rOBP0], a
+ call UpdateGBCPal_OBP0
ld d, $37 ; leaf tile
ld a, 3 ; number of leaves
ld [wNumFallingObjects], a
- call AnimationFallingObjects
- pop af
- ldh [rOBP0], a
- ret
+ jp AnimationFallingObjects
AnimationPetalsFalling:
; Makes lots of petals fall down from the top of the screen. It's used in
@@ -2335,6 +2503,8 @@ FallingObjects_UpdateOAMEntry:
; movement byte.
ld hl, wOAMBuffer
add hl, de
+ ld a, $1
+ ld [wdef5], a
ld a, [hl]
inc a
inc a
@@ -2343,6 +2513,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
@@ -2359,6 +2535,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
@@ -2368,9 +2551,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
@@ -2410,7 +2603,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
@@ -2426,7 +2619,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.
@@ -2455,6 +2648,14 @@ AnimationShakeEnemyHUD:
ld hl, vBGMap1 - $20 * 7
call BattleAnimCopyTileMapToVRAM
+; update BGMap attributes
+ ldh a, [hGBC]
+ and a
+ jr z, .notGBC
+ ld c, 13
+ farcall 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
@@ -2488,13 +2689,18 @@ AnimationShakeEnemyHUD:
ldh [hWY], a
ld hl, vBGMap1
call BattleAnimCopyTileMapToVRAM
+; update BGMap attributes
+ ldh a, [hGBC]
+ and a
+ jr z, .notGBC2
+ ld c, 11
+ farcall LoadBGMapAttributes
+.notGBC2
xor a
ldh [hWY], a
call SaveScreenTilesToBuffer1
ld hl, vBGMap0
call BattleAnimCopyTileMapToVRAM
- call ClearScreen
- call Delay3
call LoadScreenTilesFromBuffer1
ld hl, vBGMap1
jp BattleAnimCopyTileMapToVRAM
@@ -2583,7 +2789,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..48c3cde3
--- /dev/null
+++ b/engine/battle/bank3d_battle.asm
@@ -0,0 +1,292 @@
+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
+ ldh a, [hJoyHeld]
+ bit 1, a ; B button pressed?
+ ret nz
+.asm_3ef2f
+ ld a, [wNumberOfNoRandomBattleStepsLeft]
+ and a
+ ret nz
+ callfar TryDoWildEncounter
+ ret nz
+InitBattleCommon:
+ ld a, [wMapPalOffset]
+ push af
+ ld hl, wLetterPrintingDelayFlags
+ ld a, [hl]
+ push af
+ res 1, [hl]
+ call InitBattleVariables
+ ld a, [wEnemyMonSpecies2]
+ sub OPP_ID_OFFSET
+ jp c, InitWildBattle
+ ld [wTrainerClass], a
+ call GetTrainerInformation
+ callfar ReadTrainer
+ callfar DoBattleTransitionAndInitBattleVariables
+ call _LoadTrainerPic
+ xor a
+ ld [wEnemyMonSpecies2], a
+ ldh [hStartTileID], a
+ dec a
+ ld [wAICount], a
+ hlcoord 12, 0
+ predef CopyUncompressedPicToTilemap
+ ld a, $ff
+ ld [wEnemyMonPartyPos], a
+ ld a, $2
+ ld [wIsInBattle], a
+
+; Is this a major story battle?
+ ld a, [wLoneAttackNo]
+ and a
+ jp z, _InitBattleCommon
+ callabd_ModifyPikachuHappiness PIKAHAPPY_GYMLEADER ; useless since already in bank3d
+ jp _InitBattleCommon
+
+InitWildBattle:
+ ld a, $1
+ ld [wIsInBattle], a
+ callfar LoadEnemyMonData
+ callfar DoBattleTransitionAndInitBattleVariables
+ ld a, [wCurOpponent]
+ cp RESTLESS_SOUL
+ jr z, .isGhost
+ callfar IsGhostBattle
+ jr nz, .isNoGhost
+.isGhost
+ ld hl, wMonHSpriteDim
+ ld a, $66
+ ld [hli], a ; write sprite dimensions
+ ld bc, GhostPic
+ ld a, c
+ ld [hli], a ; write front sprite pointer
+ ld [hl], b
+ ld hl, wEnemyMonNick ; set name to "GHOST"
+ ld 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
+ ldh [hStartTileID], a
+ hlcoord 12, 0
+ predef CopyUncompressedPicToTilemap
+
+; common code that executes after init battle code specific to trainer or wild battles
+_InitBattleCommon:
+ ld b, SET_PAL_BATTLE_BLACK
+ call RunPaletteCommand
+ callfar SlidePlayerAndEnemySilhouettesOnScreen
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ld hl, .emptyString
+ call PrintText
+ call SaveScreenTilesToBuffer1
+ call ClearScreen
+ ld a, $98
+ ldh [hAutoBGTransferDest + 1], a
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call Delay3
+ ld a, $9c
+ ldh [hAutoBGTransferDest + 1], a
+ call LoadScreenTilesFromBuffer1
+ hlcoord 9, 7
+ lb bc, 5, 10
+ call ClearScreenArea
+ hlcoord 1, 0
+ lb bc, 4, 10
+ call ClearScreenArea
+ call ClearSprites
+ ld a, [wIsInBattle]
+ dec a ; is it a wild battle?
+ ld hl, DrawEnemyHUDAndHPBar
+ ld b, BANK(DrawEnemyHUDAndHPBar)
+ call z, Bankswitch ; draw enemy HUD and HP bar if it's a wild battle
+ callfar StartBattle
+ callfar EndOfBattle
+ pop af
+ ld [wLetterPrintingDelayFlags], a
+ pop af
+ ld [wMapPalOffset], a
+ ld a, [wSavedTilesetType]
+ ldh [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
+ hlcoord 1, 5
+ lb bc, 7, 8
+ call ClearScreenArea
+ ld hl, wMonHBackSprite - wMonHeader
+ call UncompressMonSprite
+ predef ScaleSpriteByTwo
+ ld de, vBackPic
+ call InterlaceMergeSpriteBuffers ; combine the two buffers to a single 2bpp sprite
+ ld hl, vSprites
+ ld de, vBackPic
+ ld c, (2*SPRITEBUFFERSIZE)/16 ; count of 16-byte chunks to be copied
+ ldh a, [hLoadedROMBank]
+ ld b, a
+ jp CopyVideoData
+
+AnimateSendingOutMon:
+ ld a, [wPredefRegisters]
+ ld h, a
+ ld a, [wPredefRegisters + 1]
+ ld l, a
+ ldh a, [hStartTileID]
+ ldh [hDownArrowBlinkCount1], 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
+ ldh a, [hDownArrowBlinkCount1]
+ add $31
+ jr CopyUncompressedPicToHL
+
+CopyUncompressedPicToTilemap:
+ ld a, [wPredefRegisters]
+ ld h, a
+ ld a, [wPredefRegisters + 1]
+ ld l, a
+ ldh a, [hStartTileID]
+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/move_effects/focus_energy.asm"
+INCLUDE "engine/battle/move_effects/heal.asm"
+INCLUDE "engine/battle/move_effects/transform.asm"
+INCLUDE "engine/battle/move_effects/reflect_light_screen.asm"
+INCLUDE "engine/battle/move_effects/mist.asm"
+INCLUDE "engine/battle/move_effects/one_hit_ko.asm"
+INCLUDE "engine/battle/move_effects/pay_day.asm"
+INCLUDE "engine/battle/move_effects/paralyze.asm"
diff --git a/engine/battle/battle_transitions.asm b/engine/battle/battle_transitions.asm
index 90e99f98..82c3318c 100644
--- a/engine/battle/battle_transitions.asm
+++ b/engine/battle/battle_transitions.asm
@@ -163,6 +163,9 @@ BattleTransition_BlackScreen:
ldh [rBGP], a
ldh [rOBP0], a
ldh [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
ret
; for non-dungeon trainer battles
@@ -326,6 +329,7 @@ BattleTransition_FlashScreen_:
cp 1
jr z, .done
ldh [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 2
call DelayFrames
jr .loop
@@ -351,7 +355,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
@@ -385,7 +389,7 @@ BattleTransition_Shrink:
; used for high level trainer dungeon battles
BattleTransition_Split:
- ld c, SCREEN_HEIGHT / 2
+ ld c, 9
xor a
ldh [hAutoBGTransferEnabled], a
.loop
diff --git a/engine/battle/common_text.asm b/engine/battle/common_text.asm
index 0e270424..95c06bf5 100644
--- a/engine/battle/common_text.asm
+++ b/engine/battle/common_text.asm
@@ -8,8 +8,20 @@ PrintBeginningBattleText:
cp POKEMON_TOWER_7F + 1
jr c, .pokemonTower
.notPokemonTower
+ ld a, [wBattleType]
+ cp BATTLE_TYPE_PIKACHU
+ jr nz, .notPikachuBattle
+ callfar IsPlayerPikachuAsleepInParty
+ ld e, $24
+ jr c, .asm_f4026
+ ld e, $a
+.asm_f4026
+ callfar PlayPikachuSoundClip
+ jr .continue
+.notPikachuBattle
ld a, [wEnemyMonSpecies2]
call PlayCry
+.continue
ld hl, WildMonAppearedText
ld a, [wMoveMissed]
and a
@@ -23,9 +35,13 @@ PrintBeginningBattleText:
call DelayFrames
ld hl, TrainerWantsToFightText
.wildBattle
+ ld a, [wBattleType]
+ and a
+ jr nz, .doNotDrawPokeballs
push hl
callfar DrawAllPokeballs
pop hl
+.doNotDrawPokeballs
call PrintText
jr .done
.pokemonTower
diff --git a/engine/battle/core.asm b/engine/battle/core.asm
index 4628e86a..f66f509f 100755
--- a/engine/battle/core.asm
+++ b/engine/battle/core.asm
@@ -67,6 +67,9 @@ SlidePlayerAndEnemySilhouettesOnScreen:
ldh [rBGP], a
ldh [rOBP0], a
ldh [rOBP1], a
+ call 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
@@ -156,10 +159,16 @@ StartBattle:
call DelayFrames
call SaveScreenTilesToBuffer1
.checkAnyPartyAlive
+ ld a, [wBattleType]
+ cp BATTLE_TYPE_RUN
+ jp z, .specialBattle
+ cp BATTLE_TYPE_PIKACHU
+ jp z, .specialBattle
call AnyPartyAlive
ld a, d
and a
jp z, HandlePlayerBlackOut ; jump if no mon is alive
+.specialBattle
call LoadScreenTilesFromBuffer1
ld a, [wBattleType]
and a ; is it a normal battle?
@@ -893,6 +902,11 @@ ReplaceFaintedEnemyMon:
ld hl, wEnemyHPBarColor
ld e, $30
call GetBattleHealthBarColor
+ setpal SHADE_BLACK, SHADE_DARK, SHADE_LIGHT, SHADE_WHITE
+ ldh [rOBP0], a
+ ldh [rOBP1], a
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
callfar DrawEnemyPokeballs
ld a, [wLinkState]
cp LINK_STATE_BATTLING
@@ -958,9 +972,7 @@ TrainerDefeatedText:
PlayBattleVictoryMusic:
push af
- ld a, SFX_STOP_ALL_MUSIC
- ld [wNewSoundID], a
- call PlaySoundWaitForCurrent
+ call StopAllMusic
ld c, BANK(Music_DefeatedTrainer)
pop af
call PlayMusic
@@ -1014,6 +1026,7 @@ RemoveFaintedPlayerMon:
ld a, $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
@@ -1038,10 +1051,36 @@ RemoveFaintedPlayerMon:
and a ; was this called by HandleEnemyMonFainted?
ret z ; if so, return
+ ld a, [wPlayerMonNumber]
+ ld [wWhichPokemon], a
+ callfar IsThisPartymonStarterPikachu_Party
+ jr nc, .notPlayerPikachu
+ ld e, $3
+ callfar PlayPikachuSoundClip
+ jr .printText
+.notPlayerPikachu
ld a, [wBattleMonSpecies]
call PlayCry
+.printText
ld hl, PlayerMonFaintedText
- jp PrintText
+ call PrintText
+ ld a, [wPlayerMonNumber]
+ ld [wWhichPokemon], a
+ ld a, [wBattleMonLevel]
+ ld b, a
+ ld a, [wEnemyMonLevel]
+ sub b ; enemylevel - playerlevel
+ ; are we stronger than the opposing pokemon?
+ jr c, .regularFaint ; if so, deduct happiness regularly
+
+ cp 30 ; is the enemy 30 levels greater than us?
+ jr nc, .carelessTrainer ; if so, punish the player for being careless, as they shouldn't be fighting a very high leveled trainer with such a level difference
+.regularFaint
+ callabd_ModifyPikachuHappiness PIKAHAPPY_FAINTED
+ ret
+.carelessTrainer
+ callabd_ModifyPikachuHappiness PIKAHAPPY_CARELESSTRAINER
+ ret
PlayerMonFaintedText:
text_far _PlayerMonFaintedText
@@ -1098,7 +1137,7 @@ ChooseNextMon:
ld a, [wLinkState]
cp LINK_STATE_BATTLING
jr nz, .notLinkBattle
- inc a
+ ld a, 1
ld [wActionResultOrTookBattleTurn], a
call LinkBattleExchangeData
.notLinkBattle
@@ -1498,6 +1537,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
@@ -1753,19 +1794,46 @@ SendOutMon:
call RunPaletteCommand
ld hl, wEnemyBattleStatus1
res USING_TRAPPING_MOVE, [hl]
+ callfar IsThisPartymonStarterPikachu
+ jr c, .starterPikachu
ld a, $1
ldh [hWhoseTurn], a
ld a, POOF_ANIM
call PlayMoveAnimation
hlcoord 4, 11
predef AnimateSendingOutMon
+ jr .playRegularCry
+.starterPikachu
+ xor a
+ ldh [hWhoseTurn], a
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ callfar StarterPikachuBattleEntranceAnimation
+ callfar IsPlayerPikachuAsleepInParty
+ ld e, $24
+ jr c, .asm_3cd81
+ ld e, $a
+.asm_3cd81
+ callfar 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
+ callfar IsThisPartymonStarterPikachu
+ pop bc
+ ld a, b
+ ld [wWhichPokemon], a
+ jr c, .starterPikachu
hlcoord 1, 5
lb bc, 7, 7
call ClearScreenArea
@@ -1789,10 +1857,17 @@ AnimateRetreatingPlayerMon:
call .clearScreenArea
ld a, $4c
ldcoord_a 5, 11
+ jr .clearScreenArea
+.starterPikachu
+ xor a
+ ldh [hWhoseTurn], a
+ callfar AnimationSlideMonOff
+ ret
.clearScreenArea
hlcoord 1, 5
lb bc, 7, 7
- jp ClearScreenArea
+ call ClearScreenArea
+ ret
; reads player's current mon's HP into wBattleMonHP
ReadPlayerMonCurHPAndStatus:
@@ -2014,36 +2089,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
hlcoord 9, 14
ld [hl], "▶"
- ld c, 80
+ ld c, 20
call DelayFrames
ld [hl], " "
hlcoord 9, 16
ld [hl], "▶"
- ld c, 50
+ ld c, 20
call DelayFrames
ld [hl], "▷"
ld a, $2 ; select the "ITEM" menu
jp .upperLeftMenuItemWasNotSelected
.oldManName
db "OLD MAN@"
+.profOakName
+ db "PROF.OAK@"
.handleBattleMenuInput
ld a, [wBattleAndStartSavedMenuItem]
ld [wCurrentMenuItem], a
@@ -2126,6 +2214,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
@@ -2157,7 +2248,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
+ text_far _RunAwayText
+ text_end
.upperLeftMenuItemWasNotSelected ; a menu item other than the upper left item was selected
cp $2
@@ -2194,19 +2296,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
@@ -2365,6 +2471,8 @@ PartyMenuOrRockOrRun:
predef StatusScreen
predef StatusScreen2
; now we need to reload the enemy mon pic
+ ld a, 1
+ ldh [hWhoseTurn], a
ld a, [wEnemyBattleStatus2]
bit HAS_SUBSTITUTE_UP, a ; does the enemy mon have a substitute?
ld hl, AnimationSubstitute
@@ -2469,13 +2577,13 @@ MoveSelectionMenu:
.writemoves
ld de, wMovesString
- ldh a, [hFlagsFFF6]
+ ldh a, [hFlagsFFFA]
set 2, a
- ldh [hFlagsFFF6], a
+ ldh [hFlagsFFFA], a
call PlaceString
- ldh a, [hFlagsFFF6]
+ ldh a, [hFlagsFFFA]
res 2, a
- ldh [hFlagsFFF6], a
+ ldh [hFlagsFFFA], a
ret
.regularmenu
@@ -2484,8 +2592,7 @@ MoveSelectionMenu:
ld hl, wBattleMonMoves
call .loadmoves
hlcoord 4, 12
- ld b, 4
- ld c, 14
+ lb bc, 4, 14
di ; out of pure coincidence, it is possible for vblank to occur between the di and ei
; so it is necessary to put the di ei block to not cause tearing
call TextBoxBorder
@@ -2503,8 +2610,7 @@ MoveSelectionMenu:
ld hl, wEnemyMonMoves
call .loadmoves
hlcoord 0, 7
- ld b, 4
- ld c, 14
+ lb bc, 4, 14
call TextBoxBorder
hlcoord 2, 8
call .writemoves
@@ -2518,8 +2624,7 @@ MoveSelectionMenu:
call AddNTimes
call .loadmoves
hlcoord 4, 7
- ld b, 4
- ld c, 14
+ lb bc, 4, 14
call TextBoxBorder
hlcoord 6, 8
call .writemoves
@@ -2533,8 +2638,6 @@ MoveSelectionMenu:
ld a, [wMoveMenuType]
cp $1
jr z, .selectedmoveknown
- ld a, $1
- jr nc, .selectedmoveknown
ld a, [wPlayerMoveListIndex]
inc a
.selectedmoveknown
@@ -2595,10 +2698,10 @@ SelectMenuItem:
call AddNTimes
ld [hl], "▷"
.select
- ld hl, hFlagsFFF6
+ ld hl, hFlagsFFFA
set 1, [hl]
call HandleMenuInput
- ld hl, hFlagsFFF6
+ ld hl, hFlagsFFFA
res 1, [hl]
bit 6, a
jp nz, SelectMenuItem_CursorUp ; up
@@ -2700,6 +2803,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
+ ldh [hWhoseTurn], a
+ call LoadScreenTilesFromBuffer1
+ call Func_3d536
+ ld a, [wTestBattlePlayerSelectedMove]
+ and a
+ jp z, MoveSelectionMenu
+ ld [wAnimationID], a
+ xor a
+ ld [wAnimationType], a
+ predef MoveAnimation
+ callfar Func_78e98
+ jp MoveSelectionMenu
+
+Func_3d523:
+ ld a, [wTestBattlePlayerSelectedMove]
+ dec a
+ jr asm_3d52d
+Func_3d529:
+ ld a, [wTestBattlePlayerSelectedMove]
+ inc a
+asm_3d52d:
+ ld [wTestBattlePlayerSelectedMove], a
+ call Func_3d536
+ jp MoveSelectionMenu
+
+Func_3d536:
+ hlcoord 10, 16
+ lb bc, 2, 10
+ call ClearScreenArea
+ hlcoord 10, 17
+ ld de, wTestBattlePlayerSelectedMove
+ lb bc, LEADING_ZEROES | 1, 3
+ call PrintNumber
+ ld a, [wTestBattlePlayerSelectedMove]
+ and a
+ ret z
+ cp STRUGGLE
+ ret nc
+ ld [wd11e], a
+ call GetMoveName
+ hlcoord 13, 17
+ jp PlaceString
+
AnyMoveToSelect:
; return z and Struggle as the selected move if all moves have 0 PP and/or are disabled
ld a, STRUGGLE
@@ -2733,7 +2885,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
@@ -2748,6 +2903,9 @@ NoMovesLeftText:
text_end
SwapMovesInMenu:
+ ld a, [wPlayerBattleStatus3]
+ bit TRANSFORMED, a
+ jp nz, MoveSelectionMenu
ld a, [wMenuItemToSwap]
and a
jr z, .noMenuItemSelected
@@ -2827,8 +2985,7 @@ PrintMenuItem:
xor a
ldh [hAutoBGTransferEnabled], a
hlcoord 0, 8
- ld b, 3
- ld c, 9
+ lb bc, 3, 9
call TextBoxBorder
ld a, [wPlayerDisabledMove]
and a
@@ -2895,7 +3052,7 @@ PrintMenuItem:
jp Delay3
DisabledText:
- db "disabled!@"
+ db "Disabled!@"
TypeText:
db "TYPE@"
@@ -4574,7 +4731,7 @@ JumpToOHKOMoveEffect:
INCLUDE "data/battle/unused_critical_hit_moves.asm"
; 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
@@ -4988,7 +5145,7 @@ AttackSubstitute:
ldh a, [hWhoseTurn]
xor $01
ldh [hWhoseTurn], a
- callfar HideSubstituteShowMonAnim ; animate the substitute breaking
+ callfar Func_79929 ; animate the substitute breaking
; flip the turn back to the way it was
ldh a, [hWhoseTurn]
xor $01
@@ -5285,32 +5442,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
@@ -5318,9 +5469,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/types/type_matchups.asm"
@@ -6299,10 +6462,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
@@ -6327,6 +6493,8 @@ LoadPlayerBackPic:
ld [hli], a ; OAM tile number
inc a ; increment tile number
ldh [hOAMTile], a
+ ld a, $2
+ ld [hl], a
inc hl
dec c
jr nz, .innerLoop
@@ -6340,18 +6508,15 @@ LoadPlayerBackPic:
jr nz, .loop
ld de, vBackPic
call InterlaceMergeSpriteBuffers
- ld a, $a
- ld [MBC1SRamEnable], a
- xor a
- ld [MBC1SRamBank], a
+ ld a, $0
+ call SwitchSRAMBankAndLatchClockData
ld hl, vSprites
ld de, sSpriteBuffer1
ldh a, [hLoadedROMBank]
ld b, a
ld c, 7 * 7
call CopyVideoData
- xor a
- ld [MBC1SRamEnable], a
+ call PrepareRTCDataAndDisableSRAM
ld a, $31
ldh [hStartTileID], a
hlcoord 1, 5
@@ -6723,288 +6888,6 @@ 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
- ldh a, [hJoyHeld]
- bit 1, a ; B button pressed?
- ret nz
-.asm_3ef2f
- ld a, [wNumberOfNoRandomBattleStepsLeft]
- and a
- ret nz
- callfar TryDoWildEncounter
- ret nz
-InitBattleCommon:
- ld a, [wMapPalOffset]
- push af
- ld hl, wLetterPrintingDelayFlags
- ld a, [hl]
- push af
- res 1, [hl]
- callfar InitBattleVariables
- ld a, [wEnemyMonSpecies2]
- sub OPP_ID_OFFSET
- jp c, InitWildBattle
- ld [wTrainerClass], a
- call GetTrainerInformation
- callfar ReadTrainer
- call DoBattleTransitionAndInitBattleVariables
- call _LoadTrainerPic
- xor a
- ld [wEnemyMonSpecies2], a
- ldh [hStartTileID], a
- dec a
- ld [wAICount], a
- hlcoord 12, 0
- predef CopyUncompressedPicToTilemap
- ld a, $ff
- ld [wEnemyMonPartyPos], a
- ld a, $2
- ld [wIsInBattle], a
- jp _InitBattleCommon
-
-InitWildBattle:
- ld a, $1
- ld [wIsInBattle], a
- call LoadEnemyMonData
- call DoBattleTransitionAndInitBattleVariables
- ld a, [wCurOpponent]
- cp RESTLESS_SOUL
- jr z, .isGhost
- call IsGhostBattle
- jr nz, .isNoGhost
-.isGhost
- ld hl, wMonHSpriteDim
- ld a, $66
- ld [hli], a ; write sprite dimensions
- ld bc, GhostPic
- ld a, c
- ld [hli], a ; write front sprite pointer
- ld [hl], b
- ld hl, wEnemyMonNick ; set name to "GHOST"
- ld 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
- ldh [hStartTileID], a
- hlcoord 12, 0
- predef CopyUncompressedPicToTilemap
-
-; common code that executes after init battle code specific to trainer or wild battles
-_InitBattleCommon:
- ld b, SET_PAL_BATTLE_BLACK
- call RunPaletteCommand
- call SlidePlayerAndEnemySilhouettesOnScreen
- xor a
- ldh [hAutoBGTransferEnabled], a
- ld hl, .emptyString
- call PrintText
- call SaveScreenTilesToBuffer1
- call ClearScreen
- ld a, $98
- ldh [hAutoBGTransferDest + 1], a
- ld a, $1
- ldh [hAutoBGTransferEnabled], a
- call Delay3
- ld a, $9c
- ldh [hAutoBGTransferDest + 1], a
- call LoadScreenTilesFromBuffer1
- hlcoord 9, 7
- lb bc, 5, 10
- call ClearScreenArea
- hlcoord 1, 0
- lb bc, 4, 10
- call ClearScreenArea
- call ClearSprites
- ld a, [wIsInBattle]
- dec a ; is it a wild battle?
- call z, DrawEnemyHUDAndHPBar ; draw enemy HUD and HP bar if it's a wild battle
- call StartBattle
- callfar EndOfBattle
- pop af
- ld [wLetterPrintingDelayFlags], a
- pop af
- ld [wMapPalOffset], a
- ld a, [wSavedTilesetType]
- ldh [hTilesetType], a
- scf
+ predef MoveAnimation
+ callfar Func_78e98
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
- ldh a, [hStartTileID]
- ldh [hBaseTileID], a
- ld b, $4c
- ld a, [wIsInBattle]
- and a
- jr z, .notInBattle
- add b
- ld [hl], a
- call Delay3
- ld bc, -(SCREEN_WIDTH * 2 + 1)
- add hl, bc
- ld a, 1
- ld [wDownscaledMonSize], a
- lb bc, 3, 3
- predef CopyDownscaledMonTiles
- ld c, 4
- call DelayFrames
- ld bc, -(SCREEN_WIDTH * 2 + 1)
- add hl, bc
- xor a
- ld [wDownscaledMonSize], a
- lb bc, 5, 5
- predef CopyDownscaledMonTiles
- ld c, 5
- call DelayFrames
- ld bc, -(SCREEN_WIDTH * 2 + 1)
- jr .next
-.notInBattle
- ld bc, -(SCREEN_WIDTH * 6 + 3)
-.next
- add hl, bc
- ldh a, [hBaseTileID]
- add $31
- jr CopyUncompressedPicToHL
-
-CopyUncompressedPicToTilemap:
- ld a, [wPredefRegisters]
- ld h, a
- ld a, [wPredefRegisters + 1]
- ld l, a
- ldh a, [hStartTileID]
-CopyUncompressedPicToHL::
- lb bc, 7, 7
- ld de, SCREEN_WIDTH
- push af
- ld a, [wSpriteFlipped]
- and a
- jr nz, .flipped
- pop af
-.loop
- push bc
- push hl
-.innerLoop
- ld [hl], a
- add hl, de
- inc a
- dec c
- jr nz, .innerLoop
- pop hl
- inc hl
- pop bc
- dec b
- jr nz, .loop
- ret
-
-.flipped
- push bc
- ld b, 0
- dec c
- add hl, bc
- pop bc
- pop af
-.flippedLoop
- push bc
- push hl
-.flippedInnerLoop
- ld [hl], a
- add hl, de
- inc a
- dec c
- jr nz, .flippedInnerLoop
- pop hl
- dec hl
- pop bc
- dec b
- jr nz, .flippedLoop
- ret
-
-LoadMonBackPic:
-; Assumes the monster's attributes have
-; been loaded with GetMonHeader.
- ld a, [wBattleMonSpecies2]
- ld [wcf91], a
- hlcoord 1, 5
- ld b, 7
- ld c, 8
- call ClearScreenArea
- ld hl, wMonHBackSprite - wMonHeader
- call UncompressMonSprite
- predef ScaleSpriteByTwo
- ld de, vBackPic
- call InterlaceMergeSpriteBuffers ; combine the two buffers to a single 2bpp sprite
- ld hl, vSprites
- ld de, vBackPic
- ld c, (2*SPRITEBUFFERSIZE)/16 ; count of 16-byte chunks to be copied
- ldh a, [hLoadedROMBank]
- ld b, a
- jp CopyVideoData
diff --git a/engine/battle/decrement_pp.asm b/engine/battle/decrement_pp.asm
index b7c428f7..441bbb81 100644
--- a/engine/battle/decrement_pp.asm
+++ b/engine/battle/decrement_pp.asm
@@ -37,7 +37,7 @@ DecrementPP:
ld a, [wPlayerMoveListIndex] ; which move (0, 1, 2, 3) did we use?
ld c, a
ld b, 0
- add hl ,bc ; calculate the address in memory of the PP we need to decrement
+ add hl, bc ; calculate the address in memory of the PP we need to decrement
; based on the move chosen.
dec [hl] ; Decrement PP
ret
diff --git a/engine/battle/draw_hud_pokeball_gfx.asm b/engine/battle/draw_hud_pokeball_gfx.asm
index 097a0fcc..6aed1d0a 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/effects.asm b/engine/battle/effects.asm
index 441d6c1c..c4e81816 100644
--- a/engine/battle/effects.asm
+++ b/engine/battle/effects.asm
@@ -60,6 +60,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
@@ -198,7 +208,7 @@ FreezeBurnParalyzeEffect:
ret nz ; return if they have a substitute, can't effect them
ldh a, [hWhoseTurn]
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
@@ -211,7 +221,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
@@ -224,9 +244,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
@@ -234,7 +254,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
@@ -242,7 +262,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
@@ -250,7 +270,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
@@ -263,12 +283,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
@@ -276,23 +306,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
@@ -458,25 +494,25 @@ UpdateStatDone:
ld bc, wPlayerMonMinimized
ldh a, [hWhoseTurn]
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
@@ -974,6 +1010,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
@@ -1015,10 +1054,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
@@ -1488,6 +1544,7 @@ PlayBattleAnimationGotID:
push de
push bc
predef MoveAnimation
+ callfar Func_78e98
pop bc
pop de
pop hl
diff --git a/engine/battle/end_of_battle.asm b/engine/battle/end_of_battle.asm
index bd4a1901..e64f54e7 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
callfar DisplayLinkBattleVersusTextBox
ld a, [wBattleResult]
cp $1
@@ -43,6 +45,8 @@ EndOfBattle:
xor a
ld [wForceEvolution], a
predef EvolutionAfterBattle
+ ld d, $82
+ callfar UpdatePikachuMoodAfterBattle
.resetVariables
xor a
ld [wLowHealthAlarm], a ;disable low health alarm
diff --git a/engine/battle/experience.asm b/engine/battle/experience.asm
index 0eab6e08..bab804bb 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
- callfar CalculateModifiedStats
- callfar ApplyBurnAndParalysisPenaltiesToPlayer
- callfar ApplyBadgeStatBoosts
- callfar DrawPlayerHUDAndHPBar
- callfar 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:
ldh [hQuotient + 2], a
ret
+Bankswitch15ToF:
+ ld b, BANK(BattleCore)
+ jp Bankswitch
+
GainedText:
text_far _GainedText
text_asm
diff --git a/engine/battle/ghost_marowak_anim.asm b/engine/battle/ghost_marowak_anim.asm
index 6760c3d5..03059022 100644
--- a/engine/battle/ghost_marowak_anim.asm
+++ b/engine/battle/ghost_marowak_anim.asm
@@ -2,6 +2,7 @@ MarowakAnim:
; animate the ghost being unveiled as a Marowak
ld a, $e4
ldh [rOBP1], a
+ call 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
hlcoord 12, 0
@@ -27,6 +28,7 @@ MarowakAnim:
sla a
sla a
ldh [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
ldh [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 29c11356..e55a0672 100644
--- a/engine/battle/link_battle_versus_text.asm
+++ b/engine/battle/link_battle_versus_text.asm
@@ -2,8 +2,7 @@
DisplayLinkBattleVersusTextBox:
call LoadTextBoxTilePatterns
hlcoord 3, 4
- ld b, 7
- ld c, 12
+ lb bc, 7, 12
call TextBoxBorder
hlcoord 4, 5
ld de, wPlayerName
diff --git a/engine/battle/misc.asm b/engine/battle/misc.asm
index 33af6f6f..df9145f2 100755
--- a/engine/battle/misc.asm
+++ b/engine/battle/misc.asm
@@ -101,22 +101,3 @@ InitList:
ld a, b
ld [wItemPrices + 1], a
ret
-
-; get species of mon e in list [wMonDataLocation] for LoadMonData
-GetMonSpecies:
- ld hl, wPartySpecies
- ld a, [wMonDataLocation]
- and a
- jr z, .getSpecies
- dec a
- jr z, .enemyParty
- ld hl, wBoxSpecies
- jr .getSpecies
-.enemyParty
- ld hl, wEnemyPartyMons
-.getSpecies
- ld d, 0
- add hl, de
- ld a, [hl]
- ld [wcf91], a
- ret
diff --git a/engine/battle/move_effects/heal.asm b/engine/battle/move_effects/heal.asm
index e9fb62a7..80923a29 100644
--- a/engine/battle/move_effects/heal.asm
+++ b/engine/battle/move_effects/heal.asm
@@ -86,7 +86,7 @@ HealEffect_:
ld [wHPBarNewHP], a
.playAnim
ld hl, PlayCurrentMoveAnimation
- call BankswitchEtoF
+ call Bankswitch3DtoF
ldh a, [hWhoseTurn]
and a
hlcoord 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:
text_far _StartedSleepingEffect
diff --git a/engine/battle/move_effects/reflect_light_screen.asm b/engine/battle/move_effects/reflect_light_screen.asm
index 7bdc7be7..c05055fa 100644
--- a/engine/battle/move_effects/reflect_light_screen.asm
+++ b/engine/battle/move_effects/reflect_light_screen.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:
text_far _LightScreenProtectedText
@@ -40,6 +40,6 @@ ReflectGainedArmorText:
text_far _ReflectGainedArmorText
text_end
-BankswitchEtoF:
+Bankswitch3DtoF:
ld b, BANK(BattleCore)
jp Bankswitch
diff --git a/engine/battle/move_effects/transform.asm b/engine/battle/move_effects/transform.asm
index 46cea51c..d37bd94d 100644
--- a/engine/battle/move_effects/transform.asm
+++ b/engine/battle/move_effects/transform.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:
text_far _TransformedText
diff --git a/engine/battle/read_trainer_party.asm b/engine/battle/read_trainer_party.asm
index 7e5c1249..02fbfeda 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
+.AddAdditionalMoveData
+; does the trainer have additional move data?
+ ld a, [wTrainerClass]
+ ld b, a
+ ld a, [wTrainerNo]
+ ld c, a
+ ld hl, SpecialTrainerMoves
+.loopAdditionalMoveData
+ ld a, [hli]
+ cp $ff
+ jr z, .FinishUp
+ cp b
+ jr nz, .asm_39c46
+ ld a, [hli]
+ cp c
+ jr nz, .asm_39c46
+ ld d, h
+ ld e, l
+.writeAdditionalMoveDataLoop
+ ld a, [de]
+ inc de
and a
- jr z, .AddTeamMove
+ jp z, .FinishUp
+ dec a
+ ld hl, wEnemyMon1Moves
+ ld bc, wEnemyMon2 - wEnemyMon1
+ call AddNTimes
+ ld a, [de]
+ inc de
dec a
- add a
ld c, a
ld b, 0
- ld hl, LoneMoves
add hl, bc
+ ld a, [de]
+ inc de
+ ld [hl], a
+ jr .writeAdditionalMoveDataLoop
+.asm_39c46
ld a, [hli]
- ld d, [hl]
- ld hl, wEnemyMon1Moves + 2
- 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, [hli]
- cp b
- jr z, .GiveTeamMoves ; is there a match?
- inc hl ; if not, go to the next entry
- inc a
- jr nz, .IterateTeamMoves
-
-; no matches found. is this trainer champion rival?
- ld a, b
- cp RIVAL3
- jr z, .ChampionRival
- jr .FinishUp ; nope
-.GiveTeamMoves
- ld a, [hl]
- ld [wEnemyMon5Moves + 2], a
- jr .FinishUp
-.ChampionRival ; give moves to his team
-
-; pidgeot
- ld a, SKY_ATTACK
- ld [wEnemyMon1Moves + 2], a
-
-; starter
- ld a, [wRivalStarter]
- cp STARTER3
- ld b, MEGA_DRAIN
- jr z, .GiveStarterMove
- cp STARTER1
- ld b, FIRE_BLAST
- jr z, .GiveStarterMove
- ld b, BLIZZARD ; must be squirtle
-.GiveStarterMove
- ld a, b
- ld [wEnemyMon6Moves + 2], a
+ and a
+ jr nz, .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 4f01c2f4..9362cc3a 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 87b4398d..794a65ab 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 2225dca1..17e68e75 100644
--- a/engine/battle/trainer_ai.asm
+++ b/engine/battle/trainer_ai.asm
@@ -288,13 +288,19 @@ INCLUDE "data/trainers/special_moves.asm"
INCLUDE "data/trainers/parties.asm"
TrainerAI:
- and a
ld a, [wIsInBattle]
dec a
- ret z ; if not a trainer, we're done here
+ jr z, .done ; if not a trainer, we're done here
ld a, [wLinkState]
cp LINK_STATE_BATTLING
- ret z
+ 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
@@ -305,7 +311,7 @@ TrainerAI:
add hl, bc
ld a, [wAICount]
and a
- ret z ; if no AI uses left, we're done here
+ jr z, .done; if no AI uses left, we're done here
inc hl
inc a
jr nz, .getpointer
@@ -318,6 +324,9 @@ TrainerAI:
ld l, a
call Random
jp hl
+.done
+ and a
+ ret
INCLUDE "data/trainers/ai_pointers.asm"
@@ -377,22 +386,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 8c9c1529..d16c6515 100644
--- a/engine/battle/wild_encounters.asm
+++ b/engine/battle/wild_encounters.asm
@@ -24,8 +24,9 @@ TryDoWildEncounter:
ld [wRepelRemainingSteps], a
.next
; determine if wild pokemon can appear in the half-block we're standing in
-; is the bottom right tile (9,9) of the half-block we're standing in a grass/water tile?
- hlcoord 9, 9
+; is the bottom left tile (8,9) of the half-block we're standing in a grass/water tile?
+; note that by using the bottom left tile, this prevents the "left-shore" tiles from generating grass encounters
+ hlcoord 8, 9
ld c, [hl]
ld a, [wGrassTile]
cp c
@@ -68,8 +69,6 @@ TryDoWildEncounter:
cp $14 ; is the bottom left tile (8,9) of the half-block we're standing in a water tile?
jr nz, .gotWildEncounterType ; else, it's treated as a grass tile by default
ld hl, wWaterMons
-; since the bottom right tile of a "left shore" half-block is $14 but the bottom left tile is not,
-; "left shore" half-blocks (such as the one in the east coast of Cinnabar) load grass encounters.
.gotWildEncounterType
ld b, 0
add hl, bc
diff --git a/engine/bg_map_attributes.asm b/engine/bg_map_attributes.asm
new file mode 100644
index 00000000..4c50bcf8
--- /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
+ ldh [rVBK], a
+ push hl
+ ld a, [hl]
+ ld c, a ; save attribute count for later
+ ld de, $10
+ add hl, de
+ ld a, h
+ ldh [rHDMA1], a
+ ld a, l
+ ldh [rHDMA2], a
+ ld de, vBGMap0
+ ld a, d
+ ldh [rHDMA3], a
+ ld a, e
+ ldh [rHDMA4], a
+
+ ldh a, [rLCDC]
+ and rLCDC_ENABLE_MASK ; is LCD off?
+ jr z, .lcdOff ; if off, transfer immediately
+; wait for VBlank if LCD is on
+.waitForVBlankLoop1
+ ldh a, [rLY]
+ cp $90
+ jr nz, .waitForVBlankLoop1
+.waitForAccessibleVRAMLoop1
+ ldh a, [rSTAT]
+ and %10 ; are we in HBlank or VBlank?
+ jr nz, .waitForAccessibleVRAMLoop1 ; loop until we're in a safe period to transfer to VRAM
+.lcdOff
+ ld a, c ; number of BG attributes to transfer, plus 1 times 16
+ ldh [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
+ ldh [rHDMA1], a
+ ld a, l
+ ldh [rHDMA2], a
+ ld de, vBGMap1 ; copy to vBGMap1
+ ld a, d
+ ldh [rHDMA3], a
+ ld a, e
+ ldh [rHDMA4], a
+; LCD check again
+ ldh a, [rLCDC]
+ and rLCDC_ENABLE_MASK ; is LCD off?
+ jr z, .lcdOff2 ; if off, transfer immediately
+; wait for VBlank if LCD is on
+.waitForVBlankLoop2
+ ldh a, [rLY]
+ cp $90
+ jr nz, .waitForVBlankLoop2
+.waitForAccessibleVRAMLoop2
+ ldh a, [rSTAT]
+ and %10 ; are we in HBlank or VBlank?
+ jr nz, .waitForAccessibleVRAMLoop2 ; loop until we're in a safe period to transfer to VRAM
+.lcdOff2
+ ld a, c
+ ldh [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
+ ldh a, [rIF]
+ res VBLANK, a
+ ldh [rIF], a
+ xor a
+ ldh [rVBK], a
+ ei
+ ret
+
+BGMapAttributesPointers:
+ dw BGMapAttributes_Unknown1
+ dw BGMapAttributes_Unknown2
+ dw BGMapAttributes_GameFreakIntro
+ dw BGMapAttributes_TrainerCard
+ dw BGMapAttributes_PartyMenu
+ dw BGMapAttributes_NidorinoIntro
+ dw BGMapAttributes_TitleScreen
+ dw BGMapAttributes_Slots
+ dw BGMapAttributes_Pokedex
+ dw BGMapAttributes_StatusScreen
+ dw BGMapAttributes_Battle
+ dw BGMapAttributes_WholeScreen
+ dw BGMapAttributes_Unknown13
+
+HandleBadgeFaceAttributes:
+; zero out the attributes if the player doesn't have the respective badge
+; BOULDERBADGE
+ ld hl, vBGMap1 + $183
+ ld de, wTrainerCardBadgeAttributes + 6 * 0
+ ld a, [de]
+ and a
+ call z, ZeroOutCurrentBadgeAttributes
+; CASCADEBADGE
+ ld hl, vBGMap1 + $187
+ ld de, wTrainerCardBadgeAttributes + 6 * 1
+ ld a, [de]
+ and a
+ call z, ZeroOutCurrentBadgeAttributes
+; THUNDERBADGE
+ ld hl, vBGMap1 + $18b
+ ld de, wTrainerCardBadgeAttributes + 6 * 2
+ ld a, [de]
+ and a
+ call z, ZeroOutCurrentBadgeAttributes
+; RAINBOWBADGE
+ ld hl, vBGMap1 + $18f
+ ld de, wTrainerCardBadgeAttributes + 6 * 3
+ ld a, [de]
+ and a
+ call z, ZeroOutCurrentBadgeAttributes
+; SOULBADGE
+ ld hl, vBGMap1 + $1e3
+ ld de, wTrainerCardBadgeAttributes + 6 * 6
+ ld a, [de]
+ and a
+ call z, ZeroOutCurrentBadgeAttributes
+; MARSHBADGE
+ ld hl, vBGMap1 + $1e7
+ ld de, wTrainerCardBadgeAttributes + 6 * 7
+ ld a, [de]
+ and a
+ call z, ZeroOutCurrentBadgeAttributes
+; VOLCANOBADGE
+ ld hl, vBGMap1 + $1eb
+ ld de, wTrainerCardBadgeAttributes + 6 * 8
+ ld a, [de]
+ and a
+ call z, ZeroOutCurrentBadgeAttributes
+; EARTHBADGE
+ ld hl, vBGMap1 + $1ef
+ ld de, wTrainerCardBadgeAttributes + 6 * 9
+ ld a, [de]
+ and a
+ call z, ZeroOutCurrentBadgeAttributes
+ ret
+
+ZeroOutCurrentBadgeAttributes:
+ push hl
+ xor a
+ ld [hli], a
+ ld [hl], a
+ ld bc, $1f
+ add hl, bc
+ ld [hli], a
+ ld [hl], a
+ pop hl
+ ret
+
+HandlePartyHPBarAttributes:
+; hp bars require 3 (green, orange, red) colours, when there are only 2 "free" colours per palette
+; therefore, we must transfer individual bg attributes where the locations of the hp bars are in vram
+ ld hl, vBGMap1 + $25 ; location of start of the HP bar in vram
+ ld de, wPartyHPBarAttributes
+ ld c, PARTY_LENGTH
+.loop
+ push bc
+ push hl
+ ld a, [de]
+ and $3 ; 4 possible palettes
+ rept 7 ; hp bar length in tiles
+ ld [hli], a
+ endr
+ pop hl
+ ld bc, $40 ; get 2nd party location
+ add hl, bc
+ push hl
+
+ push de ; (inefficiently) copy de to hl
+ pop hl
+
+ ld bc, $6
+ add hl, bc ; get the next palette
+
+ push hl
+ pop de ; copy back to de
+
+ pop hl
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
diff --git a/engine/debug/debug_menu.asm b/engine/debug/debug_menu.asm
index 02280db0..a85c9c64 100644
--- a/engine/debug/debug_menu.asm
+++ b/engine/debug/debug_menu.asm
@@ -1,74 +1,5 @@
DebugMenu:
-IF DEF(_DEBUG)
- call ClearScreen
-
- ld hl, DebugPlayerName
- ld de, wPlayerName
- ld bc, NAME_LENGTH
- call CopyData
-
- ld hl, DebugRivalName
- ld de, wRivalName
- ld bc, NAME_LENGTH
- call CopyData
-
- call LoadFontTilePatterns
- call LoadHpBarAndStatusTilePatterns
- call ClearSprites
- call RunDefaultPaletteCommand
-
- hlcoord 5, 6
- ld b, 3
- ld c, 9
- call TextBoxBorder
-
- hlcoord 7, 7
- ld de, DebugMenuOptions
- call PlaceString
-
- ld a, 3 ; medium speed
- ld [wOptions], a
-
- ld a, A_BUTTON | B_BUTTON | START
- ld [wMenuWatchedKeys], a
- xor a
- ld [wMenuJoypadPollCount], a
- inc a
- ld [wMaxMenuItem], a
- ld a, 7
- ld [wTopMenuItemY], a
- dec a
- ld [wTopMenuItemX], a
- xor a
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- ld [wMenuWatchMovingOutOfBounds], a
-
- call HandleMenuInput
- bit BIT_B_BUTTON, a
- jp nz, DisplayTitleScreen
-
- ld a, [wCurrentMenuItem]
- and a ; FIGHT?
- jp z, TestBattle
-
- ; DEBUG
- ld hl, wd732
- set 1, [hl]
- jp StartNewGameDebug
-
-DebugPlayerName:
- db "Tom@"
-
-DebugRivalName:
- db "Juerry@"
-
-DebugMenuOptions:
- db "FIGHT"
- next "DEBUG@"
-ELSE
ret
-ENDC
TestBattle:
.loop
diff --git a/engine/debug/debug_party.asm b/engine/debug/debug_party.asm
index 17baa7ef..8545b848 100644
--- a/engine/debug/debug_party.asm
+++ b/engine/debug/debug_party.asm
@@ -1,13 +1,6 @@
-; This function is 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 -1
@@ -20,140 +13,12 @@ SetIshiharaTeam:
call AddPartyMon
jr .loop
-IshiharaTeam:
- db EXEGGUTOR, 90
-IF DEF(_DEBUG)
- db MEW, 5
-ELSE
- db MEW, 20
-ENDC
- db JOLTEON, 56
- db DUGTRIO, 56
- db ARTICUNO, 57
-IF DEF(_DEBUG)
+DebugTeam:
+ db SNORLAX, 80
+ db PERSIAN, 80
+ db JIGGLYPUFF, 15
db PIKACHU, 5
-ENDC
db -1 ; end
DebugStart:
-IF DEF(_DEBUG)
- xor a ; PLAYER_PARTY_DATA
- ld [wMonDataLocation], a
-
- ; Fly anywhere.
- dec a ; $ff
- ld [wTownVisitedFlag], a
- ld [wTownVisitedFlag + 1], a
-
- ; Get all badges except Earth Badge.
- ld a, $ff ^ (1 << BIT_EARTHBADGE)
- ld [wObtainedBadges], a
-
- call SetIshiharaTeam
-
- ; Exeggutor gets four HM moves.
- ld hl, wPartyMon1Moves
- ld a, FLY
- ld [hli], a
- ld a, CUT
- ld [hli], a
- ld a, SURF
- ld [hli], a
- ld a, STRENGTH
- ld [hl], a
- ld hl, wPartyMon1PP
- ld a, 15
- ld [hli], a
- ld a, 30
- ld [hli], a
- ld a, 15
- ld [hli], a
- ld [hl], a
-
- ; Jolteon gets Thunderbolt.
- ld hl, wPartyMon3Moves + 3
- ld a, THUNDERBOLT
- ld [hl], a
- ld hl, wPartyMon3PP + 3
- ld a, 15
- ld [hl], a
-
- ; Articuno gets Fly.
- ld hl, wPartyMon5Moves
- ld a, FLY
- ld [hl], a
- ld hl, wPartyMon5PP
- ld a, 15
- ld [hl], a
-
- ; Pikachu gets Surf.
- ld hl, wPartyMon6Moves + 2
- ld a, SURF
- ld [hl], a
- ld hl, wPartyMon6PP + 2
- ld a, 15
- ld [hl], a
-
- ; Get some debug items.
- ld hl, wNumBagItems
- ld de, DebugItemsList
-.items_loop
- ld a, [de]
- cp -1
- jr z, .items_end
- ld [wcf91], a
- inc de
- ld a, [de]
- inc de
- ld [wItemQuantity], a
- call AddItemToInventory
- jr .items_loop
-.items_end
-
- ; Complete the Pokédex.
- ld hl, wPokedexOwned
- call DebugSetPokedexEntries
- ld hl, wPokedexSeen
- call DebugSetPokedexEntries
- SetEvent EVENT_GOT_POKEDEX
-
- ; Rival chose Squirtle,
- ; Player chose Charmander.
- ld hl, wRivalStarter
- ld a, STARTER2
- ld [hli], a
- inc hl ; hl = wPlayerStarter
- ld a, STARTER1
- ld [hl], a
-
- ret
-
-DebugSetPokedexEntries:
- ld b, wPokedexOwnedEnd - wPokedexOwned - 1
- ld a, %11111111
-.loop
- ld [hli], a
- dec b
- jr nz, .loop
- ld [hl], %01111111
- ret
-
-DebugItemsList:
- db BICYCLE, 1
- db FULL_RESTORE, 99
- db FULL_HEAL, 99
- db ESCAPE_ROPE, 99
- db RARE_CANDY, 99
- db MASTER_BALL, 99
- db TOWN_MAP, 1
- db SECRET_KEY, 1
- db CARD_KEY, 1
- db S_S_TICKET, 1
- db LIFT_KEY, 1
- db -1 ; end
-
-DebugUnusedList:
- db -1 ; end
-ELSE
ret
-ENDC
diff --git a/engine/diploma_3a.asm b/engine/diploma_3a.asm
new file mode 100755
index 00000000..83a7345b
--- /dev/null
+++ b/engine/diploma_3a.asm
@@ -0,0 +1,168 @@
+CIRCLE_TILE_ID EQU $10
+
+_DisplayDiploma:
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ ld de, SurfingPikachu3Graphics
+ ld hl, vChars2
+ lb bc, BANK(SurfingPikachu3Graphics), (SurfingPikachu3GraphicsEnd - SurfingPikachu3Graphics) / $10
+ call CopyVideoData
+
+ hlcoord 0, 0
+ call Func_e9bdf
+
+ hlcoord 0, 0
+ call Func_e9beb
+
+ hlcoord 19, 0
+ call Func_e9beb
+
+ ld a, $00
+ hlcoord 0, 0
+ ld [hl], a
+ hlcoord 19, 0
+ ld [hl], a
+
+ ld de, String_e9a73
+ hlcoord 5, 2
+ call PlaceString
+
+ ld de, String_e9a7d
+ hlcoord 3, 4
+ call PlaceString
+
+ ld de, wPlayerName
+ hlcoord 10, 4
+ call PlaceString
+
+ ld de, String_e9a84
+ hlcoord 2, 6
+ call PlaceString
+
+ ld de, String_e9ac8
+ hlcoord 9, 16
+ call PlaceString
+
+ ld b, SET_PAL_GENERIC
+ call RunPaletteCommand
+ ld a, $01
+ ldh [hAutoBGTransferEnabled], a
+ call Delay3
+ call GBPalNormal
+ ret
+
+String_e9a73:
+ db CIRCLE_TILE_ID, "Diploma", CIRCLE_TILE_ID, "@"
+
+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
+ hlcoord 0, 17
+ call Func_e9bdf
+ hlcoord 0, 0
+ call Func_e9beb
+ hlcoord 19, 0
+ call Func_e9beb
+ ld a, $00
+ hlcoord 0, 17
+ ld [hl], a
+ hlcoord 19, 17
+ ld [hl], a
+ ld de, Tilemap_e9b3e
+ hlcoord 6, 2
+ lb bc, 10, 12
+ call Diploma_Surfing_CopyBox
+ ld de, Tilemap_e9bb6
+ hlcoord 5, 13
+ lb bc, 1, 11
+ call Diploma_Surfing_CopyBox
+ ld de, String_e9bd5
+ hlcoord 2, 15
+ call PlaceString
+ hlcoord 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
+ hlcoord 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/events/black_out.asm b/engine/events/black_out.asm
index 16d2081f..6d3d91b8 100644
--- a/engine/events/black_out.asm
+++ b/engine/events/black_out.asm
@@ -1,6 +1,8 @@
ResetStatusAndHalveMoneyOnBlackout::
; Reset player status on blackout.
xor a
+ ld [wd435], a
+ xor a ; gamefreak copypasting functions (double xor a)
ld [wBattleResult], a
ld [wWalkBikeSurfState], a
ld [wIsInBattle], a
diff --git a/engine/events/card_key.asm b/engine/events/card_key.asm
index b052d3e2..de5f402e 100755
--- a/engine/events/card_key.asm
+++ b/engine/events/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
ldh [hSpriteIndexOrTextID], a
call PrintPredefTextID
- pop de
+ call GetCoordsInFrontOfPlayer
srl d
ld a, d
ld b, a
diff --git a/engine/events/diploma.asm b/engine/events/diploma.asm
index 91541f09..a5a007fa 100755..100644
--- a/engine/events/diploma.asm
+++ b/engine/events/diploma.asm
@@ -1,5 +1,3 @@
-CIRCLE_TILE_ID EQU $70
-
DisplayDiploma::
call SaveScreenTilesToBuffer2
call GBPalWhiteOutWithDelay3
@@ -8,109 +6,12 @@ DisplayDiploma::
ld [wUpdateSpritesEnabled], a
ld hl, wd730
set 6, [hl]
- call DisableLCD
- ld hl, CircleTile
- ld de, vChars2 tile CIRCLE_TILE_ID
- ld bc, $10
- ld a, BANK(CircleTile)
- call FarCopyData2
- hlcoord 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
- hlcoord 10, 4
- ld de, wPlayerName
- call PlaceString
- farcall DrawPlayerCharacter
-
-; Move the player 33 pixels right and set the priority bit so he appears
-; behind the background layer.
- ld hl, 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
- farcall LoadTrainerInfoTextBoxTiles
- ld b, SET_PAL_GENERIC
- call RunPaletteCommand
- call Delay3
- call GBPalNormal
- ld a, $90
- ldh [rOBP0], a
+ callfar _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
- lb bc, $ff, $00
-.loop
- ld a, [hli]
- cp "@"
- ret z
- dec c
- jr .loop
-
-diploma_text: MACRO
- dw \3
- dwcoord \1, \2
-ENDM
-
-DiplomaTextPointersAndCoords:
- ; x, y, text
- diploma_text 5, 2, DiplomaText
- diploma_text 3, 4, DiplomaPlayer
- diploma_text 15, 4, DiplomaEmptyText
- diploma_text 2, 6, DiplomaCongrats
- diploma_text 9, 16, DiplomaGameFreak
-
-DiplomaText:
- db CIRCLE_TILE_ID, "Diploma", CIRCLE_TILE_ID, "@"
-
-DiplomaPlayer:
- db "Player@"
-
-DiplomaEmptyText:
- db "@"
-
-DiplomaCongrats:
- db "Congrats! This"
- next "diploma certifies"
- next "that you have"
- next "completed your"
- next "#DEX.@"
-
-DiplomaGameFreak:
- db "GAME FREAK@"
diff --git a/engine/events/elevator.asm b/engine/events/elevator.asm
index 8e871456..004893a0 100755
--- a/engine/events/elevator.asm
+++ b/engine/events/elevator.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/events/evolve_trade.asm b/engine/events/evolve_trade.asm
deleted file mode 100755
index 56069fac..00000000
--- a/engine/events/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
- callfar TryEvolvingMon
- xor a ; LINK_STATE_NONE
- ld [wLinkState], a
- jp PlayDefaultMusic
diff --git a/engine/events/give_pokemon.asm b/engine/events/give_pokemon.asm
index ef01ef99..efc184f8 100755
--- a/engine/events/give_pokemon.asm
+++ b/engine/events/give_pokemon.asm
@@ -44,6 +44,8 @@ _GivePokemon::
ret
.addToParty
call SetPokedexOwnedFlag
+ ld hl, UnknownTerminator_f6794
+ call PrintText
call AddPartyMon
ld a, 1
ld [wDoNotWaitForButtonPressAfterDisplayingText], a
@@ -68,6 +70,9 @@ SetPokedexOwnedFlag:
ld hl, GotMonText
jp PrintText
+UnknownTerminator_f6794:
+ text_end
+
GotMonText:
text_far _GotMonText
sound_get_item_1
diff --git a/engine/events/hidden_items.asm b/engine/events/hidden_items.asm
index 97bb0b71..63b95bcf 100755
--- a/engine/events/hidden_items.asm
+++ b/engine/events/hidden_items.asm
@@ -9,7 +9,7 @@ HiddenItems:
predef FlagActionPredef
ld a, c
and a
- ret nz
+ jr nz, .itemAlreadyFound
call EnableAutoTextBoxDrawing
ld a, 1
ld [wDoNotWaitForButtonPressAfterDisplayingText], a
@@ -18,6 +18,11 @@ HiddenItems:
call GetItemName
tx_pre_jump FoundHiddenItemText
+.itemAlreadyFound
+ ld a, $ff
+ ldh [hItemAlreadyFound], a
+ ret
+
INCLUDE "data/events/hidden_item_coords.asm"
FoundHiddenItemText::
@@ -54,7 +59,7 @@ HiddenCoins:
predef GetQuantityOfItemInBag
ld a, b
and a
- ret z
+ jr z, .doNotPickUpCoins
ld hl, HiddenCoinCoords
call FindHiddenItemOrCoinsIndex
ld [wHiddenItemOrCoinsIndex], a
@@ -65,7 +70,7 @@ HiddenCoins:
predef FlagActionPredef
ld a, c
and a
- ret nz
+ jr nz, .doNotPickUpCoins
xor a
ldh [hUnusedCoinsByte], a
ldh [hCoins], a
@@ -79,6 +84,12 @@ HiddenCoins:
cp 40
jr z, .bcd20 ; should be bcd40
jr .bcd100
+
+.doNotPickUpCoins
+ ld a, $ff
+ ldh [hItemAlreadyFound], a
+ ret
+
.bcd10
ld a, $10
ldh [hCoins + 1], a
diff --git a/engine/events/hidden_objects/bills_house_pc.asm b/engine/events/hidden_objects/bills_house_pc.asm
index a73596b4..bdbaff7e 100644
--- a/engine/events/hidden_objects/bills_house_pc.asm
+++ b/engine/events/hidden_objects/bills_house_pc.asm
@@ -52,9 +52,7 @@ BillsHouseInitiatedText::
text_far _BillsHouseInitiatedText
text_promptbutton
text_asm
- ld a, SFX_STOP_ALL_MUSIC
- ld [wNewSoundID], a
- call PlaySound
+ call StopAllMusic
ld c, 16
call DelayFrames
ld a, SFX_SWITCH
@@ -85,8 +83,7 @@ BillsHousePokemonList::
ld hl, wd730
set 6, [hl]
hlcoord 0, 0
- ld b, 10
- ld c, 9
+ lb bc, 10, 9
call TextBoxBorder
hlcoord 2, 2
ld de, BillsMonListText
diff --git a/engine/events/hidden_objects/cinnabar_gym_quiz.asm b/engine/events/hidden_objects/cinnabar_gym_quiz.asm
index e2ae7fbe..da550c76 100644
--- a/engine/events/hidden_objects/cinnabar_gym_quiz.asm
+++ b/engine/events/hidden_objects/cinnabar_gym_quiz.asm
@@ -9,6 +9,8 @@ CinnabarGymQuiz::
text_asm
xor a
ld [wOpponentAfterWrongAnswer], a
+ ld hl, wd475
+ res 7, [hl]
ld a, [wHiddenObjectFunctionArgument]
push af
and $f
@@ -17,7 +19,12 @@ CinnabarGymQuiz::
and $f0
swap a
ldh [hGymGateAnswer], a
+ ldh a, [hGymGateIndex]
ld hl, CinnabarGymQuizIntroText
+ cp 1
+ jr z, .onFirstQuestion
+ ld hl, CinnabarGymQuizShortIntroText
+.onFirstQuestion
call PrintText
ldh a, [hGymGateIndex]
dec a
@@ -35,10 +42,18 @@ CinnabarGymQuiz::
call CinnabarGymQuiz_1ea92
jp TextScriptEnd
+CinnabarGymQuizDummyIntroText:
+ text_far _CinnabarGymQuizDummyIntroText
+ text_end
+
CinnabarGymQuizIntroText:
text_far _CinnabarGymQuizIntroText
text_end
+CinnabarGymQuizShortIntroText:
+ text_far _CinnabarGymQuizShortIntroText
+ text_end
+
CinnabarQuizQuestions:
dw CinnabarQuizQuestionsText1
dw CinnabarQuizQuestionsText2
@@ -71,10 +86,6 @@ CinnabarQuizQuestionsText6:
text_far _CinnabarQuizQuestionsText6
text_end
-CinnabarGymGateFlagAction:
- EventFlagAddress hl, EVENT_CINNABAR_GYM_GATE0_UNLOCKED
- predef_jump FlagActionPredef
-
CinnabarGymQuiz_1ea92:
call YesNoChoice
ldh a, [hGymGateAnswer]
@@ -114,6 +125,8 @@ CinnabarGymQuiz_1ea92:
ldh a, [hGymGateIndex]
add $2
ld [wOpponentAfterWrongAnswer], a
+ ld hl, wd475
+ set 7, [hl]
ret
CinnabarGymQuizCorrectText:
@@ -140,6 +153,10 @@ CinnabarGymQuizIncorrectText:
text_far _CinnabarGymQuizIncorrectText
text_end
+CinnabarGymGateFlagAction:
+ EventFlagAddress hl, EVENT_CINNABAR_GYM_GATE0_UNLOCKED
+ predef_jump FlagActionPredef
+
UpdateCinnabarGymGateTileBlocks_::
; Update the overworld map with open floor blocks or locked gate blocks
; depending on event flags.
@@ -177,10 +194,11 @@ UpdateCinnabarGymGateTileBlocks_::
.next
pop bc
ld [wNewTileBlockID], a
- predef ReplaceTileBlock
+ call CinnabarGym_ReplaceTileBlock
ld hl, hGymGateIndex
dec [hl]
jr nz, .loop
+ callfar RedrawMapView
ret
gym_gate_coord: MACRO
@@ -198,3 +216,31 @@ CinnabarGymGateCoords:
gym_gate_coord 3, 8, VERTICAL_GATE_BLOCK
gym_gate_coord 2, 6, HORIZONTAL_GATE_BLOCK
gym_gate_coord 2, 3, HORIZONTAL_GATE_BLOCK
+
+
+CinnabarGym_ReplaceTileBlock:
+; basically a copy of the first half of ReplaceTileBlock
+; before checking if it is necessary to redraw the map view
+ ld hl, wOverworldMap
+ ld a, [wCurMapWidth]
+ add $6
+ ld e, a
+ ld d, $0
+ add hl, de
+ add hl, de
+ add hl, de
+ ld e, $3
+ add hl, de
+ ld e, a
+ ld a, b
+ and a
+ jr z, .addX
+.addWidthYTimesLoop
+ add hl, de
+ dec b
+ jr nz, .addWidthYTimesLoop
+.addX
+ add hl, bc
+ ld a, [wNewTileBlockID]
+ ld [hl], a
+ ret
diff --git a/engine/events/hidden_objects/fanclub_pictures.asm b/engine/events/hidden_objects/fanclub_pictures.asm
new file mode 100644
index 00000000..30bc72c7
--- /dev/null
+++ b/engine/events/hidden_objects/fanclub_pictures.asm
@@ -0,0 +1,23 @@
+FanClubPicture1:
+ ld a, RAPIDASH
+ ld [wcf91], a
+ call DisplayMonFrontSpriteInBox
+ call EnableAutoTextBoxDrawing
+ tx_pre FanClubPicture1Text
+ ret
+
+FanClubPicture1Text::
+ text_far _FanClubPicture1Text
+ text_end
+
+FanClubPicture2:
+ ld a, FEAROW
+ ld [wcf91], a
+ call DisplayMonFrontSpriteInBox
+ call EnableAutoTextBoxDrawing
+ tx_pre FanClubPicture2Text
+ ret
+
+FanClubPicture2Text::
+ text_far _FanClubPicture2Text
+ text_end
diff --git a/engine/events/hidden_objects/museum_fossils.asm b/engine/events/hidden_objects/museum_fossils.asm
index 27714981..539f2c3f 100644
--- a/engine/events/hidden_objects/museum_fossils.asm
+++ b/engine/events/hidden_objects/museum_fossils.asm
@@ -21,32 +21,3 @@ KabutopsFossil:
KabutopsFossilText::
text_far _KabutopsFossilText
text_end
-
-DisplayMonFrontSpriteInBox:
-; Displays a pokemon's front sprite in a pop-up window.
-; [wcf91] = pokemon internal id number
- ld a, 1
- ldh [hAutoBGTransferEnabled], a
- call Delay3
- xor a
- ldh [hWY], a
- call SaveScreenTilesToBuffer1
- ld a, MON_SPRITE_POPUP
- ld [wTextBoxID], a
- call DisplayTextBoxID
- call UpdateSprites
- ld a, [wcf91]
- ld [wd0b5], a
- call GetMonHeader
- ld de, vChars1 tile $31
- call LoadMonFrontSprite
- ld a, $80
- ldh [hStartTileID], a
- hlcoord 10, 11
- predef AnimateSendingOutMon
- call WaitForTextScrollButtonPress
- call LoadScreenTilesFromBuffer1
- call Delay3
- ld a, $90
- ldh [hWY], a
- ret
diff --git a/engine/events/hidden_objects/museum_fossils2.asm b/engine/events/hidden_objects/museum_fossils2.asm
new file mode 100644
index 00000000..fce0f03a
--- /dev/null
+++ b/engine/events/hidden_objects/museum_fossils2.asm
@@ -0,0 +1,28 @@
+DisplayMonFrontSpriteInBox:
+; Displays a pokemon's front sprite in a pop-up window.
+; [wcf91] = pokemon internal id number
+ ld a, 1
+ ldh [hAutoBGTransferEnabled], a
+ call Delay3
+ xor a
+ ldh [hWY], a
+ call SaveScreenTilesToBuffer1
+ ld a, MON_SPRITE_POPUP
+ ld [wTextBoxID], a
+ call DisplayTextBoxID
+ call UpdateSprites
+ ld a, [wcf91]
+ ld [wd0b5], a
+ call GetMonHeader
+ ld de, vChars1 + $310
+ call LoadMonFrontSprite
+ ld a, $80
+ ldh [hStartTileID], a
+ hlcoord 10, 11
+ predef AnimateSendingOutMon
+ call WaitForTextScrollButtonPress
+ call LoadScreenTilesFromBuffer1
+ call Delay3
+ ld a, $90
+ ldh [hWY], a
+ ret
diff --git a/engine/events/hidden_objects/oaks_lab_email.asm b/engine/events/hidden_objects/oaks_lab_email.asm
index b66babe0..bd4c66d7 100644
--- a/engine/events/hidden_objects/oaks_lab_email.asm
+++ b/engine/events/hidden_objects/oaks_lab_email.asm
@@ -3,7 +3,8 @@ DisplayOakLabEmailText:
cp SPRITE_FACING_UP
ret nz
call EnableAutoTextBoxDrawing
- tx_pre_jump OakLabEmailText
+ tx_pre OakLabEmailText
+ ret
OakLabEmailText::
text_far _OakLabEmailText
diff --git a/engine/events/hidden_objects/route_15_binoculars.asm b/engine/events/hidden_objects/route_15_binoculars.asm
index ce047c2f..9734e833 100644
--- a/engine/events/hidden_objects/route_15_binoculars.asm
+++ b/engine/events/hidden_objects/route_15_binoculars.asm
@@ -7,7 +7,10 @@ Route15GateLeftBinoculars:
ld a, ARTICUNO
ld [wcf91], a
call PlayCry
- jp DisplayMonFrontSpriteInBox
+ call DisplayMonFrontSpriteInBox
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ret
Route15UpstairsBinocularsText::
text_far _Route15UpstairsBinocularsText
diff --git a/engine/events/hidden_objects/safari_game.asm b/engine/events/hidden_objects/safari_game.asm
index ac07e2f3..5001a5d4 100644
--- a/engine/events/hidden_objects/safari_game.asm
+++ b/engine/events/hidden_objects/safari_game.asm
@@ -7,10 +7,6 @@ SafariZoneCheck::
jr SafariZoneGameStillGoing
SafariZoneCheckSteps::
-IF DEF(_DEBUG)
- call DebugPressedOrHeldB
- ret nz
-ENDC
ld a, [wSafariSteps]
ld b, a
ld a, [wSafariSteps + 1]
@@ -31,8 +27,7 @@ SafariZoneGameOver:
call EnableAutoTextBoxDrawing
xor a
ld [wAudioFadeOutControl], a
- dec a ; SFX_STOP_ALL_MUSIC
- call PlaySound
+ call StopAllMusic
ld c, BANK(SFX_Safari_Zone_PA)
ld a, SFX_SAFARI_ZONE_PA
call PlayMusic
diff --git a/engine/events/hidden_objects/school_blackboard.asm b/engine/events/hidden_objects/school_blackboard.asm
index de4700d4..eb927292 100644
--- a/engine/events/hidden_objects/school_blackboard.asm
+++ b/engine/events/hidden_objects/school_blackboard.asm
@@ -27,8 +27,7 @@ LinkCableHelp::
ld hl, wd730
set 6, [hl]
hlcoord 0, 0
- ld b, 8
- ld c, 13
+ lb bc, 8, 13
call TextBoxBorder
hlcoord 2, 2
ld de, HowToLinkText
diff --git a/engine/events/hidden_objects/vermilion_gym_trash.asm b/engine/events/hidden_objects/vermilion_gym_trash.asm
index c2bfed06..21dd3ee0 100644
--- a/engine/events/hidden_objects/vermilion_gym_trash.asm
+++ b/engine/events/hidden_objects/vermilion_gym_trash.asm
@@ -33,53 +33,17 @@ GymTrashScript:
.openFirstLock
; Next can is trying for the second switch.
SetEvent EVENT_1ST_LOCK_OPENED
-
- ld hl, GymTrashCans
- ld a, [wGymTrashCanIndex]
- ; * 5
- ld b, a
- add a
- add a
- add b
-
- ld d, 0
- ld e, a
- add hl, de
- ld a, [hli]
-
-; 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.
-
- ldh [hGymTrashCanRandNumMask], a
- push hl
- call Random
- swap a
- ld b, a
- ldh a, [hGymTrashCanRandNumMask]
- and b
- dec a
- pop hl
-
- ld d, 0
- ld e, a
- add hl, de
- ld a, [hl]
- and $f
- ld [wSecondLockTrashCanIndex], a
-
+ callfar Yellow_SampleSecondTrashCan
tx_pre_id VermilionGymTrashSuccessText1
jr .done
.trySecondLock
- ld a, [wSecondLockTrashCanIndex]
- ld b, a
ld a, [wGymTrashCanIndex]
+ ld b, a
+ ld a, [wSecondLockTrashCanIndex]
+ cp b
+ jr z, .openSecondLock
+ ld a, [wSecondLockTrashCanIndex + 1]
cp b
jr z, .openSecondLock
@@ -107,25 +71,26 @@ GymTrashScript:
GymTrashCans:
; byte 0: mask for random number
; bytes 1-4: indices of the trash cans that can have the second lock
-; (but see the comment above explaining a bug regarding this)
; Note that the mask is simply the number of valid trash can indices that
-; follow. The remaining bytes are filled with 0 to pad the length of each entry
+; follow. The remaining bytes are filled with -1 to pad the length of each entry
; to 5 bytes.
- db 2, 1, 3, 0, 0 ; 0
- db 3, 0, 2, 4, 0 ; 1
- db 2, 1, 5, 0, 0 ; 2
- db 3, 0, 4, 6, 0 ; 3
+; This is functionally replaced with GymTrashCans3a but was never removed from source.
+
+ db 2, 1, 3, -1, -1 ; 0
+ db 3, 0, 2, 4, -1 ; 1
+ db 2, 1, 5, -1, -1 ; 2
+ db 3, 0, 4, 6, -1 ; 3
db 4, 1, 3, 5, 7 ; 4
- db 3, 2, 4, 8, 0 ; 5
- db 3, 3, 7, 9, 0 ; 6
+ db 3, 2, 4, 8, -1 ; 5
+ db 3, 3, 7, 9, -1 ; 6
db 4, 4, 6, 8, 10 ; 7
- db 3, 5, 7, 11, 0 ; 8
- db 3, 6, 10, 12, 0 ; 9
+ db 3, 5, 7, 11, -1 ; 8
+ db 3, 6, 10, 12, -1 ; 9
db 4, 7, 9, 11, 13 ; 10
- db 3, 8, 10, 14, 0 ; 11
- db 2, 9, 13, 0, 0 ; 12
- db 3, 10, 12, 14, 0 ; 13
- db 2, 11, 13, 0, 0 ; 14
+ db 3, 8, 10, 14, -1 ; 11
+ db 2, 9, 13, -1, -1 ; 12
+ db 3, 10, 12, 14, -1 ; 13
+ db 2, 11, 13, -1, -1 ; 14
VermilionGymTrashSuccessText1::
text_far _VermilionGymTrashSuccessText1
diff --git a/engine/events/in_game_trades.asm b/engine/events/in_game_trades.asm
index c6951615..a0a23dfa 100755
--- a/engine/events/in_game_trades.asm
+++ b/engine/events/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
- callfar EvolveTradeMon
+ call InGameTrade_CheckForTradeEvo
call ClearScreen
call InGameTrade_RestoreScreen
farcall 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
+ callfar EvolveTradeMon
+ xor a ; LINK_STATE_NONE
+ ld [wLinkState], a
+ jp PlayDefaultMusic
+
InGameTrade_TrainerString:
db "<TRAINER>@@@@@@@@@@"
diff --git a/engine/events/poison.asm b/engine/events/poison.asm
index 8bb756b5..9f3ad391 100644
--- a/engine/events/poison.asm
+++ b/engine/events/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
ldh [hSpriteIndexOrTextID], a
call DisplayTextID
+ callfar IsThisPartymonStarterPikachu_Party
+ jr nc, .curMonNotPlayerPikachu
+ ld e, $3
+ callfar 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/events/pokecenter.asm b/engine/events/pokecenter.asm
index 97dbcd53..e007030a 100755
--- a/engine/events/pokecenter.asm
+++ b/engine/events/pokecenter.asm
@@ -1,4 +1,13 @@
DisplayPokemonCenterDialogue_::
+ ld a, [wCurMap]
+ cp PEWTER_POKECENTER
+ jr nz, .regularCenter
+ call CheckPikachuFollowingPlayer
+ jr z, .regularCenter
+ ld hl, LooksContentText ; if pikachu is sleeping, don't heal
+ call PrintText
+ ret
+.regularCenter
call SaveScreenTilesToBuffer1 ; save screen
ld hl, PokemonCenterWelcomeText
call PrintText
@@ -11,18 +20,36 @@ DisplayPokemonCenterDialogue_::
call PrintText
.skipShallWeHealYourPokemon
call YesNoChoicePokeCenter ; yes/no menu
+ call UpdateSprites
ld a, [wCurrentMenuItem]
and a
- jr nz, .declinedHealing ; if the player chose No
+ jp nz, .declinedHealing ; if the player chose No
call SetLastBlackoutMap
- call LoadScreenTilesFromBuffer1 ; restore screen
+ callfar IsStarterPikachuInOurParty
+ jr nc, .notHealingPlayerPikachu
+ call CheckPikachuFollowingPlayer
+ jr nz, .notHealingPlayerPikachu
+ call LoadCurrentMapView
+ call Delay3
+ call UpdateSprites
+ callfar PikachuWalksToNurseJoy ; todo
+.notHealingPlayerPikachu
ld hl, NeedYourPokemonText
call PrintText
- ld a, $18
- ld [wSprite01StateData1ImageIndex], a ; make the nurse turn to face the machine
- call Delay3
- predef HealParty
+ ld c, 64
+ call DelayFrames
+ call CheckPikachuFollowingPlayer
+ jr nz, .playerPikachuNotOnScreen
+ call DisablePikachuOverworldSpriteDrawing
+ callfar IsStarterPikachuInOurParty
+ call c, Func_6eaa
+.playerPikachuNotOnScreen
+ lb bc, 1, 8
+ call Func_6ebb
+ ld c, 30
+ call DelayFrames
farcall AnimateHealingMachine ; do the healing machine animation
+ predef HealParty
xor a
ld [wAudioFadeOutControl], a
ld a, [wAudioSavedROMBank]
@@ -31,19 +58,69 @@ DisplayPokemonCenterDialogue_::
ld [wLastMusicSoundID], a
ld [wNewSoundID], a
call PlaySound
+ call CheckPikachuFollowingPlayer
+ jr nz, .doNotReturnPikachu
+ callfar 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 [wSprite01StateData1ImageIndex], a ; make the nurse bow
- ld c, a
+ callfar IsStarterPikachuInOurParty
+ jr nc, .notInParty
+ lb bc, 15, 0
+ call Func_6ebb
+.notInParty
+ call LoadCurrentMapView
+ call Delay3
+ call UpdateSprites
+ callfar ReloadWalkingTilePatterns
+ ld a, $1
+ ldh [hSpriteIndex], a
+ ld a, $1
+ ldh [hSpriteImageIndex], a
+ call SpriteFunc_34a1
+ ld c, 40
call DelayFrames
+ call UpdateSprites
+ call LoadFontTilePatterns
jr .done
.declinedHealing
call LoadScreenTilesFromBuffer1 ; restore screen
.done
ld hl, PokemonCenterFarewellText
call PrintText
- jp UpdateSprites
+ call UpdateSprites
+ ret
+
+Func_6eaa:
+ ld a, $1
+ ldh [hSpriteIndex], a
+ ld a, $4
+ ldh [hSpriteImageIndex], a
+ call SpriteFunc_34a1
+ ld c, 64
+ call DelayFrames
+ ret
+
+Func_6ebb:
+ ld a, b
+ ldh [hSpriteIndex], a
+ ld a, c
+ ldh [hSpriteImageIndex], a
+ push bc
+ call SetSpriteFacingDirectionAndDelay
+ pop bc
+ ld a, b
+ ldh [hSpriteIndex], a
+ ld a, c
+ ldh [hSpriteImageIndex], a
+ call SpriteFunc_34a1
+ ret
PokemonCenterWelcomeText:
text_far _PokemonCenterWelcomeText
@@ -66,3 +143,7 @@ PokemonCenterFarewellText:
text_pause
text_far _PokemonCenterFarewellText
text_end
+
+LooksContentText:
+ text_far _LooksContentText
+ text_end
diff --git a/engine/events/pokedex_rating.asm b/engine/events/pokedex_rating.asm
index c61253b7..1086257a 100755
--- a/engine/events/pokedex_rating.asm
+++ b/engine/events/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,88 +51,88 @@ DisplayDexRating:
ld [de], a
ret
-PokedexRatingText_441cc:
- text_far _OaksLabText_441cc
+DexCompletionText:
+ text_far _DexCompletionText
text_end
DexRatingsTable:
- dbw 10, PokedexRatingText_44201
- dbw 20, PokedexRatingText_44206
- dbw 30, PokedexRatingText_4420b
- dbw 40, PokedexRatingText_44210
- dbw 50, PokedexRatingText_44215
- dbw 60, PokedexRatingText_4421a
- dbw 70, PokedexRatingText_4421f
- dbw 80, PokedexRatingText_44224
- dbw 90, PokedexRatingText_44229
- dbw 100, PokedexRatingText_4422e
- dbw 110, PokedexRatingText_44233
- dbw 120, PokedexRatingText_44238
- dbw 130, PokedexRatingText_4423d
- dbw 140, PokedexRatingText_44242
- dbw 150, PokedexRatingText_44247
- dbw NUM_POKEMON + 1, PokedexRatingText_4424c
+ dbw 10, DexRatingText_Own0To9
+ dbw 20, DexRatingText_Own10To19
+ dbw 30, DexRatingText_Own20To29
+ dbw 40, DexRatingText_Own30To39
+ dbw 50, DexRatingText_Own40To49
+ dbw 60, DexRatingText_Own50To59
+ dbw 70, DexRatingText_Own60To69
+ dbw 80, DexRatingText_Own70To79
+ dbw 90, DexRatingText_Own80To89
+ dbw 100, DexRatingText_Own90To99
+ dbw 110, DexRatingText_Own100To109
+ dbw 120, DexRatingText_Own110To119
+ dbw 130, DexRatingText_Own120To129
+ dbw 140, DexRatingText_Own130To139
+ dbw 150, DexRatingText_Own140To149
+ dbw NUM_POKEMON + 1, DexRatingText_Own150To151
-PokedexRatingText_44201:
- text_far _OaksLabText_44201
+DexRatingText_Own0To9:
+ text_far _DexRatingText_Own0To9
text_end
-PokedexRatingText_44206:
- text_far _OaksLabText_44206
+DexRatingText_Own10To19:
+ text_far _DexRatingText_Own10To19
text_end
-PokedexRatingText_4420b:
- text_far _OaksLabText_4420b
+DexRatingText_Own20To29:
+ text_far _DexRatingText_Own20To29
text_end
-PokedexRatingText_44210:
- text_far _OaksLabText_44210
+DexRatingText_Own30To39:
+ text_far _DexRatingText_Own30To39
text_end
-PokedexRatingText_44215:
- text_far _OaksLabText_44215
+DexRatingText_Own40To49:
+ text_far _DexRatingText_Own40To49
text_end
-PokedexRatingText_4421a:
- text_far _OaksLabText_4421a
+DexRatingText_Own50To59:
+ text_far _DexRatingText_Own50To59
text_end
-PokedexRatingText_4421f:
- text_far _OaksLabText_4421f
+DexRatingText_Own60To69:
+ text_far _DexRatingText_Own60To69
text_end
-PokedexRatingText_44224:
- text_far _OaksLabText_44224
+DexRatingText_Own70To79:
+ text_far _DexRatingText_Own70To79
text_end
-PokedexRatingText_44229:
- text_far _OaksLabText_44229
+DexRatingText_Own80To89:
+ text_far _DexRatingText_Own80To89
text_end
-PokedexRatingText_4422e:
- text_far _OaksLabText_4422e
+DexRatingText_Own90To99:
+ text_far _DexRatingText_Own90To99
text_end
-PokedexRatingText_44233:
- text_far _OaksLabText_44233
+DexRatingText_Own100To109:
+ text_far _DexRatingText_Own100To109
text_end
-PokedexRatingText_44238:
- text_far _OaksLabText_44238
+DexRatingText_Own110To119:
+ text_far _DexRatingText_Own110To119
text_end
-PokedexRatingText_4423d:
- text_far _OaksLabText_4423d
+DexRatingText_Own120To129:
+ text_far _DexRatingText_Own120To129
text_end
-PokedexRatingText_44242:
- text_far _OaksLabText_44242
+DexRatingText_Own130To139:
+ text_far _DexRatingText_Own130To139
text_end
-PokedexRatingText_44247:
- text_far _OaksLabText_44247
+DexRatingText_Own140To149:
+ text_far _DexRatingText_Own140To149
text_end
-PokedexRatingText_4424c:
- text_far _OaksLabText_4424c
+DexRatingText_Own150To151:
+ text_far _DexRatingText_Own150To151
text_end
diff --git a/engine/events/prize_menu.asm b/engine/events/prize_menu.asm
index d9320fe7..87244119 100755
--- a/engine/events/prize_menu.asm
+++ b/engine/events/prize_menu.asm
@@ -23,8 +23,7 @@ CeladonPrizeMenu::
ld [wTopMenuItemX], a
call PrintPrizePrice
hlcoord 0, 2
- ld b, 8
- ld c, 16
+ lb bc, 8, 16
call TextBoxBorder
call GetPrizeMenuId
call UpdateSprites
@@ -143,12 +142,14 @@ GetPrizeMenuId:
ld c, (1 << 7 | 2)
jp PrintBCDNumber
+NoThanksText:
+ db "NO THANKS@"
+
INCLUDE "data/events/prizes.asm"
PrintPrizePrice:
hlcoord 11, 0
- ld b, 1
- ld c, 7
+ lb bc, 1, 7
call TextBoxBorder
call UpdateSprites
hlcoord 12, 0
diff --git a/engine/events/vending_machine.asm b/engine/events/vending_machine.asm
index a67f1c07..6ff6a5e4 100755
--- a/engine/events/vending_machine.asm
+++ b/engine/events/vending_machine.asm
@@ -18,8 +18,7 @@ VendingMachineMenu::
ld hl, wd730
set 6, [hl]
hlcoord 0, 3
- ld b, 8
- ld c, 12
+ lb bc, 8, 12
call TextBoxBorder
call UpdateSprites
hlcoord 2, 5
diff --git a/engine/gfx/hp_bar.asm b/engine/gfx/hp_bar.asm
index b7bd97f2..b47b1fbd 100755
--- a/engine/gfx/hp_bar.asm
+++ b/engine/gfx/hp_bar.asm
@@ -213,13 +213,11 @@ UpdateHPBar_PrintHPNumber:
ld a, [wHPBarOldHP + 1]
ld [wHPBarTempHP], a
push hl
- ldh a, [hFlagsFFF6]
+ ld de, $15
+ ldh a, [hFlagsFFFA]
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/gfx/mon_icons.asm b/engine/gfx/mon_icons.asm
index 16409640..6e2cf0ba 100755
--- a/engine/gfx/mon_icons.asm
+++ b/engine/gfx/mon_icons.asm
@@ -91,7 +91,7 @@ PartyMonSpeeds:
LoadMonPartySpriteGfx:
; Load mon party sprite tile patterns into VRAM during V-blank.
ld hl, MonPartySpritePointers
- ld a, $1c
+ ld a, $1e
LoadAnimSpriteGfx:
; Load animated sprite tile patterns into VRAM during V-blank. hl is the address
@@ -130,7 +130,7 @@ LoadMonPartySpriteGfxWithLCDDisabled:
; LCD.
call DisableLCD
ld hl, MonPartySpritePointers
- ld a, $1c
+ ld a, $1e
ld bc, $0
.loop
push af
@@ -151,7 +151,7 @@ LoadMonPartySpriteGfxWithLCDDisabled:
inc hl
ld d, [hl]
pop hl
- call FarCopyData2
+ call FarCopyData
pop hl
pop bc
ld a, $6
@@ -170,6 +170,8 @@ WriteMonPartySpriteOAMByPartyIndex:
push de
push bc
ldh a, [hPartyMonIndex]
+ cp $ff
+ jr z, .asm_7191f
ld hl, wPartySpecies
ld e, a
ld d, 0
@@ -183,6 +185,16 @@ WriteMonPartySpriteOAMByPartyIndex:
pop hl
ret
+.asm_7191f
+ ld hl, 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].
@@ -204,7 +216,7 @@ UnusedPartyMonSpriteFunction:
ld hl, vSprites tile $00
call .LoadTilePatterns
pop af
- add $54
+ add $5A
ld hl, vSprites tile $04
call .LoadTilePatterns
xor a
diff --git a/engine/gfx/palettes.asm b/engine/gfx/palettes.asm
index f25ff215..dd723afa 100755
--- a/engine/gfx/palettes.asm
+++ b/engine/gfx/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,15 +255,25 @@ 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:
; entries correspond to SET_PAL_* constants
- 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
@@ -256,6 +281,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.
@@ -270,9 +297,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
@@ -290,6 +314,132 @@ DeterminePaletteIDOutOfBattle:
ld a, [hl]
ret
+YellowIntroPaletteAction::
+ ld a, e
+ and a
+ jr nz, .asm_720bd
+ ld hl, PalPacket_Generic
+ ldh a, [hGBC]
+ and a
+ jp z, SendSGBPacket
+ jp InitGBCPalettes
+
+.asm_720bd
+ ld hl, UnknownPalPacket_72811
+ ldh 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
+ ldh 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
+ ldh 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
@@ -325,6 +475,14 @@ UpdatePartyMenuBlkPacket:
ret
SendSGBPacket:
+ ld a, 1
+ ldh [hDisableJoypadPolling], a ; don't poll joypad while sending packet
+ call _SendSGBPacket
+ xor a
+ ldh [hDisableJoypadPolling], a
+ ret
+
+_SendSGBPacket:
;check number of packets
ld a, [hl]
and $07
@@ -334,9 +492,6 @@ SendSGBPacket:
.loop2
; save B for later use
push bc
-; disable ReadJoypad to prevent it from interfering with sending the packet
- ld a, 1
- ldh [hDisableJoypadPolling], a
; send RESET signal (P14=LOW, P15=LOW)
xor a
ldh [rJOYP], a
@@ -353,10 +508,10 @@ 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
ldh [rJOYP], a
@@ -364,7 +519,7 @@ SendSGBPacket:
ld a, $30
ldh [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
@@ -377,8 +532,6 @@ SendSGBPacket:
; set P14=HIGH,P15=HIGH
ld a, $30
ldh [rJOYP], a
- xor a
- ldh [hDisableJoypadPolling], a
; wait for about 70000 cycles
call Wait7000
; restore (previously pushed) number of packets
@@ -393,14 +546,17 @@ LoadSGB:
xor a
ld [wOnSGB], a
call CheckSGB
- ret nc
- ld a, 1
- ld [wOnSGB], a
- ld a, [wGBC]
+ jr c, .onSGB
+ ldh 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
@@ -443,23 +599,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
- ldh [hDisableJoypadPolling], a
- ei
call Wait7000
ldh a, [rJOYP]
and $3
@@ -515,6 +667,7 @@ CopyGfxToSuperNintendoVRAM:
call DisableLCD
ld a, $e4
ldh [rBGP], a
+ call _UpdateGBCPal_BGP_CheckDMG
ld de, vChars1
ld a, [wCopyingSGBTileData]
and a
@@ -545,6 +698,7 @@ CopyGfxToSuperNintendoVRAM:
call SendSGBPacket
xor a
ldh [rBGP], a
+ call _UpdateGBCPal_BGP_CheckDMG
ei
ret
@@ -562,13 +716,17 @@ Wait7000:
ret
SendSGBPackets:
- ld a, [wGBC]
+ ldh a, [hGBC]
and a
jr z, .notGBC
push de
call InitGBCPalettes
pop hl
- call EmptyFunc3
+ call InitGBCPalettes
+ ldh a, [rLCDC]
+ and rLCDC_ENABLE_MASK
+ ret z
+ call Delay3
ret
.notGBC
push de
@@ -577,30 +735,349 @@ SendSGBPackets:
jp SendSGBPacket
InitGBCPalettes:
- ld a, $80 ; index 0 with auto-increment
- ldh [rBGPI], a
- inc hl
- ld c, $20
-.loop
- ld a, [hli]
+ ld a, [hl]
+ and $f8
+ cp $20
+ jp z, TranslatePalPacketToBGMapAttributes
+
inc hl
+
+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
+ ldh a, [rBGP]
+ ld [wLastBGP], a
+ jr .convert
+.notBGP
+ dec a
+ jr nz, .notOBP0
+ ldh a, [rOBP0]
+ ld [wLastOBP0], a
+ jr .convert
+.notOBP0
+ ldh a, [rOBP1]
+ ld [wLastOBP1], a
+.convert
+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
+ or $80 ; auto-increment
+ ldh [rBGPI], a
+ ld de, rBGPD
+ ld hl, wGBCPal
+ ld b, %10 ; mask for non-V-blank/non-H-blank STAT mode
+ ldh 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 de, SuperPalettes
- add e
- jr nc, .noCarry
- inc d
-.noCarry
+ 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]
- ldh [rBGPD], a
+ ld [hli], a
+ inc de
+ dec c
+ jr nz, .loop
+ pop de
+ ret
+
+TransferBGPPals::
+; Transfer the buffered BG palettes.
+ ldh a, [rLCDC]
+ and rLCDC_ENABLE_MASK
+ jr z, .lcdDisabled
+ di
+.waitLoop
+ ldh a, [rLY]
+ cp 144
+ jr c, .waitLoop
+.lcdDisabled
+ call .DoTransfer
+ ei
+ ret
+
+.DoTransfer:
+ xor a
+ or $80 ; auto-increment
+ ldh [rBGPI], a
+ ld de, rBGPD
+ ld hl, wBGPPalsBuffer
+ ld c, 4 * PAL_SIZE
+.loop
+ ld a, [hli]
+ ld [de], a
dec c
jr nz, .loop
ret
-EmptyFunc3:
+TransferCurOBPData:
+ push de
+ add a
+ add a
+ add a
+ or $80 ; auto-increment
+ ldh [rOBPI], a
+ ld de, rOBPD
+ ld hl, wGBCPal
+ ld b, %10 ; mask for non-V-blank/non-H-blank STAT mode
+ ldh 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.
+ ldh a, [rSTAT]
+ and b
+ jr z, TransferPalColorLCDEnabled
+
+; Wait for H-blank or V-blank to begin.
+.notInBlankingPeriod
+ ldh a, [rSTAT]
+ and b
+ jr nz, .notInBlankingPeriod
+; fall through
+
+TransferPalColorLCDDisabled:
+; Transfer a palette color while the LCD is disabled.
+ ld a, [hli]
+ ld [de], a
+ ld a, [hli]
+ ld [de], a
+ ret
+
+_UpdateGBCPal_BGP_CheckDMG::
+ ldh 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
+ farcall LoadBGMapAttributes
+ ret
+
+PalPacketPointers::
+ db (palPacketPointersEnd - palPacketPointers) / 2
+palPacketPointers:
+ dw BlkPacket_WholeScreen
+ dw BlkPacket_Battle
+ dw BlkPacket_StatusScreen
+ dw BlkPacket_Pokedex
+ dw BlkPacket_Slots
+ dw BlkPacket_Titlescreen
+ dw BlkPacket_NidorinoIntro
+ dw wPartyMenuBlkPacket
+ dw wTrainerCardBlkPacket
+ dw BlkPacket_GameFreakIntro
+ dw wPalPacket
+ dw UnknownPacket_72751
+palPacketPointersEnd:
+
CopySGBBorderTiles:
; SGB tile data is stored in a 4BPP planar format.
; Each tile is 32 bytes. The first 16 bytes contain bit planes 1 and 2, while
@@ -608,9 +1085,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/gfx/screen_effects.asm b/engine/gfx/screen_effects.asm
index e8648901..973a951a 100755..100644
--- a/engine/gfx/screen_effects.asm
+++ b/engine/gfx/screen_effects.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
ldh a, [rBGP]
- or b
+ xor $ff
ldh [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 4
call DelayFrames
ldh a, [rBGP]
- and %11111100
+ xor $ff
ldh [rBGP], a
+ call UpdateGBCPal_BGP
ret
PredefShakeScreenVertically:
diff --git a/engine/gfx/sprite_oam.asm b/engine/gfx/sprite_oam.asm
index b3c07ecd..01b2c412 100644
--- a/engine/gfx/sprite_oam.asm
+++ b/engine/gfx/sprite_oam.asm
@@ -1,6 +1,8 @@
PrepareOAMData::
; Determine OAM data for currently visible
; sprites and write it to 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
ldh [hSpriteOffset2], a
- ld d, HIGH(wSpriteStateData1)
- ldh a, [hSpriteOffset2]
ld e, a
+ ld d, HIGH(wSpriteStateData1)
+
ld a, [de] ; [x#SPRITESTATEDATA1_PICTUREID]
and a
jp z, .nextSprite
@@ -40,16 +42,22 @@ PrepareOAMData::
jr c, .usefacing
; unchanging
- and $f
- add $10 ; skip to the second half of the table which doesn't account for facing direction
+ ld a, $0
jr .next
.usefacing
and $f
.next
+; read the entry from the table
+ ld c, a
+ ld b, 0
+ ld hl, SpriteFacingAndAnimationTable
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
ld l, a
-
; get sprite priority
push de
inc d
@@ -61,65 +69,46 @@ PrepareOAMData::
ldh [hSpritePriority], a ; temp store sprite priority
pop de
-; read the entry from the table
- ld h, 0
- ld bc, SpriteFacingAndAnimationTable
- add hl, hl
- add hl, hl
- add hl, bc
- ld a, [hli]
- ld c, a
- ld a, [hli]
- ld b, a
- ld a, [hli]
- ld h, [hl]
- ld l, a
call GetSpriteScreenXY
ldh a, [hOAMBufferOffset]
+ add [hl]
+ cp $a0
+ jr z, .hidden
+ jr nc, .asm_4a41
+.hidden
+ call Func_4a7b
+ ld [wd5cd], a
+ ldh a, [hOAMBufferOffset]
+
ld e, a
ld d, HIGH(wOAMBuffer)
.tileLoop
+ ld a, [hli]
+ ld c, a
+.loop
ldh a, [hSpriteScreenY] ; temp for sprite Y position
add $10 ; Y=16 is top of screen (Y=0 is invisible)
add [hl] ; add Y offset from table
ld [de], a ; write new sprite OAM Y position
inc hl
+ inc e
ldh a, [hSpriteScreenX] ; temp for sprite X position
add $8 ; X=8 is left of screen (X=0 is invisible)
add [hl] ; add X offset from table
+ ld [de], a
+ inc hl
inc e
- ld [de], a ; write new sprite OAM X position
- inc e
- ld a, [bc] ; read pattern number offset (accommodates orientation (offset 0,4 or 8) and animation (offset 0 or $80))
- inc bc
- push bc
+ ld a, [wd5cd]
+ add [hl]
+ cp $80
+ jr c, .asm_4a1c
ld b, a
-
- ld a, [wd5cd] ; temp copy of [x#SPRITESTATEDATA1_IMAGEINDEX]
- 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
+ ldh a, [hFFFC]
+ add b
+.asm_4a1c
ld [de], a ; tile id
inc hl
inc e
@@ -129,15 +118,19 @@ PrepareOAMData::
ldh a, [hSpritePriority]
or [hl]
.skipPriority
- inc hl
+ and $f0
+ bit 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
ldh [hOAMBufferOffset], a
-
.nextSprite
ldh a, [hSpriteOffset2]
add $10
@@ -145,26 +138,31 @@ PrepareOAMData::
jp nz, .spriteLoop
; Clear unused OAM.
- ldh a, [hOAMBufferOffset]
- ld l, a
- ld h, HIGH(wOAMBuffer)
- 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
+ ldh 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 ; [x#SPRITESTATEDATA1_XADJUSTED]
ret
+
+Func_4a7b:
+ push bc
+ ld a, [wd5cd] ; temp copy of [x#SPRITESTATEDATA1_IMAGEINDEX]
+ swap a ; high nybble determines sprite used (0 is always player sprite, next are some npcs)
+ and $f
+
+ ; Sprites $a and $b have one face (and therefore 4 tiles instead of 12).
+ ; As a result, sprite $b's tile offset is less than normal.
+ cp $b
+ jr nz, .notFourTileSprite
+ ld a, $a * 12 + 4 ; $7c
+ jr .done
+
+.notFourTileSprite
+ ; a *= 12
+ add a
+ add a
+ ld c, a
+ add a
+ add c
+.done
+ pop bc
+ ret
+
+INCLUDE "engine/gfx/oam_dma.asm"
+
+_IsTilePassable::
+ ld hl, wTilesetCollisionPtr ; pointer to list of passable tiles
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a ; hl now points to passable tiles
+.loop
+ ld a, [hli]
+ cp a, $ff
+ jr z, .tileNotPassable
+ cp c
+ jr nz, .loop
+ xor a
+ ret
+.tileNotPassable
+ scf
+ ret
+
+INCLUDE "data/tilesets/collision_tile_ids.asm"
diff --git a/engine/items/inventory.asm b/engine/items/inventory.asm
index bf433175..c2e0b2b4 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/item_effects.asm b/engine/items/item_effects.asm
index d4164332..b1b458ab 100755
--- a/engine/items/item_effects.asm
+++ b/engine/items/item_effects.asm
@@ -114,7 +114,9 @@ ItemUseBall:
; If this is for the old man battle, skip checking if the party & box are full.
ld a, [wBattleType]
- dec a
+ cp BATTLE_TYPE_OLD_MAN
+ jr z, .canUseBall
+ cp BATTLE_TYPE_PIKACHU
jr z, .canUseBall
ld a, [wPartyCount] ; is party full?
@@ -153,16 +155,26 @@ ItemUseBall:
jp z, .setAnimData
ld a, [wBattleType]
- dec a
- jr nz, .notOldManBattle
+ cp BATTLE_TYPE_OLD_MAN
+ jr z, .oldManBattle
+ cp BATTLE_TYPE_PIKACHU
+ jr z, .oldManBattle ; pikachu battle technically old man battle
+ jr .notOldManBattle
.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.
@@ -281,6 +293,7 @@ ItemUseBall:
inc a
.skip2
+
; Let W = ((MaxHP * 255) / BallFactor) / max(HP / 4, 1). Calculate W.
ldh [hDivisor], a
ld b, 4
@@ -348,6 +361,7 @@ ItemUseBall:
jr z, .skip4
.skip4
+
; Let Y = (CatchRate * 100) / BallFactor2. Calculate Y.
ld a, b
ldh [hDivisor], a
@@ -372,7 +386,7 @@ ItemUseBall:
ldh [hDivisor], a
ld b, 4
call Divide
-
+
; Determine Status2.
; no status ailment: Status2 = 0
; Burn/Paralysis/Poison: Status2 = 5
@@ -512,9 +526,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
@@ -546,12 +561,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
@@ -584,6 +605,9 @@ ItemUseBall:
ld [wItemQuantity], a
jp RemoveItemFromInventory
+.emptyString
+ db "@"
+
ItemUseBallText00:
;"It dodged the thrown ball!"
;"This pokemon can't be caught"
@@ -649,21 +673,28 @@ ItemUseBicycle:
call ItemUseReloadOverworldData
xor a
ld [wWalkBikeSurfState], a ; change player state to walking
+ ld a, $00
+ ld [wPikachuSpawnState], a
call PlayDefaultMusic ; play walking music
ld hl, GotOffBicycleText
- jr .printText
+ jp PrintText
+
.tryToGetOnBike
call IsBikeRidingAllowed
jp nc, NoCyclingAllowedHere
call ItemUseReloadOverworldData
xor a ; no keys pressed
ldh [hJoyHeld], a ; current joypad state
- inc a
+ ld a, $1
ld [wWalkBikeSurfState], a ; change player state to bicycling
- ld hl, GotOnBicycleText
call PlayDefaultMusic ; play bike riding music
-.printText
- jp PrintText
+ xor a
+ ld [wWalkBikeSurfState], a
+ ld hl, GotOnBicycleText
+ call PrintText
+ ld a, $1
+ ld [wWalkBikeSurfState], a
+ ret
; used for Surf out-of-battle effect
ItemUseSurfboard:
@@ -673,7 +704,7 @@ ItemUseSurfboard:
jr z, .tryToStopSurfing
.tryToSurf
call IsNextTileShoreOrWater
- jp c, SurfingAttemptFailed
+ jp nc, SurfingAttemptFailed
ld hl, TilePairCollisionsWater
call CheckForTilePairCollisions
jp c, SurfingAttemptFailed
@@ -686,6 +717,7 @@ ItemUseSurfboard:
call PlayDefaultMusic ; play surfing music
ld hl, SurfingGotOnText
jp PrintText
+
.tryToStopSurfing
xor a
ldh [hSpriteIndexOrTextID], a
@@ -698,23 +730,20 @@ ItemUseSurfboard:
ld hl, TilePairCollisionsWater
call CheckForTilePairCollisions
jr c, .cannotStopSurfing
- ld hl, wTilesetCollisionPtr ; pointer to list of passable tiles
- ld a, [hli]
- ld h, [hl]
- ld l, a ; hl now points to passable tiles
- ld a, [wTileInFrontOfPlayer] ; tile in front of the player
- ld b, a
-.passableTileLoop
- ld a, [hli]
- cp b
- jr z, .stopSurfing
- cp $ff
- jr nz, .passableTileLoop
+ ld a, [wTileInFrontOfPlayer]
+ ld c, a
+ call IsTilePassable
+ jr nc, .stopSurfing
.cannotStopSurfing
ld hl, SurfingNoPlaceToGetOffText
jp PrintText
+
.stopSurfing
call .makePlayerMoveForward
+ ld a, $3
+ ld [wPikachuSpawnState], a
+ ld hl, wPikachuOverworldStateFlags
+ set 5, [hl]
ld hl, wd730
set 7, [hl]
xor a
@@ -722,7 +751,9 @@ ItemUseSurfboard:
dec a
ld [wJoyIgnore], a
call PlayDefaultMusic ; play walking music
+ call GBPalWhiteOutWithDelay3
jp LoadWalkingPlayerSpriteGraphics
+
; uses a simulated button press to make the player move forward
.makePlayerMoveForward
ld a, [wPlayerDirection] ; direction the player is going
@@ -770,25 +801,43 @@ ItemUseEvoStone:
ld a, $ff
ld [wUpdateSpritesEnabled], a
call DisplayPartyMenu
+ ld a, [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
+ callfar IsThisPartymonStarterPikachu_Party
+ jr nc, .notPlayerPikachu
+ ld e, $1b
+ callfar 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
callfar TryEvolvingMon ; try to evolve pokemon
- ld a, [wEvolutionOccurred]
- and a
- jr z, .noEffect
pop af
ld [wWhichPokemon], a
ld hl, wNumBagItems
ld a, 1 ; remove 1 stone
ld [wItemQuantity], a
jp RemoveItemFromInventory
+
.noEffect
call ItemUseNoEffect
.canceledItemUse
@@ -797,6 +846,55 @@ ItemUseEvoStone:
pop af
ret
+Func_d85d:
+ ld hl, EvosMovesPointerTable
+ ld a, [wLoadedMon]
+ dec a
+ ld c, a
+ ld b, $0
+ add hl, bc
+ add hl, bc
+ ld de, 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:
+ text_far _RefusingText
+ text_end
+
ItemUseVitamin:
ld a, [wIsInBattle]
and a
@@ -805,7 +903,7 @@ ItemUseVitamin:
ItemUseMedicine:
ld a, [wPartyCount]
and a
- jp z, .emptyParty
+ jp z, Func_e4bf
ld a, [wWhichPokemon]
push af
ld a, [wcf91]
@@ -820,15 +918,6 @@ ItemUseMedicine:
; if using softboiled
call GoBackToPartyMenu
jr .getPartyMonDataAddress
-.emptyParty
- ld hl, .emptyPartyText
- xor a
- ld [wActionResultOrTookBattleTurn], a ; item use failed
- jp PrintText
-.emptyPartyText
- text "You don't have"
- line "any #MON!"
- prompt
.notUsingSoftboiled
call DisplayPartyMenu
.getPartyMonDataAddress
@@ -844,6 +933,16 @@ ItemUseMedicine:
ld e, a
ld [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
@@ -911,6 +1010,7 @@ ItemUseMedicine:
call CopyData ; copy party stats to in-battle stat data
predef DoubleOrHalveSelectedStats
jp .doneHealing
+
.healHP
inc hl ; hl = address of current HP
ld a, [hli]
@@ -928,7 +1028,22 @@ ItemUseMedicine:
cp MAX_REVIVE
jr z, .updateInBattleFaintedData
jp .healingItemNoEffect
+
.updateInBattleFaintedData
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wUsedItemOnWhichPokemon]
+ ld [wWhichPokemon], a
+ push hl
+ push de
+ push bc
+ callfar Func_2fd6a
+ pop bc
+ pop de
+ pop hl
+ pop af
+ ld [wWhichPokemon], a
+
ld a, [wIsInBattle]
and a
jr z, .compareCurrentHPToMaxHP
@@ -953,6 +1068,7 @@ ItemUseMedicine:
pop de
pop hl
jr .compareCurrentHPToMaxHP
+
.notFainted
ld a, [wcf91]
cp REVIVE
@@ -988,6 +1104,7 @@ ItemUseMedicine:
dec hl
dec hl
jp .cureStatusAilment
+
.notFullHP ; if the pokemon's current HP doesn't equal its max HP
xor a
ld [wLowHealthAlarm], a ;disable low health alarm
@@ -1051,15 +1168,15 @@ ItemUseMedicine:
call AddNTimes ; calculate coordinates of HP bar of pokemon that used Softboiled
ld a, SFX_HEAL_HP
call PlaySoundWaitForCurrent
- ldh a, [hFlagsFFF6]
+ ldh a, [hFlagsFFFA]
set 0, a
- ldh [hFlagsFFF6], a
+ ldh [hFlagsFFFA], a
ld a, $02
ld [wHPBarType], a
predef UpdateHPBar2 ; animate HP bar decrease of pokemon that used Softboiled
- ldh a, [hFlagsFFF6]
+ ldh a, [hFlagsFFFA]
res 0, a
- ldh [hFlagsFFF6], a
+ ldh [hFlagsFFFA], a
pop af
ld b, a ; store heal amount (1/5 of max HP)
ld hl, wHPBarOldHP + 1
@@ -1072,6 +1189,7 @@ ItemUseMedicine:
pop af
ld [hl], a
jr .addHealAmount
+
.notUsingSoftboiled2
ld a, [wcf91]
cp SODA_POP
@@ -1126,6 +1244,7 @@ ItemUseMedicine:
cp MAX_REVIVE
jr z, .setCurrentHPToMaxHp ; if using a Max Revive
jr .updateInBattleData
+
.setCurrentHPToHalfMaxHP
dec hl
dec de
@@ -1140,6 +1259,7 @@ ItemUseMedicine:
ld [wHPBarNewHP], a
dec de
jr .doneHealingPartyHP
+
.setCurrentHPToMaxHp
ld a, [hli]
ld [de], a
@@ -1183,9 +1303,11 @@ ItemUseMedicine:
dec d
jr nz, .calculateHPBarCoordsLoop
jr .doneHealing
+
.healingItemNoEffect
call ItemUseNoEffect
jp .done
+
.doneHealing
ld a, [wPseudoItemID]
and a ; using Softboiled?
@@ -1201,15 +1323,15 @@ ItemUseMedicine:
jr z, .playStatusAilmentCuringSound
ld a, SFX_HEAL_HP
call PlaySoundWaitForCurrent
- ldh a, [hFlagsFFF6]
+ ldh a, [hFlagsFFFA]
set 0, a
- ldh [hFlagsFFF6], a
+ ldh [hFlagsFFFA], a
ld a, $02
ld [wHPBarType], a
predef UpdateHPBar2 ; animate the HP bar lengthening
- ldh a, [hFlagsFFF6]
+ ldh a, [hFlagsFFFA]
res 0, a
- ldh [hFlagsFFF6], a
+ ldh [hFlagsFFFA], a
ld a, REVIVE_MSG
ld [wPartyMenuTypeOrMessageID], a
ld a, [wcf91]
@@ -1220,6 +1342,7 @@ ItemUseMedicine:
ld a, POTION_MSG
ld [wPartyMenuTypeOrMessageID], a
jr .showHealingItemMessage
+
.playStatusAilmentCuringSound
ld a, SFX_HEAL_AILMENT
call PlaySoundWaitForCurrent
@@ -1236,6 +1359,7 @@ ItemUseMedicine:
call DelayFrames
call WaitForTextScrollButtonPress
jr .done
+
.canceledItemUse
xor a
ld [wActionResultOrTookBattleTurn], a ; item use failed
@@ -1251,6 +1375,7 @@ ItemUseMedicine:
and a
ret nz
jp ReloadMapData
+
.useVitamin
push hl
ld a, [hl]
@@ -1306,6 +1431,7 @@ ItemUseMedicine:
cp b
jr nz, .statNameInnerLoop
jr .statNameLoop
+
.gotStatName
ld de, wcf4b
ld bc, 10
@@ -1315,11 +1441,13 @@ ItemUseMedicine:
ld hl, VitaminStatRoseText
call PrintText
jp RemoveUsedItem
+
.vitaminNoEffect
pop hl
ld hl, VitaminNoEffectText
call PrintText
jp GBPalWhiteOut
+
.recalculateStats
ld bc, wPartyMon1Stats - wPartyMon1
add hl, bc
@@ -1406,9 +1534,19 @@ ItemUseMedicine:
xor a ; PLAYER_PARTY_DATA
ld [wMonDataLocation], a
predef LearnMoveFromLevelUp ; learn level up move, if any
+
xor a
ld [wForceEvolution], a
- callfar TryEvolvingMon ; evolve pokemon, if appropriate
+ callabd_ModifyPikachuHappiness PIKAHAPPY_LEVELUP
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wUsedItemOnWhichPokemon]
+ ld [wWhichPokemon], a
+ callfar Func_2fd6a ; evolve pokemon, if appropriate
+ pop af
+ ld [wWhichPokemon], a
+
+ callfar TryEvolvingMon
ld a, $01
ld [wUpdateSpritesEnabled], a
pop af
@@ -1495,6 +1633,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
@@ -1507,6 +1649,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
@@ -1523,6 +1666,7 @@ ItemUseEscapeRope:
ld c, 30
call DelayFrames
jp RemoveUsedItem
+
.notUsable
jp ItemUseNotTime
@@ -1546,6 +1690,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.
@@ -1559,11 +1704,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
@@ -1586,6 +1733,7 @@ ItemUseCardKey:
ld a, [hl]
ld [wUnusedD71F], a
jr .done
+
.nextEntry1
inc hl
.nextEntry2
@@ -1593,6 +1741,7 @@ ItemUseCardKey:
.nextEntry3
inc hl
jr .loop
+
.done
ld hl, ItemUseText00
call PrintText
@@ -1614,6 +1763,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
@@ -1630,6 +1788,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
@@ -1642,6 +1809,7 @@ ItemUseXStat:
ld a, 2
ld [wActionResultOrTookBattleTurn], a ; item not used
ret
+
.inBattle
ld hl, wPlayerMoveNum
ld a, [hli]
@@ -1660,6 +1828,15 @@ ItemUseXStat:
xor a
ldh [hWhoseTurn], a ; set turn to player's turn
farcall StatModifierUpEffect ; do stat increase move
+
+ ld a, [wWhichPokemon]
+ push af
+ ld a, [wPlayerMonNumber]
+ ld [wWhichPokemon], a
+ callabd_ModifyPikachuHappiness PIKAHAPPY_USEDXITEM
+ pop af
+ ld [wWhichPokemon], a
+
pop hl
pop af
ld [hld], a ; restore [wPlayerMoveEffect]
@@ -1677,31 +1854,48 @@ ItemUsePokeflute:
cp ROUTE_12
jr nz, .notRoute12
CheckEvent EVENT_BEAT_ROUTE12_SNORLAX
- jr nz, .noSnorlaxToWakeUp
+ jr nz, .noSnorlaxOrPikachuToWakeUp
; if the player hasn't beaten Route 12 Snorlax
ld hl, Route12SnorlaxFluteCoords
call ArePlayerCoordsInArray
- jr nc, .noSnorlaxToWakeUp
+ jr nc, .noSnorlaxOrPikachuToWakeUp
ld hl, PlayedFluteHadEffectText
call PrintText
SetEvent EVENT_FIGHT_ROUTE12_SNORLAX
ret
+
.notRoute12
cp ROUTE_16
- jr nz, .noSnorlaxToWakeUp
+ jr nz, .notRoute16
CheckEvent EVENT_BEAT_ROUTE16_SNORLAX
- jr nz, .noSnorlaxToWakeUp
+ jr nz, .noSnorlaxOrPikachuToWakeUp
; if the player hasn't beaten Route 16 Snorlax
ld hl, Route16SnorlaxFluteCoords
call ArePlayerCoordsInArray
- jr nc, .noSnorlaxToWakeUp
+ jr nc, .noSnorlaxOrPikachuToWakeUp
ld hl, PlayedFluteHadEffectText
call PrintText
SetEvent EVENT_FIGHT_ROUTE16_SNORLAX
ret
-.noSnorlaxToWakeUp
+
+.notRoute16
+ cp PEWTER_POKECENTER
+ jr nz, .noSnorlaxOrPikachuToWakeUp
+ call CheckPikachuFollowingPlayer
+ jr z, .noSnorlaxOrPikachuToWakeUp
+ callfar IsPikachuRightNextToPlayer
+ jr nc, .noSnorlaxOrPikachuToWakeUp
+ ld hl, PlayedFluteHadEffectText
+ call PrintText
+ call ItemUseReloadOverworldData
+ ldpikaemotion e, PikachuEmotion26
+ callfar PlaySpecificPikachuEmotion
+ ret
+
+.noSnorlaxOrPikachuToWakeUp
ld hl, PlayedFluteNoEffectText
jp PrintText
+
.inBattle
xor a
ld [wWereAnyMonsAsleep], a
@@ -1721,8 +1915,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?
@@ -1798,8 +1999,7 @@ PlayedFluteHadEffectText:
and a
jr nz, .done
; play out-of-battle pokeflute music
- ld a, SFX_STOP_ALL_MUSIC
- call PlaySound
+ call StopAllMusic
ld a, SFX_POKEFLUTE
ld c, BANK(SFX_Pokeflute)
call PlayMusic
@@ -1860,13 +2060,28 @@ INCLUDE "data/wild/good_rod.asm"
ItemUseSuperRod:
call FishingInit
jp c, ItemUseNotTime
- call ReadSuperRodData
- ld a, e
+ callfar ReadSuperRodData
+ ld c, e
+ ld b, d
+ ld a, $2
+ ld [wRodResponse], a
+ ld a, c
+ and a ; are there fish in the map?
+ jr z, DoNotGenerateFishingEncounter ; if not, do not generate an encounter
+ ld a, $1
+ ld [wRodResponse], a
+ call Random
+ and $1
+ jr nz, RodResponse
+ xor a
+ ld [wRodResponse], a
+ jr DoNotGenerateFishingEncounter
+
RodResponse:
ld [wRodResponse], a
dec a ; is there a bite?
- jr nz, .next
+ jr nz, DoNotGenerateFishingEncounter
; if yes, store level and species data
ld a, 1
ld [wMoveMissed], a
@@ -1875,7 +2090,7 @@ RodResponse:
ld a, c ; species
ld [wCurOpponent], a
-.next
+DoNotGenerateFishingEncounter:
ld hl, wWalkBikeSurfState
ld a, [hl] ; store the value in a
push af
@@ -1895,22 +2110,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
@@ -1963,7 +2184,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
@@ -2003,6 +2240,7 @@ ItemUsePPRestore:
ld hl, PPMaxedOutText
call PrintText
jr .chooseMove
+
.PPNotMaxedOut
ld a, [hl]
add 1 << 6 ; increase PP Up count by 1
@@ -2010,6 +2248,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
@@ -2018,6 +2258,7 @@ ItemUsePPRestore:
call GBPalWhiteOut
call RunDefaultPaletteCommand
jp RemoveUsedItem
+
.afterRestoringPP ; after using a (Max) Ether/Elixir
ld a, [wWhichPokemon]
ld b, a
@@ -2036,10 +2277,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
@@ -2074,6 +2317,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
@@ -2083,6 +2327,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
@@ -2186,6 +2431,7 @@ ItemUseTMHM:
ld a, 2
ld [wActionResultOrTookBattleTurn], a ; item not used
ret
+
.useMachine
ld a, [wWhichPokemon]
push af
@@ -2231,10 +2477,13 @@ ItemUseTMHM:
ld hl, MonCannotLearnMachineMoveText
call PrintText
jr .chooseMon
+
.checkIfAlreadyLearnedMove
callfar CheckIfMoveIsKnown ; check if the pokemon already knows the move
jr c, .chooseMon
predef LearnMove ; teach move
+ ld a, [wWhichPokemon]
+ ld d, a
pop af
ld [wcf91], a
pop af
@@ -2242,6 +2491,28 @@ ItemUseTMHM:
ld a, b
and a
ret z
+
+ ld a, [wWhichPokemon]
+ push af
+ ld a, d
+ ld [wWhichPokemon], a
+ callabd_ModifyPikachuHappiness PIKAHAPPY_USEDTMHM
+ callfar IsThisPartymonStarterPikachu_Party
+ jr nc, .notTeachingThunderboltOrThunderToPikachu
+ ld a, [wcf91]
+ cp TM_THUNDERBOLT ; are we teaching thunderbolt to the player pikachu?
+ jr z, .teachingThunderboltOrThunderToPlayerPikachu
+ cp TM_THUNDER ; are we teaching thunder then?
+ jr nz, .notTeachingThunderboltOrThunderToPikachu
+.teachingThunderboltOrThunderToPlayerPikachu
+ ld a, $5
+ ld [wd49c], a
+ ld a, $85
+ ld [wPikachuMood], a
+.notTeachingThunderboltOrThunderToPikachu
+ pop af
+ ld [wWhichPokemon], a
+
ld a, [wcf91]
call IsItemHM
ret c
@@ -2288,6 +2559,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
@@ -2349,6 +2626,10 @@ BoxFullCannotThrowBallText:
text_far _BoxFullCannotThrowBallText
text_end
+DontHavePokemonText:
+ text_far _DontHavePokemonText
+ text_end
+
ItemUseText00:
text_far _ItemUseText001
text_low
@@ -2483,6 +2764,7 @@ GetMaxPP:
.sourceWithOneMon
call GetSelectedMoveOffset2
jr .next
+
.sourceWithMultipleMon
call GetSelectedMoveOffset
.next
@@ -2584,6 +2866,7 @@ TossItem_::
pop hl
and a
ret
+
.tooImportantToToss
push hl
ld hl, TooImportantToTossText
@@ -2650,7 +2933,7 @@ SendNewMonToBox:
ld a, [wcf91]
ld [wd0b5], a
ld c, a
-.asm_e7b1
+.asm_e6f5
inc de
ld a, [de]
ld b, a
@@ -2658,13 +2941,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
@@ -2676,7 +2959,7 @@ SendNewMonToBox:
ld a, [wNumInBox]
dec a
ld b, a
-.asm_e7db
+.asm_e71f
push bc
push hl
ld bc, NAME_LENGTH
@@ -2688,15 +2971,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
@@ -2710,7 +2993,7 @@ SendNewMonToBox:
ld a, [wNumInBox]
dec a
ld b, a
-.asm_e817
+.asm_e75b
push bc
push hl
ld bc, NAME_LENGTH
@@ -2722,15 +3005,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
@@ -2744,7 +3027,7 @@ SendNewMonToBox:
ld a, [wNumInBox]
dec a
ld b, a
-.asm_e854
+.asm_e798
push bc
push hl
ld bc, wBoxMon2 - wBoxMon1
@@ -2756,8 +3039,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
@@ -2787,11 +3070,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
@@ -2800,89 +3083,52 @@ 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
; used for surfing and fishing
; unsets carry if it is, sets carry if not
-IsNextTileShoreOrWater:
+IsNextTileShoreOrWater::
ld a, [wCurMapTileset]
ld hl, WaterTilesets
ld de, 1
- call IsInArray
- jr nc, .notShoreOrWater
+ call IsInArray ; does the current map allow surfing?
+ ret nc ; if not, return
+ ld hl, WaterTile
ld a, [wCurMapTileset]
cp SHIP_PORT ; Vermilion Dock tileset
- ld a, [wTileInFrontOfPlayer] ; tile in front of player
jr z, .skipShoreTiles ; if it's the Vermilion Dock tileset
- cp $48 ; eastern shore tile in Safari Zone
- jr z, .shoreOrWater
- cp $32 ; usual eastern shore tile
- jr z, .shoreOrWater
+ cp GYM ; eastern shore tile in Safari Zone
+ jr z, .skipShoreTiles
+ cp DOJO ; usual eastern shore tile
+ jr z, .skipShoreTiles
+ ld hl, ShoreTiles
.skipShoreTiles
- cp $14 ; water tile
- jr z, .shoreOrWater
-.notShoreOrWater
- scf
- ret
-.shoreOrWater
- and a
- ret
-
-INCLUDE "data/tilesets/water_tilesets.asm"
-
-ReadSuperRodData:
-; return e = 2 if no fish on this map
-; return e = 1 if a bite, bc = level,species
-; return e = 0 if no bite
- ld a, [wCurMap]
- ld de, 3 ; each fishing group is three bytes wide
- ld hl, SuperRodData
+ ld a, [wTileInFrontOfPlayer]
+ ld de, $1
call IsInArray
- jr c, .ReadFishingGroup
- ld e, $2 ; $2 if no fishing groups found
ret
-.ReadFishingGroup
-; hl points to the fishing group entry in the index
- inc hl ; skip map id
-
- ; read fishing group address
- ld a, [hli]
- ld h, [hl]
- ld l, a
-
- ld b, [hl] ; how many mons in group
- inc hl ; point to data
- ld e, $0 ; no bite yet
-
-.RandomLoop
- call Random
- srl a
- ret c ; 50% chance of no battle
-
- and %11 ; 2-bit random number
- cp b
- jr nc, .RandomLoop ; if a is greater than the number of mons, regenerate
-
- ; get the mon
- add a
- ld c, a
- ld b, $0
- add hl, bc
- ld b, [hl] ; level
- inc hl
- ld c, [hl] ; species
- ld e, $1 ; $1 if there's a bite
- ret
+INCLUDE "data/tilesets/water_tilesets.asm"
-INCLUDE "data/wild/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 ea7fbcad..dcf2665d 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/items/town_map.asm b/engine/items/town_map.asm
index 42d313d9..c401d1c1 100755
--- a/engine/items/town_map.asm
+++ b/engine/items/town_map.asm
@@ -105,6 +105,13 @@ DisplayTownMap:
ld [wWhichTownMapLocation], a
jp .townMapLoop
+.asm_70f87
+ ldh a, [hJoy5]
+ and D_DOWN | D_UP
+ ret z
+ callfar PlayPikachuSoundClip
+ ret
+
INCLUDE "data/maps/town_map_order.asm"
TownMapCursor:
@@ -139,11 +146,14 @@ MonsNestText:
LoadTownMap_Fly::
call ClearSprites
call LoadTownMap
+ ld a, $1
+ ldh [hJoy7], a
call LoadPlayerSpriteGraphics
call LoadFontTilePatterns
ld de, BirdSprite
+ ld b, BANK(BirdSprite)
+ ld c, $c
ld hl, vSprites tile $04
- lb bc, BANK(BirdSprite), 12
call CopyVideoData
ld de, TownMapUpArrow
ld hl, vChars1 tile $6d
@@ -181,7 +191,7 @@ LoadTownMap_Fly::
ld c, 15
call DelayFrames
hlcoord 18, 0
- ld [hl], "▲"
+ ld [hl], "▶"
hlcoord 19, 0
ld [hl], "▼"
pop hl
@@ -215,6 +225,7 @@ LoadTownMap_Fly::
.pressedB
xor a
ld [wTownMapSpriteBlinkingEnabled], a
+ ldh [hJoy7], a
call GBPalWhiteOutWithDelay3
pop hl
pop af
@@ -281,15 +292,14 @@ LoadTownMap:
call ClearScreen
call UpdateSprites
hlcoord 0, 0
- ld b, $12
- ld c, $12
+ lb bc, $12, $12
call TextBoxBorder
call DisableLCD
ld hl, WorldMapTileGraphics
ld de, vChars2 tile $60
ld bc, WorldMapTileGraphicsEnd - WorldMapTileGraphics
ld a, BANK(WorldMapTileGraphics)
- call FarCopyData2
+ call FarCopyData
ld hl, MonNestIcon
ld de, vSprites tile $04
ld bc, MonNestIconEnd - MonNestIcon
@@ -398,8 +408,7 @@ DisplayWildLocations:
jr nz, .drawPlayerSprite
; if no OAM entries were written, print area unknown text
hlcoord 1, 7
- ld b, 2
- ld c, 15
+ lb bc, 2, 15
call TextBoxBorder
hlcoord 2, 9
ld de, AreaUnknownText
diff --git a/engine/joypad.asm b/engine/joypad.asm
index 87f92635..06a15e4e 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.
+ ldh a, [hDisableJoypadPolling]
+ and a
+ ret nz
+
+ ld a, 1 << 5 ; select direction keys
+ ;ld c, 0
+
+ ldh [rJOYP], a
+ ldh a, [rJOYP]
+ ldh a, [rJOYP]
+ cpl
+ and %1111
+ swap a
+ ld b, a
+
+ ld a, 1 << 4 ; select button keys
+ ldh [rJOYP], a
+ REPT 6
+ ldh a, [rJOYP]
+ ENDR
+ cpl
+ and %1111
+ or b
+
+ ldh [hJoyInput], a
+
+ ld a, 1 << 4 + 1 << 5 ; deselect keys
+ ldh [rJOYP], a
+ ret
+
+
_Joypad::
; hJoyReleased: (hJoyLast ^ hJoyInput) & hJoyLast
; hJoyPressed: (hJoyLast ^ hJoyInput) & hJoyInput
ldh a, [hJoyInput]
+ ld b, a
+ and $4F
cp A_BUTTON + B_BUTTON + SELECT + START ; soft reset
jp z, TrySoftReset
- ld b, a
ldh a, [hJoyLast]
ld e, a
xor b
diff --git a/engine/link/cable_club.asm b/engine/link/cable_club.asm
index 71afde1e..c75ab200 100755
--- a/engine/link/cable_club.asm
+++ b/engine/link/cable_club.asm
@@ -10,8 +10,7 @@ CableClub_DoBattleOrTrade:
call LoadHpBarAndStatusTilePatterns
call LoadTrainerInfoTextBoxTiles
hlcoord 3, 8
- ld b, 2
- ld c, 12
+ lb bc, 2, 12
call CableClub_TextBoxBorder
hlcoord 4, 10
ld de, PleaseWaitString
@@ -119,6 +118,7 @@ CableClub_DoBattleOrTradeAgain:
ldh [rSC], a
.skipSendingTwoZeroBytes
call Delay3
+ call StopAllMusic
ld a, (1 << SERIAL)
ldh [rIE], a
ld hl, wSerialRandomNumberListBlock
@@ -139,8 +139,6 @@ CableClub_DoBattleOrTradeAgain:
call Serial_ExchangeBytes
ld a, (1 << SERIAL) | (1 << TIMER) | (1 << VBLANK)
ldh [rIE], a
- ld a, SFX_STOP_ALL_MUSIC
- call PlaySound
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
jr z, .skipCopyingRandomNumberList ; the list generated by the gameboy clocking the connection is used by both gameboys
@@ -261,8 +259,7 @@ CableClub_DoBattleOrTradeAgain:
ld [wUnusedCF8D + 1], a
xor a
ld [wTradeCenterPointerTableIndex], a
- ld a, SFX_STOP_ALL_MUSIC
- call PlaySound
+ call StopAllMusic
ldh a, [hSerialConnectionStatus]
cp USING_INTERNAL_CLOCK
ld c, 66
@@ -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, hFlagsFFF6
+ ld hl, hFlagsFFFA
set 1, [hl]
call HandleMenuInput
- ld hl, hFlagsFFF6
+ ld hl, hFlagsFFFA
res 1, [hl]
and a
jp z, .getNewInput
@@ -403,10 +411,10 @@ TradeCenter_SelectMon:
lb bc, 6, 1
call ClearScreenArea
.playerMonMenu_HandleInput
- ld hl, hFlagsFFF6
+ ld hl, hFlagsFFFA
set 1, [hl]
call HandleMenuInput
- ld hl, hFlagsFFF6
+ ld hl, hFlagsFFFA
res 1, [hl]
and a ; was anything pressed?
jr nz, .playerMonMenu_SomethingPressed
@@ -465,8 +473,7 @@ TradeCenter_SelectMon:
.displayStatsTradeMenu
push af
hlcoord 0, 14
- ld b, 2
- ld c, 18
+ lb bc, 2, 18
call CableClub_TextBoxBorder
hlcoord 2, 16
ld de, .statsTrade
@@ -601,8 +608,7 @@ TradeCenter_DrawCancelBox:
ld bc, 2 * SCREEN_WIDTH + 9
call FillMemory
hlcoord 0, 15
- ld b, 1
- ld c, 9
+ lb bc, 1, 9
call CableClub_TextBoxBorder
hlcoord 2, 16
ld de, CancelTextString
@@ -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:
hlcoord 0, 0
- ld b, 6
- ld c, 18
+ lb bc, 6, 18
call CableClub_TextBoxBorder
hlcoord 0, 8
- ld b, 6
- ld c, 18
+ lb bc, 6, 18
call CableClub_TextBoxBorder
hlcoord 5, 0
ld de, wPlayerName
@@ -685,8 +692,7 @@ TradeCenter_Trade:
ld [wMenuWatchMovingOutOfBounds], a
ld [wMenuJoypadPollCount], a
hlcoord 0, 12
- ld b, 4
- ld c, 18
+ lb bc, 4, 18
call CableClub_TextBoxBorder
ld a, [wTradingWhichPlayerMon]
ld hl, wPartySpecies
@@ -727,8 +733,7 @@ TradeCenter_Trade:
ld a, $1
ld [wSerialExchangeNybbleSendData], a
hlcoord 0, 12
- ld b, 4
- ld c, 18
+ lb bc, 4, 18
call CableClub_TextBoxBorder
hlcoord 1, 14
ld de, TradeCanceled
@@ -744,8 +749,7 @@ TradeCenter_Trade:
jr nz, .doTrade
; if the other person cancelled
hlcoord 0, 12
- ld b, 4
- ld c, 18
+ lb bc, 4, 18
call CableClub_TextBoxBorder
hlcoord 1, 14
ld de, TradeCanceled
@@ -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
@@ -851,9 +856,11 @@ TradeCenter_Trade:
call Serial_PrintWaitingTextAndSyncAndExchangeNybble
ld c, 40
call DelayFrames
+ call Delay3
+ ld b, $9
+ call RunPaletteCommand
hlcoord 0, 12
- ld b, 4
- ld c, 18
+ lb bc, 4, 18
call CableClub_TextBoxBorder
hlcoord 1, 14
ld de, TradeCompleted
diff --git a/engine/link/cable_club_npc.asm b/engine/link/cable_club_npc.asm
index 594adf08..4d0a0a8a 100755
--- a/engine/link/cable_club_npc.asm
+++ b/engine/link/cable_club_npc.asm
@@ -1,9 +1,12 @@
CableClubNPC::
ld hl, CableClubNPCWelcomeText
call PrintText
+ call CheckPikachuFollowingPlayer
+ jr nz, .asm_7048
CheckEvent EVENT_GOT_POKEDEX
jp nz, .receivedPokedex
; if the player hasn't received the pokedex
+.asm_7048
ld c, 60
call DelayFrames
ld hl, CableClubNPCMakingPreparationsText
@@ -107,7 +110,61 @@ CableClubNPC::
xor a
ld [hld], a
ld [hl], a
- jpfar LinkMenu
+ ld a, [wLetterPrintingDelayFlags]
+ push af
+ callfar LinkMenu
+ pop af
+ ld [wLetterPrintingDelayFlags], a
+ ret
+
+; seems to be similar of Serial_SyncAndExchangeNybble
+Serial_SyncAndExchangeNybbleDouble:
+ ld a, $ff
+ ld [wSerialExchangeNybbleReceiveData], a
+.loop
+ call Serial_ExchangeNybble
+ call DelayFrame
+ push hl
+ ld hl, wUnknownSerialCounter + 1
+ dec [hl]
+ jr nz, .next
+ dec hl
+ dec [hl]
+ jr nz, .next
+ pop hl
+ jr .setUnknownSerialCounterToFFFF
+.next
+ pop hl
+ ld a, [wSerialExchangeNybbleReceiveData]
+ inc a
+ jr z, .loop
+ call DelayFrame
+ ld a, $ff
+ ld [wSerialExchangeNybbleReceiveData], a
+ call Serial_ExchangeNybble
+ ld a, [wSerialExchangeNybbleReceiveData]
+ inc a
+ jr z, .loop
+ ld b, 10
+.syncLoop1
+ call DelayFrame
+ call Serial_ExchangeNybble
+ dec b
+ jr nz, .syncLoop1
+ ld b, 10
+.syncLoop2
+ call DelayFrame
+ call Serial_SendZeroByte
+ dec b
+ jr nz, .syncLoop2
+ ld a, [wSerialExchangeNybbleReceiveData]
+ ld [wSerialSyncAndExchangeNybbleReceiveData], a
+ ret
+.setUnknownSerialCounterToFFFF
+ ld a, $ff
+ ld [wUnknownSerialCounter], a
+ ld [wUnknownSerialCounter + 1], a
+ ret
CableClubNPCAreaReservedFor2FriendsLinkedByCableText:
text_far _CableClubNPCAreaReservedFor2FriendsLinkedByCableText
diff --git a/engine/link/print_waiting_text.asm b/engine/link/print_waiting_text.asm
index d74d635f..98a44970 100644
--- a/engine/link/print_waiting_text.asm
+++ b/engine/link/print_waiting_text.asm
@@ -1,15 +1,14 @@
PrintWaitingText::
hlcoord 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
hlcoord 4, 11
ld de, WaitingText
call PlaceString
diff --git a/engine/math/bcd.asm b/engine/math/bcd.asm
index 1e5aedc9..92bf6f17 100644
--- a/engine/math/bcd.asm
+++ b/engine/math/bcd.asm
@@ -1,6 +1,9 @@
+; 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
@@ -40,6 +43,7 @@ DivideBCD::
and $f0
ldh [hDivideBCDDivisor+2], a
jr .mulBy10Loop
+
.next
push de
push de
@@ -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/menus/display_text_id_init.asm b/engine/menus/display_text_id_init.asm
index 6ce76e7f..17f290b4 100644
--- a/engine/menus/display_text_id_init.asm
+++ b/engine/menus/display_text_id_init.asm
@@ -14,19 +14,16 @@ DisplayTextIDInit::
CheckEvent EVENT_GOT_POKEDEX
; start menu with pokedex
hlcoord 10, 0
- ld b, $0e
- ld c, $08
+ lb bc, 14, 8
jr nz, .drawTextBoxBorder
; start menu without pokedex
hlcoord 10, 0
- ld b, $0c
- ld c, $08
+ lb bc, 12, 8
jr .drawTextBoxBorder
; if text ID is not 0 (i.e. not the start menu) then do a standard dialogue text box
.notStartMenu
hlcoord 0, 12
- ld b, $04
- ld c, $12
+ lb bc, 4, 18
.drawTextBoxBorder
call TextBoxBorder
.skipDrawingTextBoxBorder
diff --git a/engine/menus/draw_start_menu.asm b/engine/menus/draw_start_menu.asm
index 00d385bc..7ca75ecb 100644
--- a/engine/menus/draw_start_menu.asm
+++ b/engine/menus/draw_start_menu.asm
@@ -3,13 +3,11 @@ DrawStartMenu::
CheckEvent EVENT_GOT_POKEDEX
; menu with pokedex
hlcoord 10, 0
- ld b, $0e
- ld c, $08
+ lb bc, 14, 8
jr nz, .drawTextBoxBorder
; shorter menu if the player doesn't have the pokedex
hlcoord 10, 0
- ld b, $0c
- ld c, $08
+ lb bc, 12, 8
.drawTextBoxBorder
call TextBoxBorder
ld a, 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/menus/league_pc.asm b/engine/menus/league_pc.asm
index f2107c49..5551fd0b 100755
--- a/engine/menus/league_pc.asm
+++ b/engine/menus/league_pc.asm
@@ -100,8 +100,7 @@ LeaguePCShowMon:
call LoadFrontSpriteByMonIndex
call GBPalNormal
hlcoord 0, 13
- ld b, 2
- ld c, $12
+ lb bc, 2, 18
call TextBoxBorder
hlcoord 1, 15
ld de, HallOfFameNoText
@@ -110,7 +109,7 @@ LeaguePCShowMon:
ld de, wHoFTeamNo
lb bc, 1, 3
call PrintNumber
- farjp HoFDisplayMonInfo
+ farjp Func_7033f
HallOfFameNoText:
db "HALL OF FAME No @"
diff --git a/engine/menus/link_menu.asm b/engine/menus/link_menu.asm
new file mode 100644
index 00000000..2f2db573
--- /dev/null
+++ b/engine/menus/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]
+ ldh [hSerialSendData], a
+ call Serial_ExchangeByte
+ push af
+ ld hl, wLinkMenuSelectionSendBuffer
+ ld a, [hl]
+ ldh [hSerialSendData], a
+ call Serial_ExchangeByte
+ pop bc
+ cp b
+ jr nz, .asm_f5399
+ and $f0
+ cp $c0
+ jr nz, .asm_f5399
+ ld a, b
+ and $c
+ jr nz, .asm_f53c4
+ ld a, [wLinkMenuSelectionSendBuffer]
+ and $c
+ jr z, .asm_f5377
+ jr .asm_f53df
+.asm_f53c4
+ ld a, [wLinkMenuSelectionSendBuffer]
+ and $c
+ jr z, .asm_f53d1
+ ldh a, [hSerialConnectionStatus]
+ cp $2
+ jr z, .asm_f53df
+.asm_f53d1
+ ld a, $1
+ ld [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]
+ ldh [hSerialSendData], a
+ call Serial_ExchangeByte
+ call Serial_ExchangeByte
+ ld b, $14
+.loop
+ call DelayFrame
+ call Serial_SendZeroByte
+ dec b
+ jr nz, .loop
+ ld b, " "
+ ld c, " "
+ ld d, " "
+ ld e, "▷"
+ ld a, [wLinkMenuSelectionSendBuffer]
+ bit 3, a
+ jr nz, .asm_f541a
+ ld b, e
+ ld e, c
+ ld a, [wCurrentMenuItem]
+ and a
+ jr z, .asm_f541a
+ ld c, b
+ ld b, d
+ dec a
+ jr z, .asm_f541a
+ ld d, c
+ ld c, b
+.asm_f541a
+ ld a, b
+ ldcoord_a 9, 2
+ ld a, c
+ ldcoord_a 9, 4
+ ld a, d
+ ldcoord_a 9, 6
+ ld a, e
+ ldcoord_a 9, 8
+ ld c, 40
+ call DelayFrames
+ ld a, [wLinkMenuSelectionSendBuffer]
+ bit 3, a
+ jr nz, asm_f547f
+ ld a, [wCurrentMenuItem]
+ cp $3
+ jr z, asm_f547f
+ inc a
+ ld [wUnknownSerialFlag_d499], a
+ ld a, [wCurrentMenuItem]
+ ld hl, PointerTable_f5488
+ ld c, a
+ ld b, $0
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld de, .returnaddress
+ push de
+ jp hl
+.returnaddress
+ ld [wLinkMenuSelectionSendBuffer], a
+ xor a
+ ld [wUnknownSerialCounter], a
+ ld [wUnknownSerialCounter+1], a
+ call Serial_SyncAndExchangeNybble
+ ld a, [wLinkMenuSelectionSendBuffer]
+ and a
+ jr nz, asm_f547c
+ ld a, [wLinkMenuSelectionReceiveBuffer]
+ and a
+ jr nz, Func_f5476
+ xor a
+ ld [wUnknownSerialCounter], a
+ ld [wUnknownSerialCounter+1], a
+ and a
+ ret
+
+Func_f5476::
+ ld hl, ColosseumIneligibleText
+ call PrintText
+asm_f547c::
+ jp Func_f531b
+
+asm_f547f::
+ xor a
+ ld [wUnknownSerialCounter], a
+ ld [wUnknownSerialCounter+1], a
+ scf
+ ret
+
+PointerTable_f5488::
+ dw PokeCup
+ dw PikaCup
+ dw PetitCup
+
+PokeCup::
+ ld hl, wPartyCount
+ ld a, [hli]
+ cp $3
+ jp nz, NotThreeMonsInParty
+ ld b, $3
+.loop
+ ld a, [hli]
+ cp MEW
+ jp z, MewInParty
+ dec b
+ jr nz, .loop
+ dec hl
+ dec hl
+ cp [hl] ; is third mon second mon?
+ jp z, DuplicateSpecies
+ dec hl ; wPartySpecies
+ cp [hl] ; is third mon first mon?
+ jp z, DuplicateSpecies
+ ld a, [hli]
+ cp [hl] ; is first mon second mon?
+ jp z, DuplicateSpecies
+ ld a, [wPartyMon1Level]
+ cp 56
+ jp nc, LevelAbove55
+ cp 50
+ jp c, LevelUnder50
+ ld b, a
+ ld a, [wPartyMon2Level]
+ cp 56
+ jp nc, LevelAbove55
+ cp 50
+ jp c, LevelUnder50
+ ld c, a
+ ld a, [wPartyMon3Level]
+ cp 56
+ jp nc, LevelAbove55
+ cp 50
+ jp c, LevelUnder50
+ add b
+ add c
+ cp 156
+ jp nc, CombinedLevelsGreaterThan155
+ xor a
+ ret
+
+PikaCup::
+ ld hl, wPartyCount
+ ld a, [hli]
+ cp $3
+ jp nz, NotThreeMonsInParty
+ ld b, $3
+.loop
+ ld a, [hli] ; wPartySpecies
+ cp MEW
+ jp z, MewInParty
+ dec b
+ jr nz, .loop
+ dec hl
+ dec hl
+ cp [hl] ; is third mon second mon?
+ jp z, DuplicateSpecies
+ dec hl ; wPartySpecies
+ cp [hl] ; is third mon first mon?
+ jp z, DuplicateSpecies
+ ld a, [hli]
+ cp [hl] ; is first mon second mon?
+ jp z, DuplicateSpecies
+ ld a, [wPartyMon1Level]
+ cp 21
+ jp nc, LevelAbove20
+ cp 15
+ jp c, LevelUnder15
+ ld b, a
+ ld a, [wPartyMon2Level]
+ cp 21
+ jp nc, LevelAbove20
+ cp 15
+ jp c, LevelUnder15
+ ld c, a
+ ld a, [wPartyMon3Level]
+ cp 21
+ jp nc, LevelAbove20
+ cp 15
+ jp c, LevelUnder15
+ add b
+ add c
+ cp 51
+ jp nc, CombinedLevelsAbove50
+ xor a
+ ret
+
+PetitCup::
+ ld hl, wPartyCount
+ ld a, [hli]
+ cp $3
+ jp nz, NotThreeMonsInParty
+ ld b, $3
+.loop
+ ld a, [hli]
+ cp MEW
+ jp z, MewInParty
+ dec b
+ jr nz, .loop
+ dec hl
+ dec hl
+ cp [hl] ; is third mon second mon?
+ jp z, DuplicateSpecies
+ dec hl ; wPartySpecies
+ cp [hl] ; is third mon first mon?
+ jp z, DuplicateSpecies
+ ld a, [hli]
+ cp [hl] ; is first mon second mon?
+ jp z, DuplicateSpecies
+ dec hl
+ ld a, [hl]
+ ld [wcf91], a
+ push hl
+ callfar Func_3b10f
+ pop hl
+ jp c, asm_f56ad
+ inc hl
+ ld a, [hl]
+ ld [wcf91], a
+ push hl
+ callfar Func_3b10f
+ pop hl
+ jp c, asm_f56ad
+ inc hl
+ ld a, [hl]
+ ld [wcf91], a
+ push hl
+ callfar Func_3b10f
+ pop hl
+ jp c, asm_f56ad
+ dec hl
+ dec hl
+ ld b, $3
+.bigloop
+ ld a, [hli]
+ push hl
+ push bc
+ push af
+ dec a
+ ld c, a
+ ld b, $0
+ ld hl, PokedexEntryPointers
+ add hl, bc
+ add hl, bc
+ ld de, 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
+ ldh [hAutoBGTransferEnabled], 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
+ ldh [hAutoBGTransferEnabled], a
+ ret
+
+PointerTable_f56ee::
+ dw Text_f56f4
+ dw Text_f5728
+ dw Text_f575b
+
+Text_f56f4::
+ db "LVs of 3<PKMN>:50-55"
+ next "Sum of LVs:155 MAX"
+ next "MEW can't attend.@"
+
+Text_f5728::
+ db "LVs of 3<PKMN>:15-20"
+ next "Sum of LVs:50 MAX"
+ next "MEW can't attend.@"
+
+Text_f575b::
+ db "3 Basic <PKMN>.LV25-30"
+ next "Sum of LVs:80 MAX"
+ next "6’8” and 44lb MAX@"
+
+Text_f5791::
+ db "View"
+ next "Rules@"
+
+Text_f579c::
+ db "# Cup"
+ next "Pika Cup"
+ next "Petit Cup"
+ next "CANCEL@"
+
+Colosseum3MonsText::
+ text_far _Colosseum3MonsText
+ text_end
+
+ColosseumMewText::
+ text_far _ColosseumMewText
+ text_end
+
+ColosseumDifferentMonsText::
+ text_far _ColosseumDifferentMonsText
+ text_end
+
+ColosseumMaxL55Text::
+ text_far _ColosseumMaxL55Text
+ text_end
+
+ColosseumMinL50Text::
+ text_far _ColosseumMinL50Text
+ text_end
+
+ColosseumTotalL155Text::
+ text_far _ColosseumTotalL155Text
+ text_end
+
+ColosseumMaxL30Text::
+ text_far _ColosseumMaxL30Text
+ text_end
+
+ColosseumMinL25Text::
+ text_far _ColosseumMinL25Text
+ text_end
+
+ColosseumTotalL80Text::
+ text_far _ColosseumTotalL80Text
+ text_end
+
+ColosseumMaxL20Text::
+ text_far _ColosseumMaxL20Text
+ text_end
+
+ColosseumMinL15Text::
+ text_far _ColosseumMinL15Text
+ text_end
+
+ColosseumTotalL50Text::
+ text_far _ColosseumTotalL50Text
+ text_end
+
+ColosseumHeightText::
+ text_far _ColosseumHeightText
+ text_end
+
+ColosseumWeightText::
+ text_far _ColosseumWeightText
+ text_end
+
+ColosseumEvolvedText::
+ text_far _ColosseumEvolvedText
+ text_end
+
+ColosseumIneligibleText::
+ text_far _ColosseumIneligibleText
+ text_end
+
+LinkMenu:
+ xor a
+ ld [wLetterPrintingDelayFlags], a
+ ld hl, wd72e
+ set 6, [hl]
+ ld hl, TextTerminator_f5a16
+ call PrintText
+ call SaveScreenTilesToBuffer1
+ ld hl, ColosseumWhereToText
+ call PrintText
+ hlcoord 5, 3
+ lb bc, 8, 13
+ call TextBoxBorder
+ call UpdateSprites
+ hlcoord 7, 5
+ ld de, TradeCenterText
+ call PlaceString
+ xor a
+ ld [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.
+ ldh 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
+ ldh a, [hSerialConnectionStatus]
+ cp USING_INTERNAL_CLOCK
+ jr nz, .skipStartingTransfer
+ call DelayFrame
+ call DelayFrame
+ ld a, START_TRANSFER_INTERNAL_CLOCK
+ ldh [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
+ callfar 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
+ jpfar SpecialEnterMap
+.choseCancel
+ xor a
+ ld [wMenuJoypadPollCount], a
+ call Delay3
+ callfar 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
+ ldh a, [hSerialConnectionStatus]
+ cp $2
+ call z, DelayFrame
+ dec b
+ jr z, .asm_f59b2
+ call Serial_ExchangeNybble
+ call DelayFrame
+ ld a, [wSerialExchangeNybbleReceiveData]
+ inc a
+ jr z, .loop
+ ld b, $f
+.loop2
+ call DelayFrame
+ call Serial_ExchangeNybble
+ dec b
+ jr nz, .loop2
+ ld b, $f
+.loop3
+ call DelayFrame
+ call Serial_SendZeroByte
+ dec b
+ jr nz, .loop3
+ jr .asm_f59d6
+
+.asm_f59b2
+ xor a
+ ld [wUnknownSerialCounter], a
+ ld [wUnknownSerialCounter+1], a
+ ld a, [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
+ ldcoord_a 6, 5
+ ld a, c
+ ldcoord_a 6, 7
+ ld a, d
+ ldcoord_a 6, 9
+ ld a, e
+ ldcoord_a 6, 11
+ ld c, 40
+ call DelayFrames
+ ret
+
+ColosseumWhereToText:
+ text_far _ColosseumWhereToText
+ text_end
+
+ColosseumPleaseWaitText:
+ text_far _ColosseumPleaseWaitText
+ text_end
+
+ColosseumCanceledText:
+ text_far _ColosseumCanceledText
+ text_end
+
+ColosseumVersionText:
+ text_far _ColosseumVersionText
+ text_end
+
+TextTerminator_f5a16:
+ text_end
+
+TradeCenterText:
+ db "TRADE CENTER"
+ next "COLOSSEUM"
+ next "COLOSSEUM2"
+ next "CANCEL@"
diff --git a/engine/menus/main_menu.asm b/engine/menus/main_menu.asm
index 95404cce..7d81d2f6 100755
--- a/engine/menus/main_menu.asm
+++ b/engine/menus/main_menu.asm
@@ -34,8 +34,7 @@ MainMenu:
jr z, .noSaveFile
; there's a save file
hlcoord 0, 0
- ld b, 6
- ld c, 13
+ lb bc, 6, 13
call TextBoxBorder
hlcoord 2, 2
ld de, ContinueText
@@ -43,8 +42,7 @@ MainMenu:
jr .next2
.noSaveFile
hlcoord 0, 0
- ld b, 4
- ld c, 13
+ lb bc, 4, 13
call TextBoxBorder
hlcoord 2, 2
ld de, NewGameText
@@ -129,179 +127,21 @@ 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, LinkMenuEmptyText
- call PrintText
- call SaveScreenTilesToBuffer1
- ld hl, WhereWouldYouLikeText
- call PrintText
- hlcoord 5, 5
- ld b, $6
- ld c, $d
- call TextBoxBorder
- call UpdateSprites
- hlcoord 7, 7
- ld de, CableClubOptionsText
- call PlaceString
- xor a
- ld [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.
- ldh a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- jr z, .doneChoosingMenuSelection
-.useEnemyMenuSelection
- ld a, b
- ld [wLinkMenuSelectionSendBuffer], a
- and $3
- ld [wCurrentMenuItem], a
-.doneChoosingMenuSelection
- ldh a, [hSerialConnectionStatus]
- cp USING_INTERNAL_CLOCK
- jr nz, .skipStartingTransfer
- call DelayFrame
- call DelayFrame
- ld a, START_TRANSFER_INTERNAL_CLOCK
- ldh [rSC], a
-.skipStartingTransfer
- ld b, " "
- ld c, " "
- ld d, "▷"
- 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
- ldcoord_a 6, 7
- ld a, c
- ldcoord_a 6, 9
- ld a, d
- ldcoord_a 6, 11
- ld c, 40
- call DelayFrames
- call LoadScreenTilesFromBuffer1
- ld a, [wLinkMenuSelectionSendBuffer]
- and (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:
- text_far _WhereWouldYouLikeText
- text_end
-
-PleaseWaitText:
- text_far _PleaseWaitText
- text_end
-
-LinkCanceledText:
- text_far _LinkCanceledText
+NotEnoughMemoryText:
+ text_far _NotEnoughMemoryText
text_end
StartNewGame:
@@ -309,6 +149,8 @@ StartNewGame:
res 1, [hl]
StartNewGameDebug:
call OakSpeech
+ ld a, $8
+ ld [wPlayerMovingDirection], a
ld c, 20
call DelayFrames
@@ -324,6 +166,7 @@ SpecialEnterMap::
call ResetPlayerSpriteData
ld c, 20
call DelayFrames
+ call Func_5cc1
ld a, [wEnteringCableClub]
and a
ret nz
@@ -338,17 +181,11 @@ NewGameText:
db "NEW GAME"
next "OPTION@"
-CableClubOptionsText:
- db "TRADE CENTER"
- next "COLOSSEUM"
- next "CANCEL@"
-
DisplayContinueGameInfo:
xor a
ldh [hAutoBGTransferEnabled], a
hlcoord 4, 7
- ld b, 8
- ld c, 14
+ lb bc, 8, 14
call TextBoxBorder
hlcoord 5, 9
ld de, SaveScreenInfoText
@@ -371,8 +208,7 @@ PrintSaveScreenText:
xor a
ldh [hAutoBGTransferEnabled], a
hlcoord 4, 0
- ld b, $8
- ld c, $e
+ lb bc, 8, 14
call TextBoxBorder
call LoadTextBoxTilePatterns
call UpdateSprites
@@ -430,259 +266,8 @@ SaveScreenInfoText:
next "TIME@"
DisplayOptionMenu:
- hlcoord 0, 0
- ld b, 3
- ld c, 18
- call TextBoxBorder
- hlcoord 0, 5
- ld b, 3
- ld c, 18
- call TextBoxBorder
- hlcoord 0, 10
- ld b, 3
- ld c, 18
- call TextBoxBorder
- hlcoord 1, 1
- ld de, TextSpeedOptionText
- call PlaceString
- hlcoord 1, 6
- ld de, BattleAnimationOptionText
- call PlaceString
- hlcoord 1, 11
- ld de, BattleStyleOptionText
- call PlaceString
- hlcoord 2, 16
- ld de, OptionMenuCancelText
- call PlaceString
- xor a
- ld [wCurrentMenuItem], a
- ld [wLastMenuItem], a
- inc a
- ld [wLetterPrintingDelayFlags], a
- ld [wOptionsCancelCursorX], a
- ld a, 3 ; text speed cursor Y coordinate
- ld [wTopMenuItemY], a
- call SetCursorPositionsFromOptions
- ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate
- ld [wTopMenuItemX], a
- ld a, $01
- ldh [hAutoBGTransferEnabled], a ; enable auto background transfer
- call Delay3
-.loop
- call PlaceMenuCursor
- call SetOptionsFromCursorPositions
-.getJoypadStateLoop
- call JoypadLowSensitivity
- ldh a, [hJoy5]
- ld b, a
- and 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
+ callfar 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
- hlcoord 0, 3
- call .placeUnfilledRightArrow
- sla c
- ld a, 1 ; On
- jr nc, .storeBattleAnimationCursorX
- ld a, 10 ; Off
-.storeBattleAnimationCursorX
- ld [wOptionsBattleAnimCursorX], a ; battle animation cursor X coordinate
- hlcoord 0, 8
- call .placeUnfilledRightArrow
- sla c
- ld a, 1
- jr nc, .storeBattleStyleCursorX
- ld a, 10
-.storeBattleStyleCursorX
- ld [wOptionsBattleStyleCursorX], a ; battle style cursor X coordinate
- hlcoord 0, 13
- call .placeUnfilledRightArrow
-; cursor in front of Cancel
- hlcoord 0, 16
- ld a, 1
-.placeUnfilledRightArrow
- ld e, a
- ld d, 0
- add hl, de
- ld [hl], "▷"
- ret
-
-; table that indicates how the 3 text speed options affect frame delays
-; Format:
-; 00: X coordinate of menu cursor
-; 01: delay after printing a letter (in frames)
-TextSpeedOptionData:
- db 14, 5 ; Slow
- db 7, 3 ; Medium
- db 1, 1 ; Fast
- db 7 ; default X coordinate (Medium)
- db -1 ; end
CheckForPlayerNameInSRAM:
; Check if the player name data in SRAM has a string terminator character
diff --git a/engine/menus/naming_screen.asm b/engine/menus/naming_screen.asm
index 9347212e..553c47d0 100755
--- a/engine/menus/naming_screen.asm
+++ b/engine/menus/naming_screen.asm
@@ -5,8 +5,7 @@ AskName:
ld a, [wIsInBattle]
dec a
hlcoord 0, 0
- ld b, 4
- ld c, 11
+ lb bc, 4, 11
call z, ClearScreenArea ; only if in wild battle
ld a, [wcf91]
ld [wd11e], a
@@ -94,8 +93,7 @@ DisplayNamingScreen:
call LoadEDTile
farcall LoadMonPartySpriteGfx
hlcoord 0, 4
- ld b, 9
- ld c, 18
+ lb bc, 9, 18
call TextBoxBorder
call PrintNamingText
ld a, 3
@@ -324,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 tile $70
- 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
+ ldh a, [rSTAT]
+ and %10 ; in HBlank?
+ jr nz, .waitForHBlankLoop
+ ld a, [de]
+ ld [hli], a
+ ld [hli], a
+ inc de
+ ld a, [de]
+ ld [hli], a
+ ld [hli], a
+ inc de
+ dec c
+ jr nz, .waitForHBlankLoop
+ ret
ED_Tile:
INCBIN "gfx/font/ED.1bpp"
diff --git a/engine/menus/options.asm b/engine/menus/options.asm
new file mode 100644
index 00000000..110bef2a
--- /dev/null
+++ b/engine/menus/options.asm
@@ -0,0 +1,443 @@
+DisplayOptionMenu_:
+ call InitOptionsMenu
+.optionMenuLoop
+ call JoypadLowSensitivity
+ ldh 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
+ ldh 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]
+ hlcoord 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:
+ ldh 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]
+ hlcoord 14, 4
+ call PlaceString
+ and a
+ ret
+
+AnimationOptionStringsPointerTable:
+ dw AnimationOnText
+ dw AnimationOffText
+
+AnimationOnText:
+ db "ON @"
+AnimationOffText:
+ db "OFF@"
+
+OptionsMenu_BattleStyle:
+ ldh 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]
+ hlcoord 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
+ ldh 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
+ ldh [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]
+ hlcoord 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
+ ldh 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]
+ hlcoord 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:
+ ldh a, [hJoy5]
+ and A_BUTTON
+ jr nz, .pressedCancel
+ and a
+ ret
+.pressedCancel
+ scf
+ ret
+
+OptionsControl:
+ ld hl, wOptionsCursorLocation
+ ldh 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:
+ hlcoord 1, 1
+ ld de, SCREEN_WIDTH
+ ld c, 16
+.loop
+ ld [hl], " "
+ add hl, de
+ dec c
+ jr nz, .loop
+ hlcoord 1, 2
+ ld bc, SCREEN_WIDTH * 2
+ ld a, [wOptionsCursorLocation]
+ call AddNTimes
+ ld [hl], "▶"
+ ret
+
+InitOptionsMenu:
+ hlcoord 0, 0
+ lb bc, SCREEN_HEIGHT - 2, SCREEN_WIDTH - 2
+ call TextBoxBorder
+ hlcoord 2, 2
+ ld de, AllOptionsText
+ call PlaceString
+ hlcoord 2, 16
+ ld de, OptionMenuCancelText
+ call PlaceString
+ xor a
+ ld [wOptionsCursorLocation], a
+ ld c, 5 ; the number of options to loop through
+.loop
+ push bc
+ call GetOptionPointer ; updates the next option
+ pop bc
+ ld hl, wOptionsCursorLocation
+ inc [hl] ; moves the cursor for the highlighted option
+ dec c
+ jr nz, .loop
+ xor a
+ ld [wOptionsCursorLocation], a
+ inc a
+ ldh [hAutoBGTransferEnabled], a
+ call Delay3
+ ret
+
+AllOptionsText:
+ db "TEXT SPEED :"
+ next "ANIMATION :"
+ next "BATTLESTYLE:"
+ next "SOUND:"
+ next "PRINT:@"
+
+OptionMenuCancelText:
+ db "CANCEL@"
diff --git a/engine/menus/party_menu.asm b/engine/menus/party_menu.asm
index 6648ab54..32f47f6a 100755
--- a/engine/menus/party_menu.asm
+++ b/engine/menus/party_menu.asm
@@ -30,9 +30,17 @@ RedrawPartyMenu_::
call GetPartyMonName
pop hl
call PlaceString ; print the pokemon's name
- farcall WriteMonPartySpriteOAMByPartyIndex ; place the appropriate pokemon icon
ldh a, [hPartyMonIndex]
ld [wWhichPokemon], a
+ callfar IsThisPartymonStarterPikachu_Party
+ jr nc, .regularMon
+ call CheckPikachuFollowingPlayer
+ jr z, .regularMon
+ ld a, $ff
+ ldh [hPartyMonIndex], a
+.regularMon
+ farcall WriteMonPartySpriteOAMByPartyIndex ; place the appropriate pokemon icon
+ ld a, [wWhichPokemon]
inc a
ldh [hPartyMonIndex], a
call LoadMonData
@@ -69,14 +77,14 @@ RedrawPartyMenu_::
pop hl
push hl
ld bc, SCREEN_WIDTH + 1 ; down 1 row and right 1 column
- ldh a, [hFlagsFFF6]
+ ldh a, [hFlagsFFFA]
set 0, a
- ldh [hFlagsFFF6], a
+ ldh [hFlagsFFFA], a
add hl, bc
predef DrawHP2 ; draw HP bar and prints current / max HP
- ldh a, [hFlagsFFF6]
+ ldh a, [hFlagsFFFA]
res 0, a
- ldh [hFlagsFFF6], a
+ ldh [hFlagsFFFA], a
call SetPartyMenuHPBarColor ; color the HP bar (on SGB)
pop hl
jr .printLevel
@@ -90,8 +98,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
@@ -157,9 +165,9 @@ RedrawPartyMenu_::
; if it does match
ld de, .ableToEvolveText
.placeEvolutionStoneString
- ld bc, 20 + 9 ; down 1 row and right 9 columns
pop hl
push hl
+ ld bc, 20 + 9 ; down 1 row and right 9 columns
add hl, bc
call PlaceString
pop hl
diff --git a/engine/menus/players_pc.asm b/engine/menus/players_pc.asm
index 5461be51..1fac030b 100755
--- a/engine/menus/players_pc.asm
+++ b/engine/menus/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
hlcoord 0, 0
- ld b, $8
- ld c, $e
+ lb bc, 8, 14
call TextBoxBorder
call UpdateSprites
hlcoord 2, 2
diff --git a/engine/menus/pokedex.asm b/engine/menus/pokedex.asm
index 5660ecfb..874fe50f 100755
--- a/engine/menus/pokedex.asm
+++ b/engine/menus/pokedex.asm
@@ -12,9 +12,10 @@ ShowPokedexMenu:
ld [wd11e], a
ldh [hJoy7], a
.setUpGraphics
+ callfar LoadPokedexTilePatterns
+.loop
ld b, SET_PAL_GENERIC
call RunPaletteCommand
- callfar LoadPokedexTilePatterns
.doPokemonListMenu
ld hl, wTopMenuItemY
ld a, 3
@@ -43,12 +44,15 @@ ShowPokedexMenu:
call GBPalWhiteOutWithDelay3
call RunDefaultPaletteCommand
jp ReloadMapData
+
.goToSideMenu
call HandlePokedexSideMenu
dec b
jr z, .exitPokedex ; if the player chose Quit
dec b
jr z, .doPokemonListMenu ; if pokemon not seen or player pressed B button
+ dec b
+ jr z, .loop
jp .setUpGraphics ; if pokemon data or area was shown
; handles the menu on the lower right in the pokedex screen
@@ -79,20 +83,21 @@ HandlePokedexSideMenu:
jr z, .exitSideMenu
call PokedexToIndex
ld hl, wTopMenuItemY
- ld a, 10
+ ld a, 8
ld [hli], a ; top menu item Y
ld a, 15
ld [hli], a ; top menu item X
xor a
ld [hli], a ; current menu item ID
inc hl
- ld a, 3
+ ld a, 4
ld [hli], a ; max menu item ID
- ;ld a, 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
+ ldh [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
+ ldh [hJoy7], a
push bc
hlcoord 0, 3
ld de, 20
@@ -128,9 +137,9 @@ HandlePokedexSideMenu:
.buttonBPressed
push bc
- hlcoord 15, 10
+ hlcoord 15, 8
ld de, 20
- lb bc, " ", 7
+ lb bc, " ", 9
call DrawTileLine ; cover up the menu cursor in the side menu
pop bc
jr .exitSideMenu
@@ -152,13 +161,105 @@ HandlePokedexSideMenu:
ld b, 0
jr .exitSideMenu
+.chosePrint
+ ldh a, [hTilesetType]
+ push af
+ xor a
+ ldh [hTilesetType], a
+ ld a, [wd11e]
+ ld [wcf91], a
+ callfar PrintPokedexEntry
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call ClearScreen
+ pop af
+ ldh [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
ldh [hAutoBGTransferEnabled], a
; draw the horizontal line separating the seen and owned amounts from the menu
- hlcoord 15, 8
+ hlcoord 15, 6
ld a, "─"
ld [hli], a
ld [hli], a
@@ -175,26 +276,26 @@ HandlePokedexListMenu:
ld b, wPokedexSeenEnd - wPokedexSeen
call CountSetBits
ld de, wNumSetBits
- hlcoord 16, 3
+ hlcoord 16, 2
lb bc, 1, 3
call PrintNumber ; print number of seen pokemon
ld hl, wPokedexOwned
ld b, wPokedexOwnedEnd - wPokedexOwned
call CountSetBits
ld de, wNumSetBits
- hlcoord 16, 6
+ hlcoord 16, 5
lb bc, 1, 3
call PrintNumber ; print number of owned pokemon
- hlcoord 16, 2
+ hlcoord 16, 1
ld de, PokedexSeenText
call PlaceString
- hlcoord 16, 5
+ hlcoord 16, 4
ld de, PokedexOwnText
call PlaceString
hlcoord 1, 1
ld de, PokedexContentsText
call PlaceString
- hlcoord 16, 10
+ hlcoord 16, 8
ld de, PokedexMenuItemsText
call PlaceString
; find the highest pokedex number among the pokemon the player has seen
@@ -214,7 +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
ldh [hAutoBGTransferEnabled], a
hlcoord 4, 2
@@ -282,98 +413,8 @@ HandlePokedexListMenu:
ld a, 01
ldh [hAutoBGTransferEnabled], 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
ldh [rNR50], a
+ ldh a, [hTilesetType]
+ push af
+ xor a
+ ldh [hTilesetType], a
call GBPalWhiteOut ; zero all palettes
- call ClearScreen
ld a, [wd11e] ; pokemon ID
ld [wcf91], a
push af
@@ -410,10 +454,42 @@ ShowPokedexDataInternal:
call RunPaletteCommand
pop af
ld [wd11e], a
- ldh a, [hTilesetType]
- push af
- xor a
+ call DrawDexEntryOnScreen
+ call c, Pokedex_PrintFlavorTextAtRow11
+.waitForButtonPress
+ call JoypadLowSensitivity
+ ldh a, [hJoy5]
+ and a, A_BUTTON | B_BUTTON
+ jr z, .waitForButtonPress
+ pop af
ldh [hTilesetType], a
+ call GBPalWhiteOut
+ call ClearScreen
+ call RunDefaultPaletteCommand
+ call LoadTextBoxTilePatterns
+ call GBPalNormal
+ ld hl, wd72c
+ res 1, [hl]
+ ld a, $77 ; max volume
+ ldh [rNR50], a
+ ret
+
+HeightWeightText:
+ db "HT ?′??″"
+ 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, $69, $6B, $69, $6B, $6B
+ db $6B, $6B, $69, $6B, $69, $6B, $69, $6B, $69, $6A
+ db "@"
+
+DrawDexEntryOnScreen:
+ call ClearScreen
hlcoord 0, 0
ld de, 1
@@ -512,7 +588,8 @@ ShowPokedexDataInternal:
ld a, c
and a
- jp z, .waitForButtonPress ; if the pokemon has not been owned, don't print the height, weight, or description
+ ret z ; if the pokemon has not been owned, don't print the height, weight, or description
+
inc de ; de = address of feet (height)
ld a, [de] ; reads feet, but a is overwritten without being used
hlcoord 12, 6
@@ -565,43 +642,48 @@ ShowPokedexDataInternal:
ldh [hDexWeight], a ; restore original value of [hDexWeight]
pop hl
inc hl ; hl = address of pokedex description text
+ scf
+ ret
+
+Pokedex_PrintFlavorTextAtRow11:
bccoord 1, 11
+Pokedex_PrintFlavorTextAtBC:
ld a, %10
ldh [hClearLetterPrintingDelayFlags], a
call TextCommandProcessor ; print pokedex description text
xor a
ldh [hClearLetterPrintingDelayFlags], a
-.waitForButtonPress
- call JoypadLowSensitivity
- ldh a, [hJoy5]
- and A_BUTTON | B_BUTTON
- jr z, .waitForButtonPress
- pop af
- ldh [hTilesetType], a
- call GBPalWhiteOut
- call ClearScreen
- call RunDefaultPaletteCommand
- call LoadTextBoxTilePatterns
- call GBPalNormal
- ld hl, wd72c
- res 1, [hl]
- ld a, $77 ; max volume
- ldh [rNR50], a
ret
-HeightWeightText:
- db "HT ?′??″"
- 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, $69, $6B, $69, $6B, $6B
- db $6B, $6B, $69, $6B, $69, $6B, $69, $6B, $69, $6A
- db "@"
+Pokedex_PrepareDexEntryForPrinting:
+ hlcoord 0, 0
+ ld de, SCREEN_WIDTH
+ lb bc, $66, $d
+ call DrawTileLine
+ hlcoord 19, 0
+ ld b, $67
+ call DrawTileLine
+ hlcoord 0, 13
+ ld de, $1
+ lb bc, $6f, SCREEN_WIDTH
+ call DrawTileLine
+ ld a, $6c
+ ldcoord_a 0, 13
+ ld a, $6e
+ ldcoord_a 19, 13
+ ld a, [wPrinterPokedexEntryTextPointer]
+ ld l, a
+ ld a, [wPrinterPokedexEntryTextPointer + 1]
+ ld h, a
+ bccoord 1, 1
+ ldh a, [hFlagsFFFA]
+ set 3, a
+ ldh [hFlagsFFFA], a
+ call Pokedex_PrintFlavorTextAtBC
+ ldh a, [hFlagsFFFA]
+ res 3, a
+ ldh [hFlagsFFFA], a
+ ret
; draws a line of tiles
; INPUT:
diff --git a/engine/menus/save.asm b/engine/menus/save.asm
index 45fed8a6..bcb27ddf 100755
--- a/engine/menus/save.asm
+++ b/engine/menus/save.asm
@@ -32,10 +32,8 @@ FileDataDestroyedText:
text_end
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:
farcall 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
- hlcoord 1, 13
- lb bc, 4, 18
- call ClearScreenArea
- hlcoord 1, 14
- ld de, NowSavingString
- call PlaceString
- ld c, 120
+ ld hl, SavingText
+ call PrintText
+ ld c, 128
call DelayFrames
ld hl, GameSavedText
call PrintText
+ ld c, 10
+ call DelayFrames
ld a, SFX_SAVE
call PlaySoundWaitForCurrent
call WaitForSoundToFinish
ld c, 30
- jp DelayFrames
-
-NowSavingString:
- db "Now saving...@"
+ call DelayFrames
+ ret
SaveSAVConfirm:
call PrintText
@@ -187,6 +179,10 @@ WouldYouLikeToSaveText:
text_far _WouldYouLikeToSaveText
text_end
+SavingText:
+ text_far _SavingText
+ text_end
+
GameSavedText:
text_far _GameSavedText
text_end
@@ -196,10 +192,8 @@ OlderFileWillBeErasedText:
text_end
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, hFlagsFFF6
+ ld hl, hFlagsFFFA
set 1, [hl]
call HandleMenuInput
- ld hl, hFlagsFFF6
+ ld hl, hFlagsFFFA
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
hlcoord 0, 0
- ld b, 2
- ld c, 9
+ lb bc, 2, 9
call TextBoxBorder
ld hl, ChooseABoxText
call PrintText
hlcoord 11, 0
- ld b, 12
- ld c, 7
+ lb bc, 12, 7
call TextBoxBorder
- ld hl, hFlagsFFF6
+ ld hl, hFlagsFFFA
set 2, [hl]
ld de, BoxNames
hlcoord 13, 1
call PlaceString
- ld hl, hFlagsFFF6
+ ld hl, hFlagsFFFA
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
; and the two random numbers generated at game beginning
; (which are stored at wPlayerID)s
- ld a, $0a
- ld [MBC1SRamEnable], a
+ call EnableSRAMAndLatchClockData
ld a, $01
- ld [MBC1SRamBankingMode], a
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, SRAM_End - SRAM_Begin
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/menus/start_sub_menus.asm b/engine/menus/start_sub_menus.asm
index 6a98a10c..84583a69 100755
--- a/engine/menus/start_sub_menus.asm
+++ b/engine/menus/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 BIT_CASCADEBADGE, a
jp z, .newBadgeRequired
@@ -165,15 +168,28 @@ StartMenu_Pokemon::
bit 1, [hl]
res 1, [hl]
jp z, .loop
+ 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 BIT_RAINBOWBADGE, a
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
@@ -469,10 +485,11 @@ StartMenu_TrainerInfo::
call LoadScreenTilesFromBuffer2 ; restore saved screen
call RunDefaultPaletteCommand
call ReloadMapData
+ farcall DrawStartMenu ; XXX what difference does this make?
call LoadGBPal
pop af
ldh [hTilesetType], a
- jp RedisplayStartMenu
+ jp RedisplayStartMenu_DoNotDrawStartMenu
; loads tile patterns and draws everything except for gym leader faces / badges
DrawTrainerInfo:
@@ -506,7 +523,7 @@ DrawTrainerInfo:
ld de, vChars2 tile $20
ld bc, 8 * 8 tiles
ld a, BANK(GymLeaderFaceAndBadgeTileGraphics)
- call FarCopyData2
+ call FarCopyData
ld hl, TextBoxGraphics
ld de, 13 tiles
add hl, de ; hl = colon tile pattern
@@ -514,7 +531,7 @@ DrawTrainerInfo:
ld bc, 1 tiles
ld a, BANK(TextBoxGraphics)
push bc
- call FarCopyData2
+ call FarCopyData
pop bc
ld hl, TrainerInfoTextBoxTileGraphics tile 8 ; background tile pattern
ld de, vChars1 tile $57
@@ -566,7 +583,7 @@ DrawTrainerInfo:
TrainerInfo_FarCopyData:
ld a, BANK(TrainerInfoTextBoxTileGraphics)
- jp FarCopyData2
+ jp FarCopyData
TrainerInfo_NameMoneyTimeText:
db "NAME/"
diff --git a/engine/menus/text_box.asm b/engine/menus/text_box.asm
index 5253ec48..7a315af2 100644
--- a/engine/menus/text_box.asm
+++ b/engine/menus/text_box.asm
@@ -134,8 +134,7 @@ DisplayMoneyBox:
ld [wTextBoxID], a
call DisplayTextBoxID
hlcoord 13, 1
- ld b, 1
- ld c, 6
+ lb bc, 1, 6
call ClearScreenArea
hlcoord 12, 1
ld de, wPlayerMoney
@@ -277,36 +276,10 @@ DisplayTwoOptionMenu:
pop hl
add hl, bc
call PlaceString
- ld hl, 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?
@@ -395,8 +368,7 @@ DisplayFieldMoveMonMenu:
; no field moves
hlcoord 11, 11
- ld b, 5
- ld c, 7
+ lb bc, 5, 7
call TextBoxBorder
call UpdateSprites
ld a, 12
diff --git a/engine/movie/credits.asm b/engine/movie/credits.asm
index 0410de21..938579f3 100755
--- a/engine/movie/credits.asm
+++ b/engine/movie/credits.asm
@@ -1,140 +1,130 @@
HallOfFamePC:
- farcall AnimateHallOfFame
+ callfar AnimateHallOfFame
call ClearScreen
ld c, 100
call DelayFrames
+
call DisableLCD
- ld hl, vFont
- ld bc, ($80 tiles) / 2
- call ZeroMemory
- ld hl, vChars2 tile $60
- ld bc, ($20 tiles) / 2
- call ZeroMemory
- ld hl, vChars2 tile $7e
- ld bc, 1 tiles
- ld a, $ff ; solid black
- call FillMemory
+ ld a, $a7
+ ldh [rWX], a
+ xor a
+ ldh [rSCX], a
+ ldh [rSCY], a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ldh [hWY], a
+ ldh [rWY], a
+ call CreditsLoadFont
hlcoord 0, 0
call FillFourRowsWithBlack
hlcoord 0, 14
call FillFourRowsWithBlack
ld a, %11000000
ldh [rBGP], a
+ call UpdateGBCPal_BGP
call EnableLCD
- ld a, SFX_STOP_ALL_MUSIC
- call PlaySoundWaitForCurrent
+ call StopAllMusic
+ ld hl, vBGMap1
+ call CreditsCopyTileMapToVRAM
+ ld hl, vBGMap0
+ call CreditsCopyTileMapToVRAM
ld c, BANK(Music_Credits)
ld a, MUSIC_CREDITS
call PlayMusic
ld c, 128
call DelayFrames
xor a
- ld [wUnusedCD3D], a ; not read
+ ld [wHoFMonSpecies], a
ld [wNumCreditsMonsDisplayed], a
jp Credits
FadeInCreditsText:
+ ld a, 1
+ ldh [hAutoBGTransferEnabled], a
ld hl, HoFGBPalettes
ld b, 4
.loop
ld a, [hli]
ldh [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
ldh [hAutoBGTransferEnabled], 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
- hlcoord 8, 6
- call GetMonHeader
- call LoadFrontSpriteByMonIndex
- ld hl, vBGMap0 + $c
+ call GetNextCreditsMon
+ ld hl, vBGMap0 + 12
call CreditsCopyTileMapToVRAM
xor a
ldh [hAutoBGTransferEnabled], a
- call LoadScreenTilesFromBuffer1
+ call LoadScreenTilesFromBuffer2DisableBGTransfer
ld hl, vBGMap0
call CreditsCopyTileMapToVRAM
- ld a, $A7
- ldh [rWX], a
- ld hl, vBGMap1
- call CreditsCopyTileMapToVRAM
- call FillMiddleOfScreenWithWhite
ld a, %11111100 ; make the mon a black silhouette
ldh [rBGP], a
-
-; scroll the mon left by one tile 7 times
- ld bc, 7
-.scrollLoop1
+ call UpdateGBCPal_BGP
+ ld hl, rLCDC
+ res 3, [hl]
+ ld a, 1
+ ldh [hAutoBGTransferEnabled], a
+ ld b, 0
+ ld c, 10
call ScrollCreditsMonLeft
- dec c
- jr nz, .scrollLoop1
-
-; scroll the mon left by one tile 20 times
-; This time, we have to move the window left too in order to hide the text that
-; is wrapping around to the right side of the screen.
- ld c, 20
-.scrollLoop2
+ call FillLeftHalfOfScreenWithWhite
+ ld c, 10
+ call ScrollCreditsMonLeft
+ call FillRightHalfOfScreenWithWhite
+ ld c, 8
call ScrollCreditsMonLeft
- ldh a, [rWX]
- sub 8
- ldh [rWX], a
- dec c
- jr nz, .scrollLoop2
-
- xor a
- ldh [hWY], a
ld a, %11000000
ldh [rBGP], a
+ call UpdateGBCPal_BGP
+ xor a
+ ldh [hSCX], a
ret
-INCLUDE "data/credits/credits_mons.asm"
-
ScrollCreditsMonLeft:
- ld h, b
- ld l, $20
- call ScrollCreditsMonLeft_SetSCX
- ld h, $0
- ld l, $70
- call ScrollCreditsMonLeft_SetSCX
ld a, b
- add $8
+ ldh [hSCX], a
+ add 8
ld b, a
+ call DelayFrame
+ dec c
+ jr nz, ScrollCreditsMonLeft
ret
-ScrollCreditsMonLeft_SetSCX:
- ldh a, [rLY]
- cp l
- jr nz, ScrollCreditsMonLeft_SetSCX
- ld a, h
- ldh [rSCX], a
-.loop
- ldh a, [rLY]
- cp h
- jr z, .loop
+GetNextCreditsMon:
+ ld hl, wNumCreditsMonsDisplayed
+ ld c, [hl]
+ inc [hl]
+ ld b, 0
+ ld hl, CreditsMons
+ add hl, bc
+ ld a, [hl]
+ ld [wcf91], a
+ ld [wd0b5], a
+ hlcoord 8, 6
+ call GetMonHeader
+ call LoadFrontSpriteByMonIndex
ret
-HoFGBPalettes:
- db %11000000
- db %11010000
- db %11100000
- db %11110000
+INCLUDE "data/credits/credits_mons.asm"
CreditsCopyTileMapToVRAM:
ld a, l
@@ -145,6 +135,23 @@ CreditsCopyTileMapToVRAM:
ldh [hAutoBGTransferEnabled], a
jp Delay3
+CreditsLoadFont:
+ call LoadFontTilePatterns
+ ld hl, vChars1
+ ld bc, ($80 tiles) / 2
+ call ZeroMemory
+
+ call LoadTextBoxTilePatterns
+ ld hl, vChars2 tile $60
+ ld bc, ($20 tiles) / 2
+ call ZeroMemory
+
+ ld hl, vChars2 tile $7e
+ ld bc, 1 tiles
+ ld a, $ff ; solid black
+ call FillMemory
+ ret
+
ZeroMemory:
; zero bc bytes at hl
ld [hl], 0
@@ -167,7 +174,40 @@ FillMiddleOfScreenWithWhite:
ld a, " "
jp FillMemory
-Credits:
+FillLeftHalfOfScreenWithWhite:
+ hlcoord 0, 4
+ push bc
+ call FillHalfOfScreenWithWhite
+ pop bc
+ ret
+
+FillRightHalfOfScreenWithWhite:
+ hlcoord 10, 4
+ push bc
+ call FillHalfOfScreenWithWhite
+ pop bc
+ ret
+
+FillHalfOfScreenWithWhite:
+ ld b, 10
+ ld c, 10
+ ld a, " "
+.loop
+ push bc
+ push hl
+.innerLoop
+ ld [hli], a
+ dec c
+ jr nz, .innerLoop
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .loop
+ ret
+
+Credits: ; Roll credits
ld de, CreditsOrder
push de
.nextCreditsScreen
@@ -192,58 +232,47 @@ Credits:
jr z, .showCopyrightText
cp CRED_THE_END
jr z, .showTheEnd
- push hl
- push hl
- ld hl, CreditsTextPointers
- add a
- ld c, a
- ld b, 0
- add hl, bc
- ld e, [hl]
- inc hl
- ld d, [hl]
- ld a, [de]
- inc de
- ld c, a
- ld b, -1
- pop hl
- add hl, bc
- call PlaceString
- pop hl
- ld bc, SCREEN_WIDTH * 2
- add hl, bc
+ call PlaceCreditsText
pop de
jr .nextCreditsCommand
+
+.showCopyrightText
+ farcall LoadCopyrightTiles
+ pop de
+ jr .nextCreditsCommand
+
+
.fadeInTextAndShowMon
call 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
- farcall LoadCopyrightTiles
- pop de
- pop de
- jr .nextCreditsCommand
.showTheEnd
- ld c, 16
+ call ShowTheEndGFX
+ pop de
+ ret
+
+ShowTheEndGFX:
+ ld c, 24
call DelayFrames
call FillMiddleOfScreenWithWhite
- pop de
ld de, TheEndGfx
ld hl, vChars2 tile $60
lb bc, BANK(TheEndGfx), (TheEndGfxEnd - TheEndGfx) / $10
@@ -258,8 +287,31 @@ Credits:
TheEndTextString:
; "T H E E N D"
- db $60," ",$62," ",$64," ",$64," ",$66," ",$68,"@"
- db $61," ",$63," ",$65," ",$65," ",$67," ",$69,"@"
+ db $60, " ", $62, " ", $64, " ", $64, " ", $66, " ", $68, "@"
+ db $61, " ", $63, " ", $65, " ", $65, " ", $67, " ", $69, "@"
+
+PlaceCreditsText:
+ push hl
+ push hl
+ ld hl, CreditsTextPointers
+ ld c, a
+ ld b, 0
+ add hl, bc
+ add hl, bc
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ pop hl
+ ld a, [de]
+ inc de
+ ld c, a
+ ld b, -1
+ add hl, bc
+ call PlaceString
+ pop hl
+ ld bc, SCREEN_WIDTH * 2
+ add hl, bc
+ ret
INCLUDE "data/credits/credits_order.asm"
diff --git a/engine/movie/evolution.asm b/engine/movie/evolution.asm
index cabe7254..624a7f5f 100755
--- a/engine/movie/evolution.asm
+++ b/engine/movie/evolution.asm
@@ -9,9 +9,7 @@ EvolveMon:
xor a
ld [wLowHealthAlarm], a
ld [wChannelSoundIDs + Ch5], a
- dec a ; SFX_STOP_ALL_MUSIC
- ld [wNewSoundID], a
- call PlaySound
+ call StopAllMusic
ld a, $1
ldh [hAutoBGTransferEnabled], a
ld a, SFX_TINK
@@ -67,9 +65,7 @@ EvolveMon:
ld a, [wEvoNewSpecies]
.done
ld [wWholeScreenPaletteMonSpecies], a
- ld a, SFX_STOP_ALL_MUSIC
- ld [wNewSoundID], a
- call PlaySound
+ call StopAllMusic
ld a, [wWholeScreenPaletteMonSpecies]
call PlayCry
ld c, 0
diff --git a/engine/movie/hall_of_fame.asm b/engine/movie/hall_of_fame.asm
index a7d3ed40..616a72e3 100755
--- a/engine/movie/hall_of_fame.asm
+++ b/engine/movie/hall_of_fame.asm
@@ -58,8 +58,7 @@ AnimateHallOfFame:
ld c, 80
call DelayFrames
hlcoord 2, 13
- ld b, 3
- ld c, 14
+ lb bc, 3, 14
call TextBoxBorder
hlcoord 4, 15
ld de, HallOfFameText
@@ -77,7 +76,7 @@ AnimateHallOfFame:
ld bc, HOF_MON
call AddNTimes
ld [hl], $ff
- call SaveHallOfFameTeams
+ callfar SaveHallOfFameTeams ; useless since in same bank
xor a
ld [wHoFMonSpecies], a
inc a
@@ -122,6 +121,7 @@ HoFShowMonOrPlayer:
call RunPaletteCommand
ld a, %11100100
ldh [rBGP], a
+ call 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
+ callfar IsThisPartymonStarterPikachu_Party
+ jr nc, .asm_70336
+ ld e, $22
+ callfar PlayPikachuSoundClip
+ jr .asm_7033c
+.asm_70336
+ ld a, [wHoFMonSpecies]
+ call PlayCry
+.asm_7033c
jp HoFRecordMonInfo
+Func_7033f:
+ call HoFDisplayMonInfo
+ ld a, [wHoFMonSpecies]
+ jp PlayCry
+
HoFDisplayMonInfo:
hlcoord 0, 2
- ld b, 9
- ld c, 10
+ lb bc, 9, 10
call TextBoxBorder
hlcoord 2, 6
ld de, HoFMonInfoText
@@ -174,8 +189,7 @@ HoFDisplayMonInfo:
ld [wd0b5], a
hlcoord 3, 9
predef PrintMonType
- ld a, [wHoFMonSpecies]
- jp PlayCry
+ ret
HoFMonInfoText:
db "LEVEL/"
@@ -186,10 +200,13 @@ HoFLoadPlayerPics:
ld de, RedPicFront
ld a, BANK(RedPicFront)
call UncompressSpriteFromDE
+ ld a, $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
hlcoord 0, 4
- ld b, 6
- ld c, 10
+ lb bc, 6, 10
call TextBoxBorder
hlcoord 5, 0
- ld b, 2
- ld c, 9
+ lb bc, 2, 9
call TextBoxBorder
hlcoord 7, 2
ld de, wPlayerName
diff --git a/engine/movie/intro.asm b/engine/movie/intro.asm
index 040d643d..9165113f 100755
--- a/engine/movie/intro.asm
+++ b/engine/movie/intro.asm
@@ -11,8 +11,7 @@ PlayIntro:
inc a
ldh [hAutoBGTransferEnabled], a
call PlayShootingStar
- call PlayIntroScene
- call GBFadeOutToWhite
+ callfar PlayIntroScene
xor a
ldh [hSCX], a
ldh [hAutoBGTransferEnabled], a
@@ -20,162 +19,6 @@ PlayIntro:
call DelayFrame
ret
-PlayIntroScene:
- ld b, SET_PAL_NIDORINO_INTRO
- call RunPaletteCommand
- ldPal a, BLACK, DARK_GRAY, LIGHT_GRAY, WHITE
- ldh [rBGP], a
- ldh [rOBP0], a
- ldh [rOBP1], a
- xor a
- ldh [hSCX], a
- ld b, TILEMAP_GENGAR_INTRO_1
- call IntroCopyTiles
- ld a, 0
- ld [wBaseCoordX], a
- ld a, 80
- ld [wBaseCoordY], a
- lb bc, 6, 6
- call InitIntroNidorinoOAM
- lb de, 80 / 2, MOVE_NIDORINO_RIGHT
- call IntroMoveMon
- ret c
-
-; hip
- ld a, SFX_INTRO_HIP
- call PlaySound
- xor a
- ld [wIntroNidorinoBaseTile], a
- ld de, IntroNidorinoAnimation1
- call AnimateIntroNidorino
-; hop
- ld a, SFX_INTRO_HOP
- call PlaySound
- ld de, IntroNidorinoAnimation2
- call AnimateIntroNidorino
- ld c, 10
- call CheckForUserInterruption
- ret c
-
-; hip
- ld a, SFX_INTRO_HIP
- call PlaySound
- ld de, IntroNidorinoAnimation1
- call AnimateIntroNidorino
-; hop
- ld a, SFX_INTRO_HOP
- call PlaySound
- ld de, IntroNidorinoAnimation2
- call AnimateIntroNidorino
- ld c, 30
- call CheckForUserInterruption
- ret c
-
-; raise
- ld b, TILEMAP_GENGAR_INTRO_2
- call IntroCopyTiles
- ld a, SFX_INTRO_RAISE
- call PlaySound
- lb de, 8 / 2, MOVE_GENGAR_LEFT
- call IntroMoveMon
- ld c, 30
- call CheckForUserInterruption
- ret c
-
-; slash
- ld b, TILEMAP_GENGAR_INTRO_3
- call IntroCopyTiles
- ld a, SFX_INTRO_CRASH
- call PlaySound
- lb de, 16 / 2, MOVE_GENGAR_RIGHT
- call IntroMoveMon
-; hip
- ld a, SFX_INTRO_HIP
- call PlaySound
- ld a, (FightIntroFrontMon2 - FightIntroFrontMon) / LEN_2BPP_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, TILEMAP_GENGAR_INTRO_1
- call IntroCopyTiles
- ld c, 60
- call CheckForUserInterruption
- ret c
-
-; hip
- ld a, SFX_INTRO_HIP
- call PlaySound
- xor a
- ld [wIntroNidorinoBaseTile], a
- ld de, IntroNidorinoAnimation4
- call AnimateIntroNidorino
-; hop
- ld a, SFX_INTRO_HOP
- call PlaySound
- ld de, IntroNidorinoAnimation5
- call AnimateIntroNidorino
- ld c, 20
- call CheckForUserInterruption
- ret c
-
- ld a, (FightIntroFrontMon2 - FightIntroFrontMon) / LEN_2BPP_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) / LEN_2BPP_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
@@ -232,83 +75,17 @@ IntroPlaceBlackTiles:
jr nz, .loop
ret
-IntroMoveMon:
-; d = number of times to move the mon (2 pixels each time)
- ld a, e
- cp MOVE_NIDORINO_RIGHT
- jr z, .moveNidorinoRight
- cp MOVE_GENGAR_LEFT
- jr z, .moveGengarLeft
-; move Gengar right
- ldh a, [hSCX]
- dec a
- dec a
- jr .next
-.moveNidorinoRight
- push de
- ld a, 2
- ld [wBaseCoordX], a
- xor a
- ld [wBaseCoordY], a
- ld c, 6 * 6
- call UpdateIntroNidorinoOAM
- pop de
-.moveGengarLeft
- ldh a, [hSCX]
- inc a
- inc a
-.next
- ldh [hSCX], a
- push de
- ld c, 2
- call CheckForUserInterruption
- pop de
- ret c
- dec d
- jr nz, IntroMoveMon
- ret
-
-IntroCopyTiles:
- hlcoord 13, 7
-
CopyTileIDsFromList_ZeroBaseTileID:
ld c, 0
predef_jump CopyTileIDsFromList
-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
farcall LoadCopyrightAndTextBoxTiles
ldPal a, BLACK, DARK_GRAY, LIGHT_GRAY, WHITE
ldh [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 180
call DelayFrames
call ClearScreen
@@ -316,7 +93,27 @@ PlayShootingStar:
xor a
ld [wCurOpponent], a
call IntroDrawBlackBars
- call LoadIntroGraphics
+; write the black and white tiles
+ ld hl, vChars2
+ ld bc, $10
+ xor a
+ call FillMemory
+ ld hl, vChars2 + $10
+ ld bc, $10
+ ld a, $ff
+ call FillMemory
+; copy gamefreak logo and others
+ ld hl, GameFreakIntro
+ ld de, vChars2 + $600
+ ld bc, GameFreakIntroEnd - GameFreakIntro
+ ld a, BANK(GameFreakIntro)
+ call FarCopyData
+ ld hl, GameFreakIntro
+ ld de, vChars1
+ ld bc, GameFreakIntroEnd - GameFreakIntro
+ ld a, BANK(GameFreakIntro)
+ call FarCopyData
+
call EnableLCD
ld hl, rLCDC
res 5, [hl]
@@ -330,12 +127,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
@@ -359,108 +150,8 @@ IntroDrawBlackBars:
EmptyFunc2:
ret
-IntroNidorinoAnimation0:
- db 0, 0
- db ANIMATION_END
-
-IntroNidorinoAnimation1:
-; This is a sequence of pixel movements for part of the Nidorino animation. This
-; list describes how Nidorino should hop.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db -2, 2
- db -1, 2
- db 1, 2
- db 2, 2
- db ANIMATION_END
-
-IntroNidorinoAnimation2:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db -2, -2
- db -1, -2
- db 1, -2
- db 2, -2
- db ANIMATION_END
-
-IntroNidorinoAnimation3:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db -12, 6
- db -8, 6
- db 8, 6
- db 12, 6
- db ANIMATION_END
-
-IntroNidorinoAnimation4:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db -8, -4
- db -4, -4
- db 4, -4
- db 8, -4
- db ANIMATION_END
-
-IntroNidorinoAnimation5:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db -8, 4
- db -4, 4
- db 4, 4
- db 8, 4
- db ANIMATION_END
-
-IntroNidorinoAnimation6:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db 0, 0
- db 2, 0
- db 2, 0
- db 0, 0
- db ANIMATION_END
-
-IntroNidorinoAnimation7:
-; This is a sequence of pixel movements for part of the Nidorino animation.
-; First byte is y movement, second byte is x movement
- db -8, -16
- db -7, -14
- db -6, -12
- db -4, -10
- db ANIMATION_END
-
GameFreakIntro:
INCBIN "gfx/splash/gamefreak_presents.2bpp"
INCBIN "gfx/splash/gamefreak_logo.2bpp"
ds 16, $00 ; blank tile
GameFreakIntroEnd:
-
-FightIntroBackMon:
- INCBIN "gfx/intro/gengar.2bpp"
- ds 16, $00 ; blank tile
-FightIntroBackMonEnd:
-
-IF DEF(_RED)
-FightIntroFrontMon:
- INCBIN "gfx/intro/red_nidorino_1.2bpp"
-FightIntroFrontMon2:
- INCBIN "gfx/intro/red_nidorino_2.2bpp"
-FightIntroFrontMon3:
- INCBIN "gfx/intro/red_nidorino_3.2bpp"
-ENDC
-
-IF DEF(_BLUE)
-FightIntroFrontMon:
- INCBIN "gfx/intro/blue_jigglypuff_1.2bpp"
-FightIntroFrontMon2:
- INCBIN "gfx/intro/blue_jigglypuff_2.2bpp"
-FightIntroFrontMon3:
- INCBIN "gfx/intro/blue_jigglypuff_3.2bpp"
-ENDC
-
-FightIntroFrontMonEnd:
-
- ds 16, $00 ; blank tile
diff --git a/engine/movie/oak_speech/clear_save.asm b/engine/movie/oak_speech/clear_save.asm
index d5c04e6e..2dd5f4a7 100755
--- a/engine/movie/oak_speech/clear_save.asm
+++ b/engine/movie/oak_speech/clear_save.asm
@@ -5,6 +5,8 @@ DoClearSaveDialogue:
call LoadTextBoxTilePatterns
ld hl, ClearSaveDataText
call PrintText
+ ld a, B_BUTTON
+ ld [wJoyIgnore], a
hlcoord 14, 7
lb bc, 8, 15
ld a, NO_YES_MENU
@@ -12,6 +14,8 @@ DoClearSaveDialogue:
ld a, TWO_OPTION_MENU
ld [wTextBoxID], a
call DisplayTextBoxID
+ ld a, 0
+ ld [wJoyIgnore], a
ld a, [wCurrentMenuItem]
and a
jp z, Init
diff --git a/engine/movie/oak_speech/init_player_data.asm b/engine/movie/oak_speech/init_player_data.asm
index 53ca24f3..d6745daf 100644
--- a/engine/movie/oak_speech/init_player_data.asm
+++ b/engine/movie/oak_speech/init_player_data.asm
@@ -12,6 +12,11 @@ InitPlayerData2:
ld a, $ff
ld [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/movie/oak_speech/oak_speech.asm b/engine/movie/oak_speech/oak_speech.asm
index 4b64f20d..1a327def 100755
--- a/engine/movie/oak_speech/oak_speech.asm
+++ b/engine/movie/oak_speech/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, wSpriteDataEnd - wSpriteDataStart
xor a
call FillMemory
+ xor a
+ ld [wSurfingMinigameHiScore], a
+ ld [wSurfingMinigameHiScore + 1], a
+ ld [wSurfingMinigameHiScore + 2], a
+ pop af
+ ld [wPrinterSettings], a
pop af
ld [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, SFX_STOP_ALL_MUSIC
- call PlaySound
+ 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
- ldh [hLoadedROMBank], 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, SFX_STOP_ALL_MUSIC
- ld [wNewSoundID], a
- call PlaySound
+ call StopAllMusic
pop af
- ldh [hLoadedROMBank], a
- ld [MBC1RomBank], a
+ call BankswitchCommon
ld c, 20
call DelayFrames
hlcoord 6, 5
- ld b, 7
- ld c, 7
+ lb bc, 7, 7
call ClearScreenArea
call LoadTextBoxTilePatterns
ld a, 1
@@ -151,13 +155,15 @@ OakSpeech:
ld c, 50
call DelayFrames
call GBFadeOutToWhite
- jp ClearScreen
+ call ClearScreen ; rip more tail-end optimizations
+ ret
+
OakSpeechText1:
text_far _OakSpeechText1
text_end
OakSpeechText2:
text_far _OakSpeechText2A
- sound_cry_nidorina
+ sound_cry_pikachu
text_far _OakSpeechText2B
text_end
IntroducePlayerText:
@@ -176,6 +182,7 @@ FadeInIntroPic:
.next
ld a, [hli]
ldh [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 10
call DelayFrames
dec b
@@ -197,6 +204,7 @@ MovePicLeft:
ld a, %11100100
ldh [rBGP], a
+ call UpdateGBCPal_BGP
.next
call DelayFrame
ldh 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/movie/oak_speech/oak_speech2.asm b/engine/movie/oak_speech/oak_speech2.asm
index 28208ddc..af31665b 100755
--- a/engine/movie/oak_speech/oak_speech2.asm
+++ b/engine/movie/oak_speech/oak_speech2.asm
@@ -108,6 +108,7 @@ OakSpeechSlidePicCommon:
.loop
xor a
ldh [hAutoBGTransferEnabled], a
+ ldh [hAutoBGTransferPortion], a
ldh a, [hSlideDirection]
and a
jr nz, .slideLeft
@@ -129,8 +130,8 @@ OakSpeechSlidePicCommon:
; If sliding left, we need to zero the last tile in the pic (there is no need
; to take a corresponding action when sliding right because hl initially points
; to a 0 tile in that case).
- xor a
dec hl
+ xor a
ld [hl], a
.next3
ld a, 1
@@ -162,8 +163,7 @@ OakSpeechSlidePicCommon:
DisplayIntroNameTextBox:
push de
hlcoord 0, 0
- ld b, $a
- ld c, $9
+ lb bc, 10, 9
call TextBoxBorder
hlcoord 3, 0
ld de, .namestring
diff --git a/engine/movie/splash.asm b/engine/movie/splash.asm
index eede8ccb..4cb0a59a 100755
--- a/engine/movie/splash.asm
+++ b/engine/movie/splash.asm
@@ -3,9 +3,11 @@ LoadShootingStarGraphics:
ldh [rOBP0], a
ld a, $a4
ldh [rOBP1], a
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
ld de, AnimationTileset2 tile 3 ; star tile (top left quadrant)
ld hl, vChars1 tile $20
- lb bc, BANK(AnimationTileset2), 1
+ lb bc, BANK(AnimationTileset2), $01
call CopyVideoData
ld de, AnimationTileset2 tile 19 ; star tile (bottom left quadrant)
ld hl, vChars1 tile $21
@@ -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,24 +174,32 @@ SmallStarsWaveCoordsPointerTable:
SmallStarsWave1Coords:
db $68, $30
- db $68, $40
+ db $05, $68
+ db $40, $05
db $68, $58
- db $68, $78
+ db $04, $68
+ db $78, $07
SmallStarsWave2Coords:
db $68, $38
- db $68, $48
+ db $05, $68
+ db $48, $06
db $68, $60
- db $68, $70
+ db $04, $68
+ db $70, $07
SmallStarsWave3Coords:
db $68, $34
- db $68, $4C
+ db $05, $68
+ db $4c, $06
db $68, $54
- db $68, $64
+ db $06, $68
+ db $64, $07
SmallStarsWave4Coords:
- db $68, $3C
- db $68, $5C
- db $68, $6C
- db $68, $74
+ db $68, $3c
+ db $05, $68
+ db $5c, $04
+ db $68, $6c
+ db $07, $68
+ db $74, $07
SmallStarsEmptyWave:
db -1 ; end
@@ -200,7 +220,7 @@ MoveDownSmallStars:
ldh a, [rOBP1]
xor %10100000
ldh [rOBP1], a
-
+ call UpdateGBCPal_OBP1
ld c, 3
call CheckForUserInterruption
ret c
@@ -228,10 +248,10 @@ GameFreakLogoOAMData:
GameFreakLogoOAMDataEnd:
GameFreakShootingStarOAMData:
- dbsprite 20, 0, 0, 0, $a0, OAM_OBP1
- dbsprite 21, 0, 0, 0, $a0, OAM_OBP1 | OAM_HFLIP
- dbsprite 20, 1, 0, 0, $a1, OAM_OBP1
- dbsprite 21, 1, 0, 0, $a1, OAM_OBP1 | OAM_HFLIP
+ dbsprite 20, 0, 0, 0, $a0, OAM_OBP1 | %100
+ dbsprite 21, 0, 0, 0, $a0, OAM_OBP1 | OAM_HFLIP | %100
+ dbsprite 20, 1, 0, 0, $a1, OAM_OBP1 | %100
+ dbsprite 21, 1, 0, 0, $a1, OAM_OBP1 | OAM_HFLIP | %100
GameFreakShootingStarOAMDataEnd:
FallingStar:
diff --git a/engine/movie/title.asm b/engine/movie/title.asm
index a75c64ee..1f2723a3 100755
--- a/engine/movie/title.asm
+++ b/engine/movie/title.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,34 @@ DisplayTitleScreen:
call ClearScreen
call DisableLCD
call LoadFontTilePatterns
+; todo: fix hl pointers
ld hl, NintendoCopyrightLogoGraphics
- ld de, vTitleLogo2 tile 16
+ ld de, vTitleLogo tile $60
ld bc, 5 tiles
ld a, BANK(NintendoCopyrightLogoGraphics)
- call FarCopyData2
+ call FarCopyData
+ ld hl, NineTile
+ ld de, vTitleLogo tile $6e
+ ld bc, $10
+ ld a, BANK(NineTile)
+ call FarCopyData
ld hl, GamefreakLogoGraphics
- ld de, vTitleLogo2 tile (16 + 5)
+ ld de, vTitleLogo tile $65
ld bc, 9 tiles
ld a, BANK(GamefreakLogoGraphics)
- call FarCopyData2
- ld hl, PokemonLogoGraphics
- ld de, vTitleLogo
- ld bc, $60 tiles
- ld a, BANK(PokemonLogoGraphics)
- call FarCopyData2 ; first chunk
- ld hl, PokemonLogoGraphics tile $60
- ld de, vTitleLogo2
- ld bc, $10 tiles
- ld a, BANK(PokemonLogoGraphics)
- call FarCopyData2 ; second chunk
- ld hl, Version_GFX
- ld de, vChars2 tile $60 + (10 tiles - (Version_GFXEnd - Version_GFX) * 2) / 2
- ld bc, Version_GFXEnd - Version_GFX
- ld a, BANK(Version_GFX)
- call FarCopyDataDouble
- call ClearBothBGMaps
-
-; place tiles for pokemon logo (except for the last row)
- hlcoord 2, 1
- ld a, $80
- ld de, SCREEN_WIDTH
- ld c, 6
-.pokemonLogoTileLoop
- ld b, $10
- push hl
-.pokemonLogoTileRowLoop ; place tiles for one row
- ld [hli], a
- inc a
- dec b
- jr nz, .pokemonLogoTileRowLoop
- pop hl
- add hl, de
- dec c
- jr nz, .pokemonLogoTileLoop
-
-; place tiles for the last row of the pokemon logo
- hlcoord 2, 7
- ld a, $31
- ld b, $10
-.pokemonLogoLastTileRowLoop
- ld [hli], a
- inc a
- dec b
- jr nz, .pokemonLogoLastTileRowLoop
-
- call DrawPlayerCharacter
-
-; put a pokeball in the player's hand
- ld hl, wOAMBuffer + $28
- ld a, $74
- ld [hl], a
-
-; place tiles for title screen copyright
- hlcoord 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
+ callfar LoadYellowTitleScreenGFX
+ ld hl, vBGMap0
+ ld bc, (vBGMap1 tile $40) - vBGMap0
+ ld a, " "
+ call FillMemory
+ callfar TitleScreen_PlacePokemonLogo
+ call FillSpriteBuffer0WithAA
+ call .WriteCopyrightTiles
call SaveScreenTilesToBuffer2
call LoadScreenTilesFromBuffer2
call EnableLCD
-
-IF DEF(_RED)
- ld a, 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
-
+ callfar TitleScreen_PlacePikachu
ld a, HIGH(vBGMap0 + $300)
call TitleScreenCopyTileMapToVRAM
call SaveScreenTilesToBuffer1
@@ -138,8 +69,9 @@ ENDC
ld b, SET_PAL_TITLE_SCREEN
call RunPaletteCommand
call GBPalNormal
- ld a, %11100100
+ ld a, %11100000
ldh [rOBP0], a
+ call UpdateGBCPal_OBP0
; make pokemon logo bounce up and down
ld bc, hSCY ; background scroll Y
@@ -181,6 +113,21 @@ ENDC
jr nz, .ScrollTitleScreenPokemonLogo
ret
+; place tiles for title screen copyright
+.WriteCopyrightTiles
+ hlcoord 2, 17
+ ld de, .tileScreenCopyrightTiles
+.titleScreenCopyrightTilesLoop
+ ld a, [de]
+ inc de
+ cp $ff
+ ret z
+ ld [hli], a
+ jr .titleScreenCopyrightTilesLoop
+
+.tileScreenCopyrightTiles
+ db $e0,$e1,$e2,$e3,$e1,$e2,$ee,$e5,$e6,$e7,$e8,$e9,$ea,$eb,$ec,$ed,$ff ; ©1995-1999 GAME FREAK inc.
+
.finishedBouncingPokemonLogo
call LoadScreenTilesFromBuffer1
ld c, 36
@@ -189,52 +136,42 @@ ENDC
call PlaySound
; scroll game version in from the right
- call PrintGameVersionOnTitleScreen
+ callfar TitleScreen_PlacePikaSpeechBubble
ld a, SCREEN_HEIGHT_PX
ldh [hWY], a
- ld d, 144
-.scrollTitleScreenGameVersionLoop
- ld h, d
- ld l, 64
- call ScrollTitleScreenGameVersion
- ld h, 0
- ld l, 80
- call ScrollTitleScreenGameVersion
- ld a, d
- add 4
- ld d, a
- and a
- jr nz, .scrollTitleScreenGameVersionLoop
-
- ld a, HIGH(vBGMap1)
- call TitleScreenCopyTileMapToVRAM
- call LoadScreenTilesFromBuffer2
- call PrintGameVersionOnTitleScreen
call Delay3
+ 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
- farcall 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
+ ldh 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
@@ -253,115 +190,41 @@ ENDC
and D_UP | SELECT | B_BUTTON
cp D_UP | SELECT | B_BUTTON
jp z, .doClearSaveDialogue
-IF DEF(_DEBUG)
- ld a, b
- bit BIT_SELECT, a
- jp nz, DebugMenu
-ENDC
jp MainMenu
-.doClearSaveDialogue
- farjp DoClearSaveDialogue
-
-TitleScreenPickNewMon:
- ld a, HIGH(vBGMap0)
- call TitleScreenCopyTileMapToVRAM
-
-.loop
-; Keep looping until a mon different from the current one is picked.
- call Random
- and $f
- ld c, a
- ld b, 0
- ld hl, TitleMons
- add hl, bc
- ld a, [hl]
- ld hl, wTitleMonSpecies
-
-; Can't be the same as before.
- cp [hl]
- jr z, .loop
-
- ld [hl], a
- call LoadTitleMonSprite
+.asm_42f0
+; unreferenced
+ callfar PrinterDebug
+ jp .loop
- ld a, $90
- ldh [hWY], a
- ld d, 1 ; scroll out
- farcall TitleScroll
- ret
-
-TitleScreenScrollInMon:
- ld d, 0 ; scroll in
- farcall TitleScroll
- xor a
- ldh [hWY], a
- ret
-
-ScrollTitleScreenGameVersion:
-.wait
- ldh a, [rLY]
- cp l
- jr nz, .wait
-
- ld a, h
- ldh [rSCX], a
-
-.wait2
- ldh a, [rLY]
- cp h
- jr z, .wait2
- ret
-
-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
- lb de, $60, $5a
- ld b, 7
-.loop
- push de
- ld c, 5
-.innerLoop
- ld a, d
- ld [hli], a ; Y
- ld a, e
- ld [hli], a ; X
- add 8
- ld e, a
- ld a, [wPlayerCharacterOAMTile]
- ld [hli], a ; tile
+.asm_42fb
+; unreferenced
+ ld a, [wTitleScreenScene + 4]
inc a
- ld [wPlayerCharacterOAMTile], a
- inc hl
- dec c
- jr nz, .innerLoop
- pop de
- ld a, 8
- add d
- ld d, a
- dec b
- jr nz, .loop
- ret
+ cp $2a
+ jr c, .asm_4305
+ ld a, $f
+.asm_4305
+ ld [wTitleScreenScene + 4], a
+ ld e, a
+ callfar 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
+ farjp DoClearSaveDialogue
-LoadTitleMonSprite:
- ld [wcf91], a
- ld [wd0b5], a
- hlcoord 5, 10
- call GetMonHeader
- jp LoadFrontSpriteByMonIndex
TitleScreenCopyTileMapToVRAM:
ldh [hAutoBGTransferDest + 1], a
@@ -376,34 +239,132 @@ LoadCopyrightAndTextBoxTiles:
LoadCopyrightTiles:
ld de, NintendoCopyrightLogoGraphics
ld hl, vChars2 tile $60
- 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
hlcoord 2, 7
ld de, CopyrightTextString
jp PlaceString
CopyrightTextString:
- db $60,$61,$62,$61,$63,$61,$64,$7F,$65,$66,$67,$68,$69,$6A ; ©'95.'96.'98 Nintendo
- next $60,$61,$62,$61,$63,$61,$64,$7F,$6B,$6C,$6D,$6E,$6F,$70,$71,$72 ; ©'95.'96.'98 Creatures inc.
- next $60,$61,$62,$61,$63,$61,$64,$7F,$73,$74,$75,$76,$77,$78,$79,$7A,$7B ; ©'95.'96.'98 GAME FREAK inc.
+ db $60,$61,$62,$63,$61,$62,$7c,$7f,$65,$66,$67,$68,$69,$6a ; ©1995-1999 Nintendo
+ next $60,$61,$62,$63,$61,$62,$7c,$7f,$6b,$6c,$6d,$6e,$6f,$70,$71,$72 ; ©1995-1999 Creatures inc.
+ next $60,$61,$62,$63,$61,$62,$7c,$7f,$73,$74,$75,$76,$77,$78,$79,$7a,$7b ; ©1995-1999 GAME FREAK inc.
db "@"
-INCLUDE "data/pokemon/title_mons.asm"
-
-; prints version text (red, blue)
-PrintGameVersionOnTitleScreen:
- hlcoord 7, 8
- ld de, VersionOnTitleScreenText
- jp PlaceString
+TitleScreen_PlayPikachuPCM:
+ callfar 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/movie/title2.asm b/engine/movie/title2.asm
index 315cf6b5..df630b53 100755
--- a/engine/movie/title2.asm
+++ b/engine/movie/title2.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/movie/trade.asm b/engine/movie/trade.asm
index bb06f231..7be100e0 100755
--- a/engine/movie/trade.asm
+++ b/engine/movie/trade.asm
@@ -20,12 +20,13 @@ ExternalClockTradeAnim:
TradeAnimCommon:
ld a, [wOptions]
push af
+ and %110000 ; preserve speaker options
+ ld [wOptions], a
ldh a, [hSCY]
push af
ldh a, [hSCX]
push af
xor a
- ld [wOptions], a
ldh [hSCY], a
ldh [hSCX], a
push de
@@ -160,12 +161,12 @@ LoadTradingGFXAndMonNames:
ld de, vChars2 tile $31
ld bc, TradingAnimationGraphicsEnd - TradingAnimationGraphics
ld a, BANK(TradingAnimationGraphics)
- call FarCopyData2
+ call FarCopyData
ld hl, TradingAnimationGraphics2
ld de, vSprites tile $7c
ld bc, TradingAnimationGraphics2End - TradingAnimationGraphics2
ld a, BANK(TradingAnimationGraphics2)
- call FarCopyData2
+ call FarCopyData
ld hl, vBGMap0
ld bc, $800
ld a, " "
@@ -182,6 +183,7 @@ LoadTradingGFXAndMonNames:
ld a, $f0 ; SGB OBP0
.next
ldh [rOBP0], a
+ call UpdateGBCPal_OBP0
call EnableLCD
xor a
ldh [hAutoBGTransferEnabled], a
@@ -199,6 +201,7 @@ LoadTradingGFXAndMonNames:
Trade_LoadMonPartySpriteGfx:
ld a, %11010000
ldh [rOBP1], a
+ call UpdateGBCPal_OBP1
farjp LoadMonPartySpriteGfx
Trade_SwapNames:
@@ -233,8 +236,7 @@ Trade_ShowPlayerMon:
xor a
ldh [hAutoBGTransferEnabled], a
hlcoord 4, 0
- ld b, 6
- ld c, 10
+ lb bc, 6, 10
call TextBoxBorder
call Trade_PrintPlayerMonInfoText
ld b, HIGH(vBGMap0)
@@ -303,6 +305,7 @@ Trade_AnimateBallEnteringLinkCable:
call DelayFrames
ld a, %11100100
ldh [rOBP0], a
+ call UpdateGBCPal_OBP0
xor a
ld [wLinkCableAnimBulgeToggle], a
lb bc, $20, $60
@@ -354,8 +357,7 @@ Trade_ShowEnemyMon:
call Trade_ShowAnimation
call Trade_ShowClearedWindow
hlcoord 4, 10
- ld b, 6
- ld c, 10
+ lb bc, 6, 10
call TextBoxBorder
call Trade_PrintEnemyMonInfoText
call Trade_CopyTileMapToVRAM
@@ -382,6 +384,7 @@ Trade_AnimLeftToRight:
ld [wTradedMonMovingRight], a
ld a, %11100100
ldh [rOBP0], a
+ call UpdateGBCPal_OBP0
ld a, $54
ld [wBaseCoordX], a
ld a, $1c
@@ -446,6 +449,8 @@ Trade_InitGameboyTransferGfx:
ld a, $1
ldh [hAutoBGTransferEnabled], a
call ClearScreen
+ ld b, SET_PAL_GENERIC
+ call RunPaletteCommand
xor a
ldh [hAutoBGTransferEnabled], a
call Trade_LoadMonPartySpriteGfx
@@ -479,8 +484,7 @@ Trade_DrawLeftGameboy:
; draw text box with player name below gameboy pic
hlcoord 4, 12
- ld b, 2
- ld c, 7
+ lb bc, 2, 7
call TextBoxBorder
hlcoord 5, 14
ld de, wPlayerName
@@ -526,8 +530,7 @@ Trade_DrawRightGameboy:
; draw text box with enemy name above link cable
hlcoord 6, 0
- ld b, 2
- ld c, 7
+ lb bc, 2, 7
call TextBoxBorder
hlcoord 7, 2
ld de, wLinkEnemyTrainerName
@@ -599,6 +602,7 @@ Trade_AnimCircledMon:
ldh a, [rBGP]
xor $3c ; make link cable flash
ldh [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/overworld/advance_player_sprite.asm b/engine/overworld/advance_player_sprite.asm
new file mode 100644
index 00000000..4ebdac84
--- /dev/null
+++ b/engine/overworld/advance_player_sprite.asm
@@ -0,0 +1,244 @@
+_AdvancePlayerSprite::
+ ld a, [wSpritePlayerStateData1YStepVector]
+ ld b, a
+ ld a, [wSpritePlayerStateData1XStepVector]
+ ld c, a
+ ld hl, wWalkCounter ; 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 $07
+ jp nz, .scrollBackgroundAndSprites
+; if this is the first iteration of the animation
+ ld a, c
+ cp $01
+ jr nz, .checkIfMovingWest
+; moving east
+ ld a, [wMapViewVRAMPointer]
+ ld e, a
+ and $e0
+ ld d, a
+ ld a, e
+ add $02
+ and $1f
+ or d
+ ld [wMapViewVRAMPointer], a
+ jr .adjustXCoordWithinBlock
+.checkIfMovingWest
+ cp $ff
+ jr nz, .checkIfMovingSouth
+; moving west
+ ld a, [wMapViewVRAMPointer]
+ ld e, a
+ and $e0
+ ld d, a
+ ld a, e
+ sub $02
+ and $1f
+ or d
+ ld [wMapViewVRAMPointer], a
+ jr .adjustXCoordWithinBlock
+.checkIfMovingSouth
+ ld a, b
+ cp $01
+ jr nz, .checkIfMovingNorth
+; moving south
+ ld a, [wMapViewVRAMPointer]
+ add $40
+ ld [wMapViewVRAMPointer], a
+ jr nc, .adjustXCoordWithinBlock
+ ld a, [wMapViewVRAMPointer + 1]
+ inc a
+ and $03
+ or $98
+ ld [wMapViewVRAMPointer + 1], a
+ jr .adjustXCoordWithinBlock
+.checkIfMovingNorth
+ cp $ff
+ jr nz, .adjustXCoordWithinBlock
+; moving north
+ ld a, [wMapViewVRAMPointer]
+ sub $40
+ ld [wMapViewVRAMPointer], a
+ jr nc, .adjustXCoordWithinBlock
+ ld a, [wMapViewVRAMPointer + 1]
+ dec a
+ and $03
+ or $98
+ ld [wMapViewVRAMPointer + 1], a
+.adjustXCoordWithinBlock
+ ld a, c
+ and a
+ jr z, .pointlessJump ; mistake?
+.pointlessJump
+ ld hl, wXBlockCoord
+ ld a, [hl]
+ add c
+ ld [hl], a
+ cp $02
+ jr nz, .checkForMoveToWestBlock
+; moved into the tile block to the east
+ xor a
+ ld [hl], a
+ ld hl, wXOffsetSinceLastSpecialWarp
+ inc [hl]
+ ld de, wCurrentTileBlockMapViewPointer
+ call MoveTileBlockMapPointerEast
+ jr .updateMapView
+.checkForMoveToWestBlock
+ cp $ff
+ jr nz, .adjustYCoordWithinBlock
+; moved into the tile block to the west
+ ld a, $01
+ ld [hl], a
+ ld hl, wXOffsetSinceLastSpecialWarp
+ dec [hl]
+ ld de, wCurrentTileBlockMapViewPointer
+ call MoveTileBlockMapPointerWest
+ jr .updateMapView
+.adjustYCoordWithinBlock
+ ld hl, wYBlockCoord
+ ld a, [hl]
+ add b
+ ld [hl], a
+ cp $02
+ jr nz, .checkForMoveToNorthBlock
+; moved into the tile block to the south
+ xor a
+ ld [hl], a
+ ld hl, wYOffsetSinceLastSpecialWarp
+ inc [hl]
+ ld de, wCurrentTileBlockMapViewPointer
+ ld a, [wCurMapWidth]
+ call MoveTileBlockMapPointerSouth
+ jr .updateMapView
+.checkForMoveToNorthBlock
+ cp $ff
+ jr nz, .updateMapView
+; moved into the tile block to the north
+ ld a, $01
+ ld [hl], a
+ ld hl, wYOffsetSinceLastSpecialWarp
+ dec [hl]
+ ld de, wCurrentTileBlockMapViewPointer
+ ld a, [wCurMapWidth]
+ call MoveTileBlockMapPointerNorth
+.updateMapView
+ call LoadCurrentMapView
+ ld a, [wSpritePlayerStateData1YStepVector]
+ cp $01
+ jr nz, .checkIfMovingNorth2
+; if moving south
+ call ScheduleSouthRowRedraw
+ jr .scrollBackgroundAndSprites
+.checkIfMovingNorth2
+ cp $ff
+ jr nz, .checkIfMovingEast2
+; if moving north
+ call ScheduleNorthRowRedraw
+ jr .scrollBackgroundAndSprites
+.checkIfMovingEast2
+ ld a, [wSpritePlayerStateData1XStepVector]
+ cp $01
+ jr nz, .checkIfMovingWest2
+; if moving east
+ call ScheduleEastColumnRedraw
+ jr .scrollBackgroundAndSprites
+.checkIfMovingWest2
+ cp $ff
+ jr nz, .scrollBackgroundAndSprites
+; if moving west
+ call ScheduleWestColumnRedraw
+.scrollBackgroundAndSprites
+ ld a, [wSpritePlayerStateData1YStepVector]
+ add a
+ ld b, a
+ ld a, [wSpritePlayerStateData1XStepVector]
+ add a
+ ld c, a
+; shift all the sprites in the direction opposite of the player's motion
+; so that the player appears to move relative to them
+ ld hl, wSprite01StateData1YPixels
+ ld e, 15
+.spriteShiftLoop
+ ld a, [hl]
+ sub b
+ ld [hli], a
+ inc l
+ ld a, [hl]
+ sub c
+ ld [hl], a
+ ld a, $0e
+ add l
+ ld l, a
+ dec e
+ jr nz, .spriteShiftLoop
+.done
+ ldh a, [hSCY]
+ add b
+ ldh [hSCY], a ; update background scroll Y
+ ldh a, [hSCX]
+ add c
+ ldh [hSCX], a ; update background scroll X
+ ret
+
+; the following four functions are used to move the pointer to the upper left
+; corner of the tile block map in the direction of motion
+
+MoveTileBlockMapPointerEast::
+ ld a, [de]
+ add $01
+ ld [de], a
+ ret nc
+ inc de
+ ld a, [de]
+ inc a
+ ld [de], a
+ ret
+
+MoveTileBlockMapPointerWest::
+ ld a, [de]
+ sub $01
+ ld [de], a
+ ret nc
+ inc de
+ ld a, [de]
+ dec a
+ ld [de], a
+ ret
+
+MoveTileBlockMapPointerSouth::
+ add MAP_BORDER * 2
+ ld b, a
+ ld a, [de]
+ add b
+ ld [de], a
+ ret nc
+ inc de
+ ld a, [de]
+ inc a
+ ld [de], a
+ ret
+
+MoveTileBlockMapPointerNorth::
+ add MAP_BORDER * 2
+ ld b, a
+ ld a, [de]
+ sub b
+ ld [de], a
+ ret nc
+ inc de
+ ld a, [de]
+ dec a
+ ld [de], a
+ ret
diff --git a/engine/overworld/auto_movement.asm b/engine/overworld/auto_movement.asm
index 9c078f08..a68da55f 100755
--- a/engine/overworld/auto_movement.asm
+++ b/engine/overworld/auto_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, 5
+ db NPC_MOVEMENT_DOWN, 6 ; differs from red
db NPC_MOVEMENT_LEFT, 1
db NPC_MOVEMENT_DOWN, 5
db NPC_MOVEMENT_RIGHT, 3
@@ -141,7 +146,7 @@ RLEList_PlayerWalkToLab:
db D_RIGHT, 3
db D_DOWN, 5
db D_LEFT, 1
- db D_DOWN, 6
+ db D_DOWN, 7 ; differs from red
db -1 ; end
PalletMovementScript_Done:
@@ -163,11 +168,9 @@ PewterMuseumGuyMovementScriptPointerTable::
PewterMovementScript_WalkToMuseum:
ld a, BANK(Music_MuseumGuy)
- ld [wAudioROMBank], a
- ld [wAudioSavedROMBank], a
+ ld c, a
ld a, MUSIC_MUSEUM_GUY
- ld [wNewSoundID], a
- call PlaySound
+ call PlayMusic
ld a, [wSpriteIndex]
swap a
ld [wNPCMovementScriptSpriteOffset], a
@@ -179,7 +182,7 @@ PewterMovementScript_WalkToMuseum:
ld [wSimulatedJoypadStatesIndex], a
xor a
ld [wWhichPewterGuy], a
- predef PewterGuys
+ call PewterGuys
ld hl, wNPCMovementDirections2
ld de, RLEList_PewterMuseumGuy
call DecodeRLEList
@@ -219,11 +222,9 @@ PewterGymGuyMovementScriptPointerTable::
PewterMovementScript_WalkToGym:
ld a, BANK(Music_MuseumGuy)
- ld [wAudioROMBank], a
- ld [wAudioSavedROMBank], a
+ ld c, a
ld a, MUSIC_MUSEUM_GUY
- ld [wNewSoundID], a
- call PlaySound
+ call PlayMusic
ld a, [wSpriteIndex]
swap a
ld [wNPCMovementScriptSpriteOffset], a
@@ -236,7 +237,7 @@ PewterMovementScript_WalkToGym:
ld [wSimulatedJoypadStatesIndex], a
ld a, 1
ld [wWhichPewterGuy], a
- predef PewterGuys
+ call PewterGuys
ld hl, wNPCMovementDirections2
ld de, RLEList_PewterGymGuy
call DecodeRLEList
@@ -266,27 +267,4 @@ RLEList_PewterGymGuy:
db NPC_MOVEMENT_RIGHT, 3
db -1 ; end
-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 -1
- jr z, .notRival
- cp b
- ret z ; the rival leaves after battling, so don't freeze him
- jr .loop
-.notRival
- ld a, [wSpriteIndex]
- ldh [hSpriteIndex], a
- jp SetSpriteMovementBytesToFF
-
-RivalIDs:
- db OPP_RIVAL1
- db OPP_RIVAL2
- db OPP_RIVAL3
- db -1 ; end
+INCLUDE "engine/events/pewter_guys.asm"
diff --git a/engine/overworld/cut.asm b/engine/overworld/cut.asm
index 6a92ccc0..e36b8d88 100755
--- a/engine/overworld/cut.asm
+++ b/engine/overworld/cut.asm
@@ -76,6 +76,7 @@ InitCutAnimOAM:
ld [wWhichAnimationOffsets], a
ld a, %11100100
ldh [rOBP1], a
+ call UpdateGBCPal_OBP1
ld a, [wCutTile]
cp $52
jr z, .grass
@@ -123,8 +124,8 @@ WriteCutOrBoulderDustAnimationOAMBlock:
jp WriteOAMBlock
CutOrBoulderDustAnimationTilesAndAttributes:
- dbsprite 2, -1, 0, 4, $fd, OAM_OBP1
- dbsprite 2, -1, 0, 6, $ff, OAM_OBP1
+ dbsprite 2, -1, 4, 4, $fd, OAM_OBP1 | %100
+ dbsprite 2, -1, 4, 6, $ff, OAM_OBP1 | %100
GetCutOrBoulderDustAnimationOffsets:
ld hl, wSpritePlayerStateData1YPixels
diff --git a/engine/overworld/cut2.asm b/engine/overworld/cut2.asm
index 3d4a5905..1f691eef 100755
--- a/engine/overworld/cut2.asm
+++ b/engine/overworld/cut2.asm
@@ -18,6 +18,7 @@ AnimCut:
ldh a, [rOBP1]
xor $64
ldh [rOBP1], a
+ call UpdateGBCPal_OBP1
call DelayFrame
pop bc
dec c
@@ -68,6 +69,7 @@ AnimCutGrass_UpdateOAMEntries:
ldh a, [rOBP1]
xor $64
ldh [rOBP1], a
+ call UpdateGBCPal_OBP1
call DelayFrame
pop bc
dec c
diff --git a/engine/overworld/dungeon_warps.asm b/engine/overworld/dungeon_warps.asm
new file mode 100644
index 00000000..7641c688
--- /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/dust_smoke.asm b/engine/overworld/dust_smoke.asm
index a20a0591..773def96 100755
--- a/engine/overworld/dust_smoke.asm
+++ b/engine/overworld/dust_smoke.asm
@@ -7,6 +7,7 @@ AnimateBoulderDust:
ld [wUpdateSpritesEnabled], a
ld a, %11100100
ldh [rOBP1], a
+ call UpdateGBCPal_OBP1
call LoadSmokeTileFourTimes
farcall WriteCutOrBoulderDustAnimationOAMBlock
ld c, 8 ; number of steps in animation
@@ -21,6 +22,7 @@ AnimateBoulderDust:
ldh a, [rOBP1]
xor %01100100
ldh [rOBP1], a
+ call UpdateGBCPal_OBP1
call Delay3
pop bc
dec c
diff --git a/engine/overworld/elevator.asm b/engine/overworld/elevator.asm
index fa404602..b873ffad 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, SFX_STOP_ALL_MUSIC
- call PlaySound
+ call StopAllMusic
ldh a, [hSCY]
ld d, a
ld e, $1
@@ -27,8 +26,7 @@ ShakeElevator::
jr nz, .shakeLoop
ld a, d
ldh [hSCY], a
- ld a, SFX_STOP_ALL_MUSIC
- call PlaySound
+ call StopAllMusic
ld c, BANK(SFX_Safari_Zone_PA)
ld a, SFX_SAFARI_ZONE_PA
call PlayMusic
diff --git a/engine/overworld/emotion_bubbles.asm b/engine/overworld/emotion_bubbles.asm
index 5a41c226..3ad714e9 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 tile $78
lb bc, BANK(EmotionBubbles), 4
call CopyVideoData
@@ -59,13 +62,9 @@ EmotionBubble:
pop af
ld [wUpdateSpritesEnabled], a
call DelayFrame
- jp UpdateSprites
+ call UpdateSprites
+ ret
-EmotionBubblesPointerTable:
-; entries correspond to *_BUBBLE constants
- dw ShockEmote
- dw QuestionEmote
- dw HappyEmote
EmotionBubblesOAM:
dbsprite 0, -1, 0, 0, $f9, 0
@@ -75,3 +74,8 @@ EmotionBubbles:
ShockEmote: INCBIN "gfx/emotes/shock.2bpp"
QuestionEmote: INCBIN "gfx/emotes/question.2bpp"
HappyEmote: INCBIN "gfx/emotes/happy.2bpp"
+SkullEmote: INCBIN "gfx/emotes/skull.2bpp"
+HeartEmote: INCBIN "gfx/emotes/heart.2bpp"
+BoltEmote: INCBIN "gfx/emotes/bolt.2bpp"
+ZzzEmote: INCBIN "gfx/emotes/zzz.2bpp"
+FishEmote: INCBIN "gfx/emotes/fish.2bpp"
diff --git a/engine/overworld/healing_machine.asm b/engine/overworld/healing_machine.asm
index 40ca6f65..e5fba7e1 100755
--- a/engine/overworld/healing_machine.asm
+++ b/engine/overworld/healing_machine.asm
@@ -12,14 +12,13 @@ AnimateHealingMachine:
push af
ld a, $e0
ldh [rOBP1], a
+ call UpdateGBCPal_OBP1
ld hl, wOAMBuffer + $84
ld de, PokeCenterOAMData
call CopyHealingMachineOAM
ld a, 4
ld [wAudioFadeOutControl], a
- ld a, SFX_STOP_ALL_MUSIC
- ld [wNewSoundID], a
- call PlaySound
+ call StopAllMusic
.waitLoop
ld a, [wAudioFadeOutControl]
and a ; is fade-out finished?
@@ -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, SFX_STOP_ALL_MUSIC
- ld [wNewSoundID], a
- call PlaySound
+ call StopAllMusic
ld a, BANK(Music_PkmnHealed)
ld [wAudioROMBank], a
.next
@@ -57,6 +54,7 @@ AnimateHealingMachine:
call DelayFrames
pop af
ldh [rOBP1], a
+ call UpdateGBCPal_OBP1
pop hl
pop af
ld [hl], a
@@ -67,14 +65,14 @@ PokeCenterFlashingMonitorAndHealBall:
PokeCenterOAMData:
; heal machine monitor
- dbsprite 6, 4, 4, 4, $7c, OAM_OBP1
+ dbsprite 6, 4, 4, 4, $7c, OAM_OBP1 | %100
; poke balls 1-6
- dbsprite 6, 5, 0, 3, $7d, OAM_OBP1
- dbsprite 7, 5, 0, 3, $7d, OAM_OBP1 | OAM_HFLIP
- dbsprite 6, 6, 0, 0, $7d, OAM_OBP1
- dbsprite 7, 6, 0, 0, $7d, OAM_OBP1 | OAM_HFLIP
- dbsprite 6, 6, 0, 5, $7d, OAM_OBP1
- dbsprite 7, 6, 0, 5, $7d, OAM_OBP1 | OAM_HFLIP
+ dbsprite 6, 5, 0, 3, $7d, OAM_OBP1 | %100
+ dbsprite 7, 5, 0, 3, $7d, OAM_OBP1 | OAM_HFLIP | %100
+ dbsprite 6, 6, 0, 0, $7d, OAM_OBP1 | %100
+ dbsprite 7, 6, 0, 0, $7d, OAM_OBP1 | OAM_HFLIP | %100
+ dbsprite 6, 6, 0, 5, $7d, OAM_OBP1 | %100
+ dbsprite 7, 6, 0, 5, $7d, OAM_OBP1 | OAM_HFLIP | %100
; d = value to xor with palette
FlashSprite8Times:
@@ -83,6 +81,7 @@ FlashSprite8Times:
ldh a, [rOBP1]
xor d
ldh [rOBP1], a
+ call UpdateGBCPal_OBP1
ld c, 10
call DelayFrames
dec b
diff --git a/engine/overworld/hidden_objects.asm b/engine/overworld/hidden_objects.asm
index 855328e7..84108986 100755
--- a/engine/overworld/hidden_objects.asm
+++ b/engine/overworld/hidden_objects.asm
@@ -1,19 +1,3 @@
-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 [hDidntFindAnyHiddenObject], else stores $ff
CheckForHiddenObject::
ld hl, hItemAlreadyFound
@@ -22,22 +6,12 @@ CheckForHiddenObject::
ld [hli], a ; [hSavedMapTextPtr]
ld [hli], a ; [hSavedMapTextPtr + 1]
ld [hl], a ; [hDidntFindAnyHiddenObject]
- 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
diff --git a/engine/overworld/ledges.asm b/engine/overworld/ledges.asm
index f01ae5ef..9925c528 100755
--- a/engine/overworld/ledges.asm
+++ b/engine/overworld/ledges.asm
@@ -61,10 +61,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:
@@ -72,5 +75,6 @@ LedgeHoppingShadow:
LedgeHoppingShadowEnd:
LedgeHoppingShadowOAM:
- dbsprite 2, -1, 0, 7, $ff, OAM_HFLIP
- dbsprite 8, -1, 0, 7, $ff, OAM_HFLIP | OAM_VFLIP
+ dbsprite 9, 11, 0, 0, $ff, 0
+ dbsprite 10, 11, 0, 0, $ff, OAM_HFLIP
+LedgeHoppingShadowOAMEnd:
diff --git a/engine/overworld/map_sprites.asm b/engine/overworld/map_sprites.asm
index fa3a37dc..e31c0bd2 100755
--- a/engine/overworld/map_sprites.asm
+++ b/engine/overworld/map_sprites.asm
@@ -4,251 +4,17 @@
; This is also called after displaying text because loading
; text tile patterns overwrites half of the sprite tile pattern data.
; Note on notation:
-; x#SPRITESTATEDATA1_* and x#SPRITESTATEDATA2_* are used to denote wSpriteStateData1 and
-; wSpriteStateData2 sprite slot, respectively, within loops. The X is the loop index.
-; If there is an inner loop, Y is the inner loop index, i.e. y#SPRITESTATEDATA1_* and
-; y#SPRITESTATEDATA2_* denote fields of the sprite slots iterated over in the inner loop.
-InitMapSprites::
+; $C1X* and $C2X* are used to denote wSpriteStateData1-wSpriteStateData1 + $ff and wSpriteStateData2 + $00-wSpriteStateData2 + $ff sprite slot
+; 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::
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, wSpritePlayerStateData1PictureID
- ld de, wSpritePlayerStateData2PictureID
-; Loop to copy picture IDs from [x#SPRITESTATEDATA1_PICTUREID]
-; to [x#SPRITESTATEDATA2_PICTUREID] for LoadMapSpriteTilePatterns.
-.copyPictureIDLoop
- ld a, [hl] ; a = [x#SPRITESTATEDATA1_PICTUREID]
- ld [de], a ; [x#SPRITESTATEDATA2_PICTUREID] = a
- ld a, $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, wSpritePlayerStateData2PictureID
- xor a
- ldh [hFourTileSpriteCount], a
-; Loop to copy picture IDs from [x#SPRITESTATEDATA2_PICTUREID]
-; to [x#SPRITESTATEDATA2_IMAGEBASEOFFSET].
-.copyPictureIDLoop
- ld a, [hli] ; a = [x#SPRITESTATEDATA2_PICTUREID]
- ld [hld], a ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET] = a
- ld a, l
- add $10
- ld l, a
- dec b
- jr nz, .copyPictureIDLoop
- ld hl, wSprite01StateData2ImageBaseOffset
-.loadTilePatternLoop
- ld de, wSprite01StateData2PictureID
-; Check if the current picture ID has already had its tile patterns loaded.
-; This done by looping through the previous sprite slots and seeing if any of
-; their picture ID's match that of the current sprite slot.
-.checkIfAlreadyLoadedLoop
- ld a, e
- and $f0
- ld b, a ; b = offset of the wSpriteStateData2 sprite slot being checked against
- ld a, l
- and $f0 ; a = offset of current wSpriteStateData2 sprite slot
- cp b ; done checking all previous sprite slots?
- jr z, .notAlreadyLoaded
- ld a, [de] ; picture ID of the wSpriteStateData2 sprite slot being checked against
- cp [hl] ; do the picture ID's match?
- jp z, .alreadyLoaded
- ld a, e
- add $10
- ld e, a
- jr .checkIfAlreadyLoadedLoop
-.notAlreadyLoaded
- ld de, wSpritePlayerStateData2ImageBaseOffset
- 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] ; y#SPRITESTATEDATA2_IMAGEBASEOFFSET
- cp 11 ; is it one of the first 10 slots?
- jr nc, .findNextVRAMSlotLoop
- cp b ; compare the slot being checked to the current max
- jr c, .findNextVRAMSlotLoop ; if the slot being checked is less than the current max
-; if the slot being checked is greater than or equal to the current max
- ld b, a ; store new max VRAM slot
- jr .findNextVRAMSlotLoop
-.foundNextVRAMSlot
- inc b ; increment previous max value to get next VRAM tile pattern slot
- ld a, b ; a = next VRAM tile pattern slot
- push af
- ld a, [hl] ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET]
- ld b, a ; b = current sprite picture ID
- cp FIRST_STILL_SPRITE ; is it a 4-tile sprite?
- jr c, .notFourTileSprite
- pop af
- ldh a, [hFourTileSpriteCount]
- add 11
- jr .storeVRAMSlot
-.notFourTileSprite
- pop af
-.storeVRAMSlot
- ld [hl], a ; store VRAM slot at [x#SPRITESTATEDATA2_IMAGEBASEOFFSET]
- ldh [hVRAMSlot], a ; used to determine if it's 4-tile sprite later
- ld a, b ; a = current sprite picture ID
- dec a
- add a
- add a
- push bc
- push hl
- ld hl, SpriteSheetPointerTable
- jr nc, .noCarry
- inc h
-.noCarry
- add l
- ld l, a
- jr nc, .noCarry2
- inc h
-.noCarry2
- push hl
- call ReadSpriteSheetData
- push af
- push de
- push bc
- ld hl, vNPCSprites ; VRAM base address
- ld bc, 12 tiles ; number of bytes per VRAM slot
- ldh a, [hVRAMSlot]
- cp 11 ; is it a 4-tile sprite?
- jr nc, .fourTileSpriteVRAMAddr
- ld d, a
- dec d
-; hl = vSprites + [hVRAMSlot] * 12 tiles
-.calculateVRAMAddrLoop
- add hl, bc
- dec d
- jr nz, .calculateVRAMAddrLoop
- jr .loadStillTilePattern
-.fourTileSpriteVRAMAddr
- ld hl, vSprites tile $7c ; address for second 4-tile sprite
- ldh a, [hFourTileSpriteCount]
- and a
- jr nz, .loadStillTilePattern
-; if it's the first 4-tile sprite
- ld hl, vSprites tile $78 ; address for first 4-tile sprite
- inc a
- ldh [hFourTileSpriteCount], a
-.loadStillTilePattern
- pop bc
- pop de
- pop af
- push hl
- push hl
- ld h, d
- ld l, e
- pop de
- ld b, a
- ld a, [wFontLoaded]
- bit 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
- ldh a, [hVRAMSlot]
- cp 11 ; is it a 4-tile sprite?
- jr nc, .skipSecondLoad ; if so, there is no second block
- push de
- call ReadSpriteSheetData
- push af
- ld a, $c0
- add e
- ld e, a
- jr nc, .noCarry3
- inc d
-.noCarry3
- ld a, [wFontLoaded]
- bit 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 = [y#SPRITESTATEDATA2_IMAGEBASEOFFSET]
- ld [hl], a ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET] = a
-.nextSpriteSlot
- ld a, l
- add $10
- ld l, a
- dec c
- jp nz, .loadTilePatternLoop
- ld hl, wSpritePlayerStateData2PictureID
- ld b, $10
-; the pictures IDs stored at [x#SPRITESTATEDATA2_PICTUREID] are no longer needed,
-; so zero them
-.zeroStoredPictureIDLoop
- xor a
- ld [hl], a ; [x#SPRITESTATEDATA2_PICTUREID]
- ld a, $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.
@@ -257,15 +23,8 @@ InitOutsideMapSprites:
ld a, [wCurMap]
cp FIRST_INDOOR_MAP ; is the map a city or a route?
ret nc ; if not, return
- ld hl, MapSpriteSets
- add l
- ld l, a
- jr nc, .noCarry
- inc h
-.noCarry
- ld a, [hl] ; a = spriteSetID
- cp $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?
@@ -277,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, wSpritePlayerStateData2PictureID
- ld a, SPRITE_RED
- ld [hl], a
- ld bc, wSpriteSet
-; Load the sprite set into RAM.
-; This loop also fills [x#SPRITESTATEDATA2_PICTUREID] where X is from $0 to $A
-; with picture IDs. This is done so that LoadMapSpriteTilePatterns will
-; load tile patterns for all sprite pictures in the sprite set.
-.loadSpriteSetLoop
- ld a, $10
- add l
- ld l, a
- ld a, [de] ; sprite picture ID from sprite set
- ld [hl], a ; [x#SPRITESTATEDATA2_PICTUREID]
- ld [bc], a
- inc de
- inc bc
- ld a, l
- cp $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 ; [x#SPRITESTATEDATA2_PICTUREID]
- 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, wSprite01StateData2ImageBaseOffset
- 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 ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET]
- ld a, $10
- add l
- ld l, a
- dec b
- jr nz, .zeroVRAMSlotsLoop
.skipLoadingSpriteSet
- ld hl, wSprite01StateData1
+ 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] ; [x#SPRITESTATEDATA1_PICTUREID] (zero if sprite slot is not used)
and a ; is the sprite slot used?
- jr z, .skipGettingPictureIndex ; if the sprite slot is not used
- ld b, a ; b = picture ID
+ jr z, .continue ; if the sprite slot is not used
+ ld c, a
+ call CheckForFourTileSprite ; is this a four tile sprite?
+ jr nc, .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 ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET]
- 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 FIRST_STILL_SPRITE ; is this a four tile sprite?
+ jr nc, .notYellowSprite ; set carry if yes
+; regular sprite
+ and a
+ ret
+
+.notYellowSprite
+ scf
+ ret
+
+LoadMapSpriteTilePatterns:
+ ld a, 0
+.loop
+ ldh [hVRAMSlot], a
+ cp 9
+ jr nc, .fourTileSprite
+ call LoadStillTilePattern
+ call LoadWalkingTilePattern
+ jr .continue
+
+.fourTileSprite
+ call LoadStillTilePattern
+.continue
+ ldh a, [hVRAMSlot]
+ inc a
+ cp 11
+ jr nz, .loop
+ ret
+
+ReloadWalkingTilePatterns:
+ xor a
+.loop
+ ldh [hVRAMSlot], a
+ cp 9
+ jr nc, .fourTileSprite
+ call LoadWalkingTilePattern
+.fourTileSprite
+ ldh a, [hVRAMSlot]
+ inc a
+ cp 11
+ jr nz, .loop
+ ret
+
+LoadStillTilePattern:
+ ld a, [wFontLoaded]
+ bit 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
+ ldh a, [hVRAMSlot]
+ ld c, a
+ ld b, 0
+ ld hl, SpriteVRAMAddresses
+ add hl, bc
+ add hl, bc
+ ld a, [hli]
+ ld h, [hl]
ld l, a
+ pop bc
+ ret
+
+SpriteVRAMAddresses:
+; 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:
+ ldh a, [hVRAMSlot]
+ ld e, a
+ ld d, 0
+ ld hl, wSpriteSet
+ add hl, de
+ ld a, [hl]
and a
- jr nz, .storeVRAMSlotsLoop
+ ret z
+
+ dec a
+ ld l, a
+ ld h, 0
+ add hl, hl
+ add hl, hl
+ ld de, SpriteSheetPointerTable
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ ld c, [hl]
+ swap c ; get the number of tiles, not the raw byte length
+ ; this is because of the use of CopyVideoDataAlternate
+ inc hl
+ ld b, [hl]
+ inc hl
scf
ret
+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
+ ldh [hVRAMSlot], a ; store current sprite set slot as a counter
+ ld a, [hl] ; [x#SPRITESTATEDATA1_PICTUREID]
+ and a ; is the sprite unused?
+ jr z, .spriteUnused
+ call Func_14179
+ push hl
+ ld de, (wSpritePlayerStateData2ImageBaseOffset) - (wSpriteStateData1) ; $10e
+ add hl, de ; [x#SPRITESTATEDATA2_IMAGEBASEOFFSET]
+ ld [hl], a ; write offset
+ pop hl
+.spriteUnused
+ ld de, wSprite02StateData1 - wSprite01StateData1
+ add hl, de
+ ldh a, [hVRAMSlot]
+ dec a
+ jr nz, .loop
+ ret
+
+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 31fdc257..358a9b9f 100644
--- a/engine/overworld/missable_objects.asm
+++ b/engine/overworld/missable_objects.asm
@@ -17,18 +17,15 @@ 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, MissableObjects ; calculate difference between out pointer and the base pointer
ld a, l
- sub e
- jr nc, .asm_f13c
- dec h
-.asm_f13c
+ sub MissableObjects & $ff ; calculate difference between out pointer and the base pointer
ld l, a
ld a, h
- sub d
+ sbc MissableObjects / $100
ld h, a
ld a, h
ldh [hDividend], a
diff --git a/engine/overworld/movement.asm b/engine/overworld/movement.asm
index 2fb8c384..dadf2194 100644
--- a/engine/overworld/movement.asm
+++ b/engine/overworld/movement.asm
@@ -22,7 +22,13 @@ UpdatePlayerSprite:
ld [wSpritePlayerStateData1ImageIndex], a
ret
.lowerLeftTileIsMapTile
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
call DetectCollisionBetweenSprites
+ pop af
+ ld [wUpdateSpritesEnabled], a
ld h, HIGH(wSpriteStateData1)
ld a, [wWalkCounter]
and a
@@ -48,42 +54,24 @@ UpdatePlayerSprite:
jr z, .notMoving
ld a, SPRITE_FACING_RIGHT
jr .next
+.next
+ ld [wSpritePlayerStateData1FacingDirection], a ; facing direction
+ ld a, [wFontLoaded]
+ bit 0, a
+ jr z, .moving
.notMoving
; zero the animation counters
xor a
ld [wSpritePlayerStateData1IntraAnimFrameCounter], a
ld [wSpritePlayerStateData1AnimFrameCounter], a
- jr .calcImageIndex
-.next
- ld [wSpritePlayerStateData1FacingDirection], a
- ld a, [wFontLoaded]
- bit 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
- ldh a, [hCurrentSpriteOffset]
- add $7
- ld l, a
- ld a, [hl]
- inc a
- ld [hl], a
- cp 4
- jr nz, .calcImageIndex
- xor a
- ld [hl], a
- inc hl
- ld a, [hl]
- inc a
- and $3
- ld [hl], a
-.calcImageIndex
- ld a, [wSpritePlayerStateData1AnimFrameCounter]
- ld b, a
- ld a, [wSpritePlayerStateData1FacingDirection]
- add b
- ld [wSpritePlayerStateData1ImageIndex], a
+ call Func_5274
+ call Func_4e32
.skipSpriteAnim
; If the player is standing on a grass tile, make the player's sprite have
; lower priority than the background so that it's partially obscured by the
@@ -100,15 +88,12 @@ UpdatePlayerSprite:
ld [wSpritePlayerStateData2GrassPriority], a
ret
-UnusedReadSpriteDataFunction:
- push bc
- push af
- ldh a, [hCurrentSpriteOffset]
- ld c, a
- pop af
- add c
- ld l, a
- pop bc
+Func_4e32:
+ ld a, [wSpritePlayerStateData1AnimFrameCounter]
+ ld b, a
+ ld a, [wSpritePlayerStateData1FacingDirection]
+ add b
+ ld [wSpritePlayerStateData1ImageIndex], a
ret
UpdateNPCSprite:
@@ -146,6 +131,8 @@ UpdateNPCSprite:
jp z, UpdateSpriteMovementDelay ; [x#SPRITESTATEDATA1_MOVEMENTSTATUS] == 2
cp $3
jp z, UpdateSpriteInWalkingAnimation ; [x#SPRITESTATEDATA1_MOVEMENTSTATUS] == 3
+ cp $4
+ jp z, Func_5357
ld a, [wWalkCounter]
and a
ret nz ; don't do anything yet if player is currently moving (redundant, already tested in CheckSpriteAvailability)
@@ -156,9 +143,9 @@ UpdateNPCSprite:
ld l, a
ld a, [hl] ; x#SPRITESTATEDATA2_MOVEMENTBYTE1
inc a
- jr z, .randomMovement ; value STAY
+ jp z, .randomMovement ; value STAY
inc a
- jr z, .randomMovement ; value WALK
+ jp z, .randomMovement ; value WALK
; scripted movement
dec a
ld [hl], a ; increment movement byte 1 (movement data index)
@@ -183,12 +170,18 @@ UpdateNPCSprite:
ret
.next
cp WALK
- jr nz, .determineDirection
+ jr nz, .asm_4ecb
; current NPC movement data is WALK ($fe). this seems buggy
ld [hl], $1 ; set movement byte 1 to $1
ld de, wNPCMovementDirections
call LoadDEPlusA ; a = [wNPCMovementDirections + $fe] (?)
- jr .determineDirection
+.asm_4ecb
+ push af
+ call Func_5288
+ pop bc
+ ld a, b
+ jr nc, .determineDirection
+ ret
.randomMovement
call GetTileSpriteStandsOn
call Random
@@ -263,34 +256,14 @@ ChangeFacingDirection:
; set carry on failure, clears carry on success
TryWalking:
push hl
- ld h, HIGH(wSpriteStateData1)
- ldh a, [hCurrentSpriteOffset]
- add $9
- ld l, a
- ld [hl], c ; x#SPRITESTATEDATA1_FACINGDIRECTION
- ldh a, [hCurrentSpriteOffset]
- add $3
- ld l, a
- ld [hl], d ; x#SPRITESTATEDATA1_YSTEPVECTOR
- inc l
- inc l
- ld [hl], e ; x#SPRITESTATEDATA1_XSTEPVECTOR
+ call Func_5337
pop hl
push de
- ld c, [hl] ; read tile to walk onto
+ ld c, [hl]
call CanWalkOntoTile
pop de
ret c ; cannot walk there (reinitialization of delay values already done)
- ld h, HIGH(wSpriteStateData2)
- ldh a, [hCurrentSpriteOffset]
- add $4
- ld l, a
- ld a, [hl] ; x#SPRITESTATEDATA2_MAPY
- add d
- ld [hli], a ; update Y position
- ld a, [hl] ; x#SPRITESTATEDATA2_MAPX
- add e
- ld [hl], a ; update X position
+ call Func_5349
ldh a, [hCurrentSpriteOffset]
ld l, a
ld [hl], $10 ; [x#SPRITESTATEDATA2_WALKANIMATIONCOUNTER] = 16
@@ -301,22 +274,7 @@ TryWalking:
; update the walking animation parameters for a sprite that is currently walking
UpdateSpriteInWalkingAnimation:
- ldh a, [hCurrentSpriteOffset]
- add $7
- ld l, a
- ld a, [hl] ; x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER
- inc a
- ld [hl], a ; [x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER]++
- cp $4
- jr nz, .noNextAnimationFrame
- xor a
- ld [hl], a ; [x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER] = 0
- inc l
- ld a, [hl] ; x#SPRITESTATEDATA1_ANIMFRAMECOUNTER
- inc a
- and $3
- ld [hl], a ; advance to next animation frame every 4 ticks (16 ticks total for one step)
-.noNextAnimationFrame
+ call Func_5274
ldh a, [hCurrentSpriteOffset]
add $3
ld l, a
@@ -448,6 +406,7 @@ InitializeSpriteStatus:
ld a, $8
ld [hli], a ; [x#SPRITESTATEDATA2_YDISPLACEMENT] = 8
ld [hl], a ; [x#SPRITESTATEDATA2_XDISPLACEMENT] = 8
+ call InitializeSpriteScreenPosition ; could have done fallthrough here
ret
; calculates the sprite's screen position from its map position and the player position
@@ -460,7 +419,7 @@ InitializeSpriteScreenPosition:
ld b, a
ld a, [hl] ; x#SPRITESTATEDATA2_MAPY
sub b ; relative to player position
- swap a ; * 16
+ call Func_5033
sub $4 ; - 4
dec h
ld [hli], a ; [x#SPRITESTATEDATA1_YPIXELS]
@@ -469,11 +428,23 @@ InitializeSpriteScreenPosition:
ld b, a
ld a, [hli] ; x#SPRITESTATEDATA2_MAPX
sub b ; relative to player position
- swap a ; * 16
+ call Func_5033
dec h
ld [hl], a ; [x#SPRITESTATEDATA1_XPIXELS]
ret
+Func_5033:
+ jr nc, .asm_503c
+ cpl
+ inc a
+ swap a
+ cpl
+ inc a
+ ret
+.asm_503c
+ swap a
+ ret
+
; tests if sprite is off screen or otherwise unable to do anything
CheckSpriteAvailability:
predef IsObjectHidden
@@ -593,16 +564,8 @@ CanWalkOntoTile:
and a
ret
.notScripted
- ld a, [wTilesetCollisionPtr]
- ld l, a
- ld a, [wTilesetCollisionPtr+1]
- ld h, a
-.tilePassableLoop
- ld a, [hli]
- cp $ff
- jr z, .impassable
- cp c
- jr nz, .tilePassableLoop
+ call _IsTilePassable
+ jr c, .impassable
ld h, HIGH(wSpriteStateData2)
ldh a, [hCurrentSpriteOffset]
add $6
@@ -626,7 +589,13 @@ CanWalkOntoTile:
jr nc, .impassable ; don't walk off screen
push de
push bc
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
call DetectCollisionBetweenSprites
+ pop af
+ ld [wUpdateSpritesEnabled], a
pop bc
pop de
ld h, HIGH(wSpriteStateData1)
@@ -649,8 +618,9 @@ CanWalkOntoTile:
; stuck whenever they walked upwards 5 steps
; on the other hand, the amount a sprite can walk out to the
; right of bottom is not limited (until the counter overflows)
+ ; this was fixed in Yellow
cp $5
- jr c, .impassable ; if [x#SPRITESTATEDATA2_YDISPLACEMENT]+d < 5, don't go
+ ;jr c, .impassable ; if [x#SPRITESTATEDATA2_YDISPLACEMENT]+d < 5, don't go
jr .checkHorizontal
.upwards
sub $1
@@ -704,7 +674,7 @@ GetTileSpriteStandsOn:
ld l, a
ld a, [hli] ; x#SPRITESTATEDATA1_YPIXELS
add $4 ; align to 2*2 tile blocks (Y position is always off 4 pixels to the top)
- and $f0 ; in case object is currently moving
+ and $f8 ; in case object is currently moving (XXX why changed to $f8?)
srl a ; screen Y tile * 4
ld c, a
ld b, $0
@@ -870,20 +840,235 @@ AnimScriptedNPCMovement:
ret
AdvanceScriptedNPCAnimFrameCounter:
+ call Func_5274
+ ld h, HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
- add $7
+ add $8
ld l, a
ld a, [hl] ; intra-animation frame counter
+ and $3
+ ldh [hSpriteAnimFrameCounter], a
+ ret
+
+Func_5274:
+ ldh a, [hCurrentSpriteOffset]
+ add $7
+ ld l, a
+ ld h, HIGH(wSpriteStateData1)
+ ld a, [hl] ; x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER
inc a
- ld [hl], a
- cp 4
+ and $3
+ ld [hl], a ; [x#SPRITESTATEDATA1_INTRAANIMFRAMECOUNTER]++
ret nz
- xor a
- ld [hl], a ; reset intra-animation frame counter
inc l
- ld a, [hl] ; animation frame counter
+ ld a, [hl] ; x#SPRITESTATEDATA1_ANIMFRAMECOUNTER
inc a
and $3
+ ld [hl], a ; advance to next animation frame every 4 ticks (16 ticks total for one step)
+ ret
+
+Func_5288:
+; nice lookup table
+; a is supposedly [wNPCMovementDirections + $fe]
+ cp $5
+ jr z, .asm_52af
+ cp $4
+ jr z, .asm_52aa
+ cp $6
+ jr z, .asm_52b4
+ cp $7
+ jr z, .asm_52b9
+ cp $11
+ jr z, .asm_52c3
+ cp $12
+ jr z, .asm_52be
+ cp $13
+ jr z, .asm_52c8
+ cp $14
+ jr z, .asm_52cd
+ xor a
+ ret
+; set 1?
+.asm_52aa
+ call Func_531f
+ jr .asm_52e6
+.asm_52af
+ call Func_5325
+ jr .asm_52e6
+.asm_52b4
+ call Func_5331
+ jr .asm_52e6
+.asm_52b9
+ call Func_532b
+ jr .asm_52e6
+; set 2?
+.asm_52be
+ call Func_531f
+ jr .asm_52fa
+.asm_52c3
+ call Func_5325
+ jr .asm_52fa
+.asm_52c8
+ call Func_5331
+ jr .asm_52fa
+.asm_52cd
+ call Func_532b
+ jr .asm_52fa
+; set 3? (unused)
+.asm_52d2
+ call Func_531f
+ jr .asm_530b
+.asm_52d7
+ call Func_5325
+ jr .asm_530b
+.asm_52dc
+ call Func_5331
+ jr .asm_530b
+.asm_52e1
+ call Func_532b
+ jr .asm_530b
+
+.asm_52e6
+ call Func_5337
+ call Func_5349
+ ldh a, [hCurrentSpriteOffset]
+ ld l, a
+ ld [hl], $8
+ dec h
+ inc l
+ ld [hl], $4
+ call UpdateSpriteImage
+ scf
+ ret
+
+.asm_52fa
+ call Func_5337
+ ldh a, [hCurrentSpriteOffset]
+ ld l, a
+ ld [hl], $8
+ dec h
+ inc l
+ ld [hl], $3
+ call UpdateSpriteImage
+ scf
+ ret
+
+.asm_530b
+ call Func_5337
+ call Func_5349
+ ldh a, [hCurrentSpriteOffset]
+ ld l, a
+ ld [hl], $8
+ dec h
+ inc l
+ ld [hl], $3
+ call UpdateSpriteImage
+ scf
+ ret
+
+Func_531f:
+ lb de, 1, 0
+ ld c, SPRITE_FACING_DOWN
+ ret
+
+Func_5325:
+ lb de, -1, 0
+ ld c, SPRITE_FACING_UP
+ ret
+
+Func_532b:
+ lb de, 0, 1
+ ld c, SPRITE_FACING_RIGHT
+ ret
+
+Func_5331:
+ lb de, 0, -1
+ ld c, SPRITE_FACING_LEFT
+ ret
+
+Func_5337:
+ ldh a, [hCurrentSpriteOffset]
+ add $9
+ ld l, a
+ ld h, HIGH(wSpriteStateData1)
+ ld [hl], c ; x#SPRITESTATEDATA1_FACINGDIRECTION
+ ldh a, [hCurrentSpriteOffset]
+ add $3
+ ld l, a
+ ld [hl], d ; x#SPRITESTATEDATA1_YSTEPVECTOR
+ inc l
+ inc l
+ ld [hl], e ; x#SPRITESTATEDATA1_XSTEPVECTOR
+ ret
+
+Func_5349:
+ ld h, HIGH(wSpriteStateData2)
+ ldh a, [hCurrentSpriteOffset]
+ add $4
+ ld l, a
+ ld a, [hl] ; x#SPRITESTATEDATA2_MAPY
+ add d
+ ld [hli], a ; update Y position
+ ld a, [hl] ; x#SPRITESTATEDATA2_MAPX
+ add e
+ ld [hl], a ; update X position
+ ret
+
+Func_5357:
+ call Func_5274
+ ldh a, [hCurrentSpriteOffset]
+ add $3
+ ld l, a
+ ld h, HIGH(wSpriteStateData1)
+ ld a, [hli]
+ add a
+ ld b, a
+ ld a, [hl]
+ add b
+ ld [hli], a
+ ld a, [hli]
+ add a
+ ld b, a
+ ld a, [hl]
+ add b
+ ld [hl], a
+ ldh a, [hCurrentSpriteOffset]
+ ld l, a
+ ld h, HIGH(wSpriteStateData2)
+ dec [hl]
+ ret nz
+ ld a, $6
+ add l
+ ld l, a
+ ld a, [hl]
+ cp $fe
+ jr nc, .asm_5386
+ ldh a, [hCurrentSpriteOffset]
+ inc a
+ ld l, a
+ ld h, HIGH(wSpriteStateData1)
+ ld [hl], $1
+ ret
+.asm_5386
+ call Random
+ ldh a, [hCurrentSpriteOffset]
+ add $8
+ ld l, a
+ ld h, HIGH(wSpriteStateData2)
+ ldh a, [hRandomAdd]
+ and $7f
+ ld [hl], a
+ dec h
+ ldh a, [hCurrentSpriteOffset]
+ inc a
+ ld l, a
+ ld [hl], $2
+ inc l
+ inc l
+ xor a
+ ld b, [hl]
+ ld [hli], a
+ inc l
+ ld c, [hl]
ld [hl], a
- ldh [hSpriteAnimFrameCounter], a
ret
diff --git a/engine/overworld/npc_movement_2.asm b/engine/overworld/npc_movement_2.asm
new file mode 100755
index 00000000..2ced9da6
--- /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 -1
+ jr z, .notRival
+ cp b
+ ret z ; the rival leaves after battling, so don't freeze him
+ jr .loop
+.notRival
+ ld a, [wSpriteIndex]
+ ldh [hSpriteIndex], a
+ jp SetSpriteMovementBytesToFF
+
+RivalIDs:
+ db OPP_RIVAL1
+ db OPP_RIVAL2
+ db OPP_RIVAL3
+ db -1 ; end
diff --git a/engine/overworld/pathfinding.asm b/engine/overworld/pathfinding.asm
index 1925dbbc..a824d337 100644
--- a/engine/overworld/pathfinding.asm
+++ b/engine/overworld/pathfinding.asm
@@ -14,22 +14,22 @@ FindPathToPlayer:
call CalcDifference
ld d, a
and a
- jr nz, .asm_f8da
+ jr nz, .asm_f76a
ldh a, [hFindPathFlags]
set 0, a ; current end of path matches the player's Y coordinate
ldh [hFindPathFlags], a
-.asm_f8da
+.asm_f76a
ldh a, [hFindPathXProgress]
ld b, a
ldh a, [hNPCPlayerXDistance] ; X distance in steps
call CalcDifference
ld e, a
and a
- jr nz, .asm_f8ec
+ jr nz, .asm_f77c
ldh a, [hFindPathFlags]
set 1, a ; current end of path matches the player's X coordinate
ldh [hFindPathFlags], a
-.asm_f8ec
+.asm_f77c
ldh a, [hFindPathFlags]
cp $3 ; has the end of the path reached the player's position?
jr z, .done
diff --git a/engine/overworld/player_animations.asm b/engine/overworld/player_animations.asm
index c458a013..5056c0b2 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), 12
call CopyVideoData
ld de, BirdSprite tile 12 ; moving animation sprite
+ ld b, BANK(BirdSprite)
+ ld c, 12
ld hl, vNPCSprites2
- lb bc, BANK(BirdSprite), 12
jp CopyVideoData
InitFacingDirectionList:
@@ -380,9 +387,10 @@ FishingAnim:
call DelayFrames
ld hl, wd736
set 6, [hl] ; reserve the last 4 OAM entries
+ ld hl, vNPCSprites
ld de, RedSprite
- ld hl, vNPCSprites tile $00
- lb bc, BANK(RedSprite), 12
+ ld b, BANK(RedSprite)
+ ld c, 12
call CopyVideoData
ld a, $4
ld hl, RedFishingTiles
diff --git a/engine/overworld/player_state.asm b/engine/overworld/player_state.asm
index 70326754..c966c128 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/maps/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
@@ -224,8 +226,7 @@ PrintSafariZoneSteps::
cp CERULEAN_CAVE_2F
ret nc
hlcoord 0, 0
- ld b, 3
- ld c, 7
+ lb bc, 3, 7
call TextBoxBorder
hlcoord 1, 1
ld de, wSafariSteps
@@ -239,11 +240,11 @@ PrintSafariZoneSteps::
call PlaceString
ld a, [wNumSafariBalls]
cp 10
- jr nc, .asm_c56d
+ jr nc, .numSafariBallsTwoDigits
hlcoord 5, 3
ld a, " "
ld [hl], a
-.asm_c56d
+.numSafariBallsTwoDigits
hlcoord 6, 3
ld de, wNumSafariBalls
lb bc, 1, 2
@@ -345,16 +346,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/push_boulder.asm b/engine/overworld/push_boulder.asm
index a8e532d3..09911ca3 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
diff --git a/engine/overworld/sprite_collisions.asm b/engine/overworld/sprite_collisions.asm
index dc57d5b9..db81977b 100644
--- a/engine/overworld/sprite_collisions.asm
+++ b/engine/overworld/sprite_collisions.asm
@@ -1,5 +1,5 @@
_UpdateSprites::
- ld h, $c1
+ ld h, wSpriteStateData1 / $100
inc h
ld a, SPRITESTATEDATA2_IMAGEBASEOFFSET
.spriteLoop
@@ -24,9 +24,12 @@ _UpdateSprites::
jr nz, .spriteLoop
ret
.updateCurrentSprite
- cp $1
- jp nz, UpdateNonPlayerSprite
- jp UpdatePlayerSprite
+ ldh a, [hCurrentSpriteOffset]
+ and a
+ jp z, UpdatePlayerSprite
+ cp $f0 ; pikachu
+ jp z, SpawnPikachu
+ ld a, [hl]
UpdateNonPlayerSprite:
dec a
@@ -52,11 +55,10 @@ UpdateNonPlayerSprite:
; The reason that 4 is added below to the coordinate is to make it align with a
; multiple of $10 to make comparisons easier.
DetectCollisionBetweenSprites:
- nop
+ ; nop
ld h, HIGH(wSpriteStateData1)
ldh a, [hCurrentSpriteOffset]
- add LOW(wSpriteStateData1)
ld l, a
ld a, [hl] ; a = [i#SPRITESTATEDATA1_PICTUREID] (0 if slot is unused)
@@ -271,6 +273,17 @@ DetectCollisionBetweenSprites:
jr nc, .next ; go to next sprite if distance is still positive after both adjustments
.collision
+ ld a, l
+ and $f0 ; collision with pikachu?
+ jr nz, .asm_4cd9
+ xor a
+ ld [wd434], a
+ ldh a, [hFF8F]
+ cp $f
+ jr nz, .asm_4cd9
+ call Func_4d0a
+ jr .asm_4cef
+.asm_4cd9
ldh a, [hFF91] ; a = 7 or 9 depending on sprite i's delta X
ld b, a
ldh a, [hFF90] ; a = 7 or 9 depending on sprite i's delta Y
@@ -296,6 +309,7 @@ DetectCollisionBetweenSprites:
; to indicate which sprite the collision occurred with
inc l
inc l
+.asm_4cef
ldh a, [hFF8F] ; a = loop counter
ld de, SpriteCollisionBitTable
add a
@@ -324,6 +338,26 @@ DetectCollisionBetweenSprites:
; c = 0 if delta X/Y is 0
; c = 7 if delta X/Y is 1
; c = 9 if delta X/Y is -1
+Func_4d0a:
+ ldh a, [hFF91]
+ ld b, a
+ ldh a, [hFF90]
+ 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/tilesets.asm b/engine/overworld/tilesets.asm
index f40cbbc2..686fa50c 100644
--- a/engine/overworld/tilesets.asm
+++ b/engine/overworld/tilesets.asm
@@ -5,23 +5,14 @@ LoadTilesetHeader:
ld a, [wCurMapTileset]
add a
add a
- ld b, a
- add a
- add b ; a = tileset * 12
- jr nc, .noCarry
- inc d
-.noCarry
ld e, a
ld hl, Tilesets
add hl, de
+ add hl, de
+ add hl, de
ld de, wTilesetBank
- ld c, $b
-.copyTilesetHeaderLoop
- ld a, [hli]
- ld [de], a
- inc de
- dec c
- jr nz, .copyTilesetHeaderLoop
+ ld bc, $b
+ call CopyData
ld a, [hl]
ldh [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
ldh a, [hPreviousTileset]
cp b
jr z, .done
-.asm_c797
+.notDungeonTileset
ld a, [wDestinationWarpID]
cp $ff
jr z, .done
diff --git a/engine/overworld/turn_sprite.asm b/engine/overworld/turn_sprite.asm
deleted file mode 100755
index 7b34a03a..00000000
--- a/engine/overworld/turn_sprite.asm
+++ /dev/null
@@ -1,25 +0,0 @@
-UpdateSpriteFacingOffsetAndDelayMovement::
- ld h, HIGH(wSpriteStateData2)
- ldh a, [hCurrentSpriteOffset]
- add $8
- ld l, a
- ld a, $7f ; maximum movement delay
- ld [hl], a ; x#SPRITESTATEDATA2_MOVEMENTDELAY
- dec h ; HIGH(wSpriteStateData1)
- ldh a, [hCurrentSpriteOffset]
- add $9
- ld l, a
- ld a, [hld] ; x#SPRITESTATEDATA1_FACINGDIRECTION
- ld b, a
- xor a
- ld [hld], a
- ld [hl], a ; x#SPRITESTATEDATA1_ANIMFRAMECOUNTER
- ldh a, [hCurrentSpriteOffset]
- add SPRITESTATEDATA1_IMAGEINDEX
- ld l, a
- ld a, [hl] ; x#SPRITESTATEDATA1_IMAGEINDEX
- or b ; or in the facing direction
- ld [hld], a
- ld a, $2 ; delayed movement status
- ld [hl], a ; x#SPRITESTATEDATA1_MOVEMENTSTATUS
- ret
diff --git a/engine/pikachu_emotions.asm b/engine/pikachu_emotions.asm
new file mode 100755
index 00000000..55262493
--- /dev/null
+++ b/engine/pikachu_emotions.asm
@@ -0,0 +1,421 @@
+IsPlayerTalkingToPikachu::
+ ld a, [wd436]
+ and a
+ ret z
+ ldh a, [hSpriteIndexOrTextID]
+ cp $f
+ ret nz
+ call InitializePikachuTextID
+ xor a
+ ldh [hSpriteIndexOrTextID], a
+ ld [wd436], a
+ ret
+
+InitializePikachuTextID::
+ ld a, TEXT_PIKACHU_ANIM ; display
+ ldh [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
+ callfar PlayPikachuSoundClip
+ ret
+
+StarterPikachuEmotionCommand_emote:
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ ld a, [de]
+ inc de
+ push de
+ call ShowPikachuEmoteBubble
+ pop de
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ ret
+
+ShowPikachuEmoteBubble:
+ ld [wWhichEmotionBubble], a
+ ld a, $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
+ callfar Func_f24ae
+ ld a, e
+ cp $ff
+ jr nz, .play_emotion
+ jr .check_pikachu_status ; useless
+
+.check_pikachu_status
+ call IsPlayerPikachuAsleepInParty
+ ldpikaemotion a, PikachuEmotion11
+ jr c, .play_emotion
+ callfar 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
+ callfar 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
+ ldh [hFFFC], a
+ call LoadPikachuSpriteIntoVRAM
+ call .GetMovementData
+ and a
+ jr z, .skip
+ call ApplyPikachuMovementData
+.skip
+ xor a
+ ldh [hFFFC], 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..fd2fbc47
--- /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
+ callfar InitializeSpriteScreenPosition
+ pop bc
+.skip
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $1
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $0
+ call RefreshPikachuFollow
+ ret
+
+Func_fc793:
+ call RefreshPikachuFollow
+ push bc
+ callfar InitializeSpriteScreenPosition
+ pop bc
+ ld hl, wSpritePikachuStateData1ImageIndex - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $ff
+ dec hl
+ ld [hl], $1
+ ret
+
+Func_fc7aa:
+ call Func_fcc92
+ jp c, Func_fc803
+ dec a
+ ld l, a
+ ld h, $0
+ add hl, hl
+ add hl, hl
+ ld de, Pointer_fc7e3
+ add hl, de
+ ld d, h
+ ld e, l
+ ld a, [de]
+ inc de
+ ld hl, wSpritePikachuStateData1FacingDirection - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], a
+ ld a, [de]
+ inc de
+ ld hl, wSpritePikachuStateData1XStepVector - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], a
+ dec hl
+ dec hl
+ ld a, [de]
+ ld [hl], a
+ inc de
+ ld a, [de]
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], a
+ cp $4
+ jp z, Func_fca0a
+ call AreThereAtLeastTwoStepsInPikachuFollowCommandBuffer
+ jp c, FastPikachuFollow
+ jp NormalPikachuFollow
+
+Pointer_fc7e3:
+ db 0, 0
+ db 1, 3
+ db 4, 0
+ db -1, 3
+ db 8, -1
+ db 0, 3
+ db 12, 1
+ db 0, 3
+ db 0, 0
+ db 1, 4
+ db 4, 0
+ db -1, 4
+ db 8, -1
+ db 0, 4
+ db 12, 1
+ db 0, 4
+
+Func_fc803:
+ call Func_fcae2
+ ret c
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ dec [hl]
+ jr nz, .asm_fc823
+ push hl
+ call GetPikachuFollowCommand
+ pop hl
+ cp $5
+ jr nc, Func_fc842
+ ld [hl], $20
+ call Random
+ and $c
+ ld hl, wSpritePikachuStateData1FacingDirection - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], a
+.asm_fc823
+ xor a
+ ld hl, wSpritePikachuStateData1IntraAnimFrameCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hli], a
+ ld [hl], a
+ call UpdatePikachuWalkingSprite
+ ret
+
+Func_fc82e:
+ ld a, [wWalkCounter]
+ and a
+ ret z
+ scf
+ ret
+
+Func_fc835:
+ ld hl, wSpritePikachuStateData2WalkAnimationCounter - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $10
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $1
+ ret
+
+Func_fc842:
+ ld hl, $0
+ push af
+ call Random
+ ldh a, [hRandomAdd]
+ and %11
+ ld e, a
+ ld d, $0
+ ld hl, PointerTable_fc85a
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ pop af
+ jp hl
+
+PointerTable_fc85a:
+ dw Func_fc862
+ dw Func_fc8f8
+ dw Func_fc92b
+ dw Func_fc95d
+
+Func_fc862:
+ dec a
+ add a
+ add a
+ and $c
+ ld hl, wSpritePikachuStateData1FacingDirection - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], a
+ ld hl, wSpritePikachuStateData1MovementStatus - wSpritePikachuStateData1
+ add hl, bc
+ ld [hl], $6
+ xor a
+ ld [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
+ ldh a, [hCurrentSpriteOffset] ; If we're here, this can only be $f0
+ add wSpritePikachuStateData2MapY - wSpritePikachuStateData2
+ ld l, a
+ ld b, [hl]
+ ld a, [wYCoord]
+ cp b
+ jr z, .same_y
+ jr nc, .not_on_screen
+ add (SCREEN_HEIGHT / 2) - 1
+ cp b
+ jr c, .not_on_screen
+.same_y
+ inc l
+ ld b, [hl]
+ ld a, [wXCoord]
+ cp b
+ jr z, .same_x
+ jr nc, .not_on_screen
+ add (SCREEN_WIDTH / 2) - 1
+ cp b
+ jr c, .not_on_screen
+.same_x
+ call .GetNPCCurrentTile
+ ld d, $60
+ ld a, [hli]
+ ld e, a
+ cp d
+ jr nc, .not_on_screen
+ ld a, [hld]
+ cp d
+ jr nc, .not_on_screen
+ ld bc, -20
+ add hl, bc
+ ld a, [hli]
+ cp d
+ jr nc, .not_on_screen
+ ld a, [hl]
+ cp d
+ jr c, .on_screen
+.not_on_screen
+ ld h, wSpriteStateData1 / $100
+ ldh a, [hCurrentSpriteOffset]
+ add wSpritePikachuStateData1ImageIndex - wSpritePikachuStateData1
+ ld l, a
+ ld [hl], $ff
+ scf
+ jr .return
+
+.on_screen
+ ld h, wSpriteStateData2 / $100
+ ldh a, [hCurrentSpriteOffset]
+ add wSpritePikachuStateData2GrassPriority - wSpritePikachuStateData2
+ ld l, a
+ ld a, [wGrassTile]
+ cp e
+ ld a, $0
+ jr nz, .priority
+ ld a, $80
+.priority
+ ld [hl], a
+ and a
+.return
+ ret
+
+.GetNPCCurrentTile:
+ ld h, wSpriteStateData1 / $100
+ ldh a, [hCurrentSpriteOffset]
+ add wSpritePikachuStateData1YPixels - wSpritePikachuStateData1
+ ld l, a
+ ld a, [hli]
+ add $4
+ and $f0
+ srl a
+ ld c, a
+ ld b, $0
+ inc l
+ ld a, [hl]
+ add $2
+ srl a
+ srl a
+ srl a
+ add SCREEN_WIDTH
+ ld d, 0
+ ld e, a
+ ld hl, wTileMap
+ rept 5
+ add hl, bc
+ endr
+ add hl, de
+ ret
+
+ComparePikachuHappinessTo80:
+; preserves a and bc
+ push bc
+ push af
+ ld a, [wPikachuHappiness]
+ cp 80
+ pop bc
+ ld a, b
+ pop bc
+ ret
diff --git a/engine/pikachu_movement.asm b/engine/pikachu_movement.asm
new file mode 100755
index 00000000..2d87e947
--- /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/overworld/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
+ ldh a, [hFFFC]
+ 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..bf1aa57f
--- /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
+ ldh [rNR52], a
+ ld a, $77
+ ldh [rNR50], a
+ xor a
+ ldh [rNR30], a
+ ld hl, rWave_0 ; 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
+ ldh [rNR30], a
+ ldh a, [rNR51]
+ or $44
+ ldh [rNR51], a
+ ld a, $ff
+ ldh [rNR31], a
+ ld a, $20
+ ldh [rNR32], a
+ ld a, $ff
+ ldh [rNR33], a
+ ld a, $87
+ ldh [rNR34], a
+ pop hl
+ pop bc
+ call PlayPikachuPCM
+ xor a
+ ld [wc0f3], a
+ ld [wc0f4], a
+ ld a, $80
+ ldh [rNR52], a
+ xor a
+ ldh [rNR30], a
+ ld hl, rWave_0
+ ld de, wRedrawRowOrColumnSrcTiles
+.reloadWaveDataLoop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, l
+ cp $40 ; end of wave data
+ jr nz, .reloadWaveDataLoop
+ ld a, $80
+ ldh [rNR30], a
+ ldh a, [rNR51]
+ and $bb
+ ldh [rNR51], a
+ xor a
+ ld [wChannelSoundIDs + Ch5], a
+ ld [wChannelSoundIDs + Ch6], a
+ ld [wChannelSoundIDs + Ch7], a
+ ld [wChannelSoundIDs + Ch8], a
+ ldh a, [hLoadedROMBank]
+ 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..7829c048
--- /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:
+ ldh a, [hAutoBGTransferEnabled]
+ push af
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ld a, [de]
+ ld [wPikaPicAnimNumber], a
+ inc de
+ push de
+ call .RunPikapic
+ pop de
+ pop af
+ ldh [hAutoBGTransferEnabled], a
+ ret
+
+.RunPikapic:
+ call PlacePikapicTextBoxBorder
+ callfar LoadOverworldPikachuFrontpicPalettes
+ call ResetPikaPicAnimBuffer
+ call LoadCurrentPikaPicAnimScriptPointer
+ call ExecutePikaPicAnimScript
+ call PlacePikapicTextBoxBorder
+ call RunDefaultPaletteCommand
+ ret
+
+ResetPikaPicAnimBuffer:
+ ld hl, wCurPikaMovementData
+ ld bc, wCurPikaMovementDataEnd - wCurPikaMovementData
+ xor a
+ call FillMemory
+ ld hl, wPikaPicAnimObjectDataBufferSize
+ ld bc, wPikaPicAnimObjectDataBufferEnd - wPikaPicAnimObjectDataBufferSize
+ xor a
+ call FillMemory
+ call ClearPikaPicUsedGFXBuffer
+ ld hl, 100
+ ld a, l
+ ld [wPikaPicAnimTimer], a
+ ld a, h
+ ld [wPikaPicAnimTimer + 1], a
+ ld a, $7
+ ld [wPikaPicPikaDrawStartX], a
+ ld a, $6
+ ld [wPikaPicPikaDrawStartY], a
+ ret
+
+PlacePikapicTextBoxBorder:
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ hlcoord 6, 5
+ lb bc, 5, 5
+ call TextBoxBorder
+ call Delay3
+ call UpdateSprites
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call Delay3
+ ret
+
+LoadCurrentPikaPicAnimScriptPointer:
+ ld a, [wPikaPicAnimNumber]
+ cp $1d
+ jr c, .valid
+ ld a, $0
+.valid
+ ld e, a
+ ld d, 0
+ ld hl, PikaPicAnimPointers
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call UpdatePikaPicAnimPointer
+ ret
+
+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
+ ldh [hAutoBGTransferEnabled], a
+ call RunPikaPicAnimSetupScript
+ call DummyFunction_fdad5
+ call AnimateCurrentPikaPicAnimFrame
+ call DummyFunction_fdad5
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call PikaPicAnimTimerAndJoypad
+ and a
+ jr z, .loop
+ ret
+
+PikaPicAnimTimerAndJoypad:
+ call Delay3
+ call CheckPikaPicAnimTimer
+ and a
+ ret nz
+ call JoypadLowSensitivity
+ ldh a, [hJoyPressed]
+ and 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
+ hlcoord 0, 0
+ ld bc, SCREEN_WIDTH
+ call AddNTimes
+ ld a, [wCurPikaPicAnimObjectXOffset] ; X offset
+ ld c, a
+ ld a, [wPikaPicPikaDrawStartX]
+ add c
+ ld c, a
+ ld b, 0
+ add hl, bc
+ pop bc
+ ret
+
+INCLUDE "data/pikachu_pic_tilemaps.asm"
+
+LoadPikaPicAnimGFXHeader:
+ push hl
+ ld e, a
+ ld d, 0
+ ld hl, PikaPicAnimGFXHeaders
+ add hl, de
+ add hl, de
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld c, a
+ ld a, [hli]
+ ld b, a
+ ld a, [hli]
+ ld e, a
+ ld a, [hli]
+ ld d, a
+ pop hl
+ ret
+
+RunPikaPicAnimSetupScript:
+ call .CheckAndAdvanceTimer
+ ret c
+ xor a
+ ld [wPikaPicAnimPointerSetupFinished], a
+.loop
+ call GetPikaPicAnimByte
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ call JumpToAddress
+ ld a, [wPikaPicAnimPointerSetupFinished]
+ and a
+ jr z, .loop
+ ret
+
+.CheckAndAdvanceTimer:
+ ld a, [wPikaPicAnimDelay]
+ and a
+ ret z
+ dec a
+ ld [wPikaPicAnimDelay], a
+ scf
+ ret
+
+.Jumptable:
+ dw PikaPicAnimCommand_nop ; 00, 0 params
+ dw PikaPicAnimCommand_writebyte ; 01, 1 param
+ dw PikaPicAnimCommand_loadgfx ; 02, 1 param
+ dw PikaPicAnimCommand_object ; 03, 5 params
+ dw PikaPicAnimCommand_nop4 ; 04, 0 params
+ dw PikaPicAnimCommand_nop5 ; 05, 0 params
+ dw PikaPicAnimCommand_deleteobject ; 06, 1 param
+ dw PikaPicAnimCommand_nop7 ; 07, 0 params
+ dw PikaPicAnimCommand_nop8 ; 08, 0 params
+ dw PikaPicAnimCommand_jump ; 09, 1 dw param
+ dw PikaPicAnimCommand_setduration ; 0a, 1 dw param
+ dw PikaPicAnimCommand_cry ; 0b, 1 param
+ dw PikaPicAnimCommand_thunderbolt ; 0c, 0 params
+ dw PikaPicAnimCommand_run ; 0d, 0 params (ret)
+ dw PikaPicAnimCommand_ret ; 0e, 0 params (ret)
+
+PikaPicAnimCommand_nop:
+ ret
+
+PikaPicAnimCommand_ret:
+ ld a, 1
+ ld [wPikaPicAnimTimer], a
+ xor a
+ ld [wPikaPicAnimTimer + 1], a
+ jr PikaPicAnimCommand_run
+
+; XXX
+ ret
+
+PikaPicAnimCommand_setduration:
+ call GetPikaPicAnimByte
+ ld [wPikaPicAnimTimer], a
+ call GetPikaPicAnimByte
+ ld [wPikaPicAnimTimer + 1], a
+ ret
+
+PikaPicAnimCommand_run:
+ ld a, $ff
+ ld [wPikaPicAnimPointerSetupFinished], a
+ ret
+
+PikaPicAnimCommand_writebyte:
+ call GetPikaPicAnimByte
+ ld [wPikaPicAnimDelay], a
+ ret
+
+PikaPicAnimCommand_nop4:
+PikaPicAnimCommand_nop5:
+PikaPicAnimCommand_nop7:
+PikaPicAnimCommand_nop8:
+ ret
+
+PikaPicAnimCommand_jump:
+ call GetPikaPicAnimByte
+ ld l, a
+ call GetPikaPicAnimByte
+ ld h, a
+ call UpdatePikaPicAnimPointer
+ ret
+
+GetPikaPicAnimByte:
+ push hl
+ ld hl, wPikaPicAnimPointer
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ ld a, [hli]
+ call UpdatePikaPicAnimPointer
+ pop hl
+ ret
+
+UpdatePikaPicAnimPointer:
+ push af
+ ld a, l
+ ld [wPikaPicAnimPointer], a
+ ld a, h
+ ld [wPikaPicAnimPointer + 1], a
+ pop af
+ ret
+
+PikaPicAnimCommand_loadgfx:
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ ldh a, [hAutoBGTransferEnabled]
+ push af
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ldh a, [hTilesetType]
+ push af
+ xor a
+ ldh [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
+ ldh [hTilesetType], a
+ pop af
+ ldh [hAutoBGTransferEnabled], a
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ ret
+
+RequestPikaPicAnimGFX:
+ push de
+ ld a, [wPikaPicAnimCurGraphicID]
+ ld d, a
+ ld e, c
+ call CheckIfThereIsRoomForPikaPicAnimGFX
+ pop de
+ jr c, .failed
+ call GetPikaPicVRAMAddressForNewGFX
+ call CopyVideoDataAlternate
+ and a
+.failed
+ ret
+
+DecompressRequestPikaPicAnimGFX:
+ push de
+ ld a, [wPikaPicAnimCurGraphicID]
+ ld d, a
+ ld e, 5 * 5
+ call CheckIfThereIsRoomForPikaPicAnimGFX
+ pop de
+ jr c, .failed
+ ld a, b
+ call UncompressSpriteFromDE
+ ld a, BANK(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
+ callfar PlayPikachuSoundClip
+ ret
+
+PikaPicAnimCommand_thunderbolt:
+ ld a, $1
+ ld [wMuteAudioAndPauseMusic], a
+ call DelayFrame
+ ld a, [wAudioROMBank]
+ push af
+ ld a, BANK(SFX_Battle_2F)
+ ld [wAudioROMBank], a
+ ld [wAudioSavedROMBank], a
+ call .LoadAudio
+ call PlaySound
+ call .FlashScreen
+ call WaitForSoundToFinish
+ pop af
+ ld [wAudioROMBank], a
+ ld [wAudioSavedROMBank], a
+ xor a
+ ld [wMuteAudioAndPauseMusic], a
+ ret
+
+.LoadAudio:
+ ld hl, MoveSoundTable
+ ld e, THUNDERBOLT
+ ld d, 0
+ add hl, de
+ add hl, de
+ add hl, de
+ ld a, BANK(MoveSoundTable)
+ call GetFarByte
+ ld b, a
+ inc hl
+ ld a, BANK(MoveSoundTable)
+ call GetFarByte
+ inc hl
+ ld [wFrequencyModifier], a
+ ld a, BANK(MoveSoundTable)
+ call GetFarByte
+ ld [wTempoModifier], a
+ ld a, b
+ ret
+
+.FlashScreen:
+ ld hl, PikaPicAnimThunderboltPals
+.loop
+ ld a, [hli]
+ cp $ff
+ ret z
+ ld c, a
+ ld b, [hl]
+ inc hl
+ push hl
+ call .UpdatePal
+ pop hl
+ jr .loop
+
+.UpdatePal:
+ ld a, b
+ ldh [rBGP], a
+ call 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 29897242..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
- ldh [hJoyPressed], a
- ldh [hJoyHeld], a
- ret
diff --git a/engine/pokemon/add_mon.asm b/engine/pokemon/add_mon.asm
index d7e7eab1..d3d08e99 100644
--- a/engine/pokemon/add_mon.asm
+++ b/engine/pokemon/add_mon.asm
@@ -170,6 +170,12 @@ _AddPartyMon::
inc de
ld a, [hli] ; catch rate (held item in gen 2)
ld [de], a
+ ld a, [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/pokemon/bills_pc.asm b/engine/pokemon/bills_pc.asm
index df02a496..cc7864f2 100644
--- a/engine/pokemon/bills_pc.asm
+++ b/engine/pokemon/bills_pc.asm
@@ -11,18 +11,15 @@ DisplayPCMainMenu::
and a
jr nz, .leaguePCAvailable
hlcoord 0, 0
- ld b, 8
- ld c, 14
+ lb bc, 8, 14
jr .next
.noOaksPC
hlcoord 0, 0
- ld b, 6
- ld c, 14
+ lb bc, 6, 14
jr .next
.leaguePCAvailable
hlcoord 0, 0
- ld b, 10
- ld c, 14
+ lb bc, 10, 14
.next
call TextBoxBorder
call UpdateSprites
@@ -119,10 +116,13 @@ BillsPCMenu:
lb bc, BANK(PokeballTileGraphics), 1
call CopyVideoData
call LoadScreenTilesFromBuffer2DisableBGTransfer
+ hlcoord 0, 12
+ lb bc, 4, 18
+ call TextBoxBorder
hlcoord 0, 0
- ld b, 10
- ld c, 12
+ lb bc, 12, 12
call TextBoxBorder
+ call UpdateSprites
hlcoord 2, 2
ld de, BillsPCMenuText
call PlaceString
@@ -133,7 +133,7 @@ BillsPCMenu:
ld [hli], a ; wTopMenuItemX
inc hl
inc hl
- ld a, 4
+ ld a, 5
ld [hli], a ; wMaxMenuItem
ld a, 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
hlcoord 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:
+ callfar PrintPCBox
+ jp BillsPCMenu
+
BillsPCDeposit:
ld a, [wPartyCount]
dec a
@@ -222,11 +225,26 @@ BillsPCDeposit:
ld hl, wPartyCount
call DisplayMonListMenu
jp c, BillsPCMenu
+ callfar IsThisPartymonStarterPikachu_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
+ callfar IsThisPartymonStarterPikachu_Party
+ jr nc, .asm_215c9
+ ld e, $1b
+ callfar 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:
+ text_far _SleepingPikachuText2
+ text_end
+
BillsPCWithdraw:
ld a, [wNumInBox]
and a
@@ -276,9 +298,15 @@ BillsPCWithdraw:
ld a, [wWhichPokemon]
ld hl, wBoxMonNicks
call GetPartyMonName
+ callfar IsThisPartymonStarterPikachu_Box
+ jr nc, .asm_21660
+ ld e, $22
+ callfar 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
+ callfar 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
+ callfar PlayPikachuSoundClip
+ ld hl, PikachuUnhappyText
+ call PrintText
+ jp BillsPCMenu
+
BillsPCChangeBox:
farcall ChangeBox
jp BillsPCMenu
@@ -343,6 +383,7 @@ BillsPCMenuText:
next "DEPOSIT <PKMN>"
next "RELEASE <PKMN>"
next "CHANGE BOX"
+ next "PRINT BOX"
next "SEE YA!"
db "@"
@@ -381,8 +422,7 @@ INCLUDE "data/moves/hm_moves.asm"
DisplayDepositWithdrawMenu:
hlcoord 9, 10
- ld b, 6
- ld c, 9
+ lb bc, 6, 9
call TextBoxBorder
ld a, [wParentMenuItem]
and a ; was the Deposit or Withdraw item selected in the parent menu?
@@ -488,6 +528,10 @@ CantTakeMonText:
text_far _CantTakeMonText
text_end
+PikachuUnhappyText:
+ text_far _PikachuUnhappyText
+ text_end
+
ReleaseWhichMonText:
text_far _ReleaseWhichMonText
text_end
diff --git a/engine/pokemon/evos_moves.asm b/engine/pokemon/evos_moves.asm
index ed44f9a6..4e48fe30 100755
--- a/engine/pokemon/evos_moves.asm
+++ b/engine/pokemon/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
+ callfar 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/pokemon/evos_moves.asm"
diff --git a/engine/pokemon/learn_move.asm b/engine/pokemon/learn_move.asm
index 8e852fd4..d365acd4 100755
--- a/engine/pokemon/learn_move.asm
+++ b/engine/pokemon/learn_move.asm
@@ -121,18 +121,17 @@ TryingToLearn:
ld hl, WhichMoveToForgetText
call PrintText
hlcoord 4, 7
- ld b, 4
- ld c, 14
+ lb bc, 4, 14
call TextBoxBorder
hlcoord 6, 8
ld de, wMovesString
- ldh a, [hFlagsFFF6]
+ ldh a, [hFlagsFFFA]
set 2, a
- ldh [hFlagsFFF6], a
+ ldh [hFlagsFFFA], a
call PlaceString
- ldh a, [hFlagsFFF6]
+ ldh a, [hFlagsFFFA]
res 2, a
- ldh [hFlagsFFF6], a
+ ldh [hFlagsFFFA], 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, hFlagsFFF6
+ ld hl, hFlagsFFFA
set 1, [hl]
call HandleMenuInput
- ld hl, hFlagsFFF6
+ ld hl, hFlagsFFFA
res 1, [hl]
push af
call LoadScreenTilesFromBuffer1
@@ -206,11 +205,36 @@ TryingToLearnText:
text_end
OneTwoAndText:
+; bugfix: In Red/Blue, the SFX_SWAP sound was played in the wrong bank, which played an incorrect sound
+; Yellow has fixed this by swapping to the correct bank
text_far _OneTwoAndText
text_pause
text_asm
+ push af
+ push bc
+ push de
+ push hl
+ ld a, $1
+ ld [wMuteAudioAndPauseMusic], a
+ call DelayFrame
+ ld a, [wAudioROMBank]
+ push af
+ ld a, BANK(SFX_Swap_1)
+ ld [wAudioROMBank], a
+ ld [wAudioSavedROMBank], a
+ call WaitForSoundToFinish
ld a, SFX_SWAP
- call PlaySoundWaitForCurrent
+ call PlaySound
+ call WaitForSoundToFinish
+ pop af
+ ld [wAudioROMBank], a
+ ld [wAudioSavedROMBank], a
+ xor a
+ ld [wMuteAudioAndPauseMusic], a
+ pop hl
+ pop de
+ pop bc
+ pop af
ld hl, PoofText
ret
diff --git a/engine/pokemon/load_mon_data.asm b/engine/pokemon/load_mon_data.asm
index c5e2041a..53840728 100644
--- a/engine/pokemon/load_mon_data.asm
+++ b/engine/pokemon/load_mon_data.asm
@@ -15,7 +15,7 @@ LoadMonData_::
ld a, [wWhichPokemon]
ld e, a
- callfar GetMonSpecies
+ call GetMonSpecies
.GetMonHeader
ld a, [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/pokemon/status_screen.asm b/engine/pokemon/status_screen.asm
index d4a4e59a..a2cfb595 100755
--- a/engine/pokemon/status_screen.asm
+++ b/engine/pokemon/status_screen.asm
@@ -40,7 +40,7 @@ DrawHP_:
push hl
call DrawHPBar
pop hl
- ldh a, [hFlagsFFF6]
+ ldh a, [hFlagsFFFA]
bit 0, a
jr z, .printFractionBelowBar
ld bc, $9 ; right of bar
@@ -170,8 +170,25 @@ StatusScreen:
call GBPalNormal
hlcoord 1, 0
call LoadFlippedFrontSpriteByMonIndex ; draw Pokémon picture
+ ld a, [wMonDataLocation]
+ cp ENEMY_PARTY_DATA
+ jr z, .playRegularCry
+ cp BOX_DATA
+ jr z, .checkBoxData
+ callfar IsThisPartymonStarterPikachu_Party
+ jr nc, .playRegularCry
+ jr .playPikachuSoundClip
+.checkBoxData
+ callfar IsThisPartymonStarterPikachu_Box
+ jr nc, .playRegularCry
+.playPikachuSoundClip
+ ld e, 16
+ callfar PlayPikachuSoundClip
+ jr .continue
+.playRegularCry
ld a, [wcf91]
call PlayCry ; play Pokémon cry
+.continue
call WaitForTextScrollButtonPress ; wait for button
pop af
ldh [hTilesetType], a
@@ -251,16 +268,14 @@ PrintStatsBox:
and a ; a is 0 from the status screen
jr nz, .DifferentBox
hlcoord 0, 8
- ld b, 8
- ld c, 8
+ lb bc, 8, 8
call TextBoxBorder ; Draws the box
hlcoord 1, 9 ; Start printing stats from here
ld bc, $19 ; Number offset
jr .PrintStats
.DifferentBox
hlcoord 9, 2
- ld b, 8
- ld c, 9
+ lb bc, 8, 9
call TextBoxBorder
hlcoord 11, 3
ld bc, $18
@@ -315,8 +330,7 @@ StatusScreen2:
hlcoord 19, 3
ld [hl], $78
hlcoord 0, 8
- ld b, 8
- ld c, 18
+ lb bc, 8, 18
call TextBoxBorder ; Draw move container
hlcoord 2, 9
ld de, wMovesString
diff --git a/engine/predefs.asm b/engine/predefs.asm
index a9877739..73f69d03 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
diff --git a/engine/printer.asm b/engine/printer.asm
new file mode 100644
index 00000000..f0b681af
--- /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
+ ldh [hCanceledPrinting], a
+ call Printer_PlayPrinterMusic
+ ldh a, [rIE]
+ push af
+ xor a
+ ldh [rIF], a
+ ld a, $9
+ ldh [rIE], a
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call Printer_GetDexEntryRegisters
+ call Printer_StartTransmission
+ ld a, [wPrinterPokedexMonIsOwned]
+ and a
+ jr z, .not_caught
+ ld a, 16
+ jr .got_size
+
+.not_caught
+ ld a, 19
+.got_size
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call ClearScreen
+ callfar Pokedex_DrawInterface
+ callfar Pokedex_PlacePokemonList
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call .TryPrintPage
+ jr c, .finish_printing
+ ld a, [wPrinterPokedexMonIsOwned]
+ and a
+ jr z, .finish_printing
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ ld c, $c
+ call DelayFrames
+ call SaveScreenTilesToBuffer1
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call Printer_PrepareDexEntryForPrinting
+ ld a, $7
+ call Printer_StartTransmission
+ ld a, $3
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call .TryPrintPage
+.finish_printing
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ xor a
+ ldh [rIF], a
+ pop af
+ ldh [rIE], a
+ call ReloadMapAfterPrinter
+ call Printer_PlayMapMusic
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ ret
+
+.TryPrintPage:
+ call Printer_ResetJoypadHRAM
+.print_loop
+ call JoypadLowSensitivity
+ call Printer_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:
+ callfar DrawDexEntryOnScreen
+ ld a, l
+ ld [wPrinterPokedexEntryTextPointer], a
+ ld a, h
+ ld [wPrinterPokedexEntryTextPointer + 1], a
+ ld a, $0
+ rla ; copy carry flag state to bit 0
+ ld [wPrinterPokedexMonIsOwned], a
+ and a
+ jr z, .not_caught
+ ld a, $5
+ jr .got_num_rows
+
+.not_caught
+ ld a, $9
+.got_num_rows
+ ret
+
+Printer_PrepareDexEntryForPrinting:
+ call ClearScreen
+ callfar Pokedex_PrepareDexEntryForPrinting
+ ret
+
+PrintSurfingMinigameHighScore:
+ xor a
+ ldh [hCanceledPrinting], a
+ call Printer_PlayPrinterMusic
+ call Printer_PrepareSurfingMinigameHighScoreTileMap
+ ldh a, [rIE]
+ push af
+ xor a
+ ldh [rIF], a
+ ld a, $9
+ ldh [rIE], a
+ call StartTransmission_Send9Rows
+ ld a, $13
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call Printer_ResetJoypadHRAM
+.loop
+ call JoypadLowSensitivity
+ call Printer_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
+ ldh [rIF], a
+ pop af
+ ldh [rIE], a
+ call ReloadMapAfterPrinter
+ call Printer_PlayMapMusic
+ ret
+
+PrintDiploma::
+ xor a
+ ldh [hCanceledPrinting], a
+ call Printer_PlayPrinterMusic
+ call _DisplayDiploma
+ ldh a, [rIE]
+ push af
+ xor a
+ ldh [rIF], a
+ ld a, $9
+ ldh [rIE], a
+ call StartTransmission_Send9Rows
+ ld a, $10
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call Func_e8d11
+ jr c, .asm_e8cfa
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ ld c, $c
+ call DelayFrames
+ call SaveScreenTilesToBuffer1
+ xor a
+ ldh [hAutoBGTransferEnabled], 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
+ ldh [rIF], a
+ pop af
+ ldh [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
+ ldh [hCanceledPrinting], a
+ call Printer_PlayPrinterMusic
+ ldh a, [rIE]
+ push af
+ xor a
+ ldh [rIF], a
+ ld a, $9
+ ldh [rIE], a
+ call SaveScreenTilesToBuffer1
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call PrintPCBox_DrawPage1
+ call StartTransmission_Send9Rows
+ ld a, $10
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ call Func_e8dfb
+ jr c, .asm_e8ddc
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ ld c, 12
+ call DelayFrames
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call PrintPCBox_DrawPage2
+ call StartTransmission_Send9Rows
+ ld a, $0
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ call Func_e8dfb
+ jr c, .asm_e8ddc
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ ld c, 12
+ call DelayFrames
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call PrintPCBox_DrawPage3
+ call StartTransmission_Send9Rows
+ ld a, $0
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ call Func_e8dfb
+ jr c, .asm_e8ddc
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ ld c, 12
+ call DelayFrames
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call PrintPCBox_DrawPage4
+ call StartTransmission_Send9Rows
+ ld a, $3
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call LoadScreenTilesFromBuffer1
+ call Func_e8dfb
+.asm_e8ddc
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ xor a
+ ldh [rIF], a
+ pop af
+ ldh [rIE], a
+ call ReloadMapAfterPrinter
+ call Printer_PlayMapMusic
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ ret
+
+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:
+ text_far _NoPokemonText
+ text_end
+
+PrintFanClubPortrait::
+ xor a
+ ldh [hCanceledPrinting], a
+ call Printer_PlayPrinterMusic
+ call Printer_GetMonStats
+ ldh a, [rIE]
+ push af
+ xor a
+ ldh [rIF], a
+ ld a, $9
+ ldh [rIE], a
+ call StartTransmission_Send9Rows
+ ld a, $13
+ ld [wcae2], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call Printer_ResetJoypadHRAM
+.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
+ ldh [rIF], a
+ pop af
+ ldh [rIE], a
+ call ReloadMapAfterPrinter
+ call Printer_PlayMapMusic
+ ret
+
+PrinterDebug:
+ push af
+ push bc
+ push de
+ push hl
+ call StopAllMusic
+ ldh a, [rIE]
+ push af
+ xor a
+ ldh [rIF], a
+ ld a, $9
+ ldh [rIE], a
+ call StartTransmission_Send9Rows
+ ld a, $13
+ ld [wcae2], a
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call Printer_CopyTileMapToPrinterTileBuffer
+ call PrinterDebug_LoadGFX
+.loop
+ ld a, [wPrinterSendState]
+ bit 7, a
+ jr nz, .quit
+ call PrinterDebug_DoFunction
+ call PrinterDebug_ConvertStatusFlagsToTiles
+ call DelayFrame
+ jr .loop
+
+.quit
+ xor a
+ ld [wPrinterConnectionOpen], a
+ ld [wPrinterOpcode], a
+ ld hl, wOAMBuffer + 32 * 4
+ ld bc, 8 * 4
+ xor a
+ call FillMemory
+ xor a
+ ldh [rIF], a
+ pop af
+ ldh [rIE], a
+ pop hl
+ pop de
+ pop bc
+ pop af
+ ret
+
+Printer_CheckPressingB:
+ ldh 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
+ ldh [rSB], a
+ ld a, $1
+ ldh [rSC], a
+ ld a, $81
+ ldh [rSC], a
+.wait_send_cancel
+ ld a, [wPrinterOpcode]
+ and a
+ jr nz, .wait_send_cancel
+.already_done
+ ld a, $1
+ ldh [hCanceledPrinting], a
+ scf
+ ret
+
+Printer_CopyTileMapToPrinterTileBuffer:
+ hlcoord 0, 0
+ decoord 0, 0, wPrinterTileBuffer
+ ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
+ call CopyData
+ ret
+
+Printer_CopyTileMapFromPrinterTileBuffer:
+ hlcoord 0, 0, wPrinterTileBuffer
+ decoord 0, 0
+ ld bc, SCREEN_HEIGHT * SCREEN_WIDTH
+ call CopyData
+ ret
+
+Printer_ResetJoypadHRAM:
+ xor a
+ ldh [hJoyLast], a
+ ldh [hJoyReleased], a
+ ldh [hJoyPressed], a
+ ldh [hJoyHeld], a
+ ldh [hJoy5], a
+ ldh [hJoy6], a
+ ret
+
+Printer_PlayPrinterMusic:
+ call Printer_FadeOutMusicAndWait
+ ld a, [wAudioROMBank]
+ ld [wAudioSavedROMBank], a
+ ld a, BANK(Music_GBPrinter)
+ ld [wAudioROMBank], a
+ ld a, MUSIC_GB_PRINTER
+ ld [wNewSoundID], a
+ call PlaySound
+ ret
+
+Printer_PlayMapMusic:
+ call Printer_FadeOutMusicAndWait
+ call PlayDefaultMusic
+ ret
+
+Printer_FadeOutMusicAndWait:
+ ld a, $4
+ ld [wAudioFadeOutControl], a
+ call StopAllMusic
+.wait_music_stop
+ ld a, [wAudioFadeOutControl]
+ and a
+ jr nz, .wait_music_stop
+ ret
+
+GBPrinter_CheckForErrors:
+ ld a, [wPrinterHandshake]
+ cp $81
+ jr z, .check_other_errors
+ ld a, [wPrinterStatusFlags]
+ cp $ff
+ jr z, .error2
+ xor a
+ jr .load_status
+
+.check_other_errors
+ ld a, [wPrinterStatusFlags]
+ and %11100000
+ ret z
+ bit 7, a
+ jr nz, .error1
+ bit 6, a
+ jr nz, .error4
+ ; error 3
+ ld a, PRINTER_ERROR_3
+ jr .load_status
+
+.error4
+ ld a, PRINTER_ERROR_4
+ jr .load_status
+
+.error1
+ ld a, PRINTER_ERROR_1
+ jr .load_status
+
+.error2
+ ld a, PRINTER_ERROR_2
+.load_status
+ ld [wPrinterStatusIndicator], a
+ ret
+
+GBPrinter_UpdateStatusMessage:
+ ld a, [wPrinterStatusIndicator]
+ and a
+ ret z
+ push af
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ hlcoord 0, 5
+ lb bc, 10, 18
+ call TextBoxBorder
+ pop af
+ ld e, a
+ ld d, $0
+ ld hl, .PrinterStatusMessages
+ add hl, de
+ add hl, de
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ hlcoord 1, 7
+ call PlaceString
+ hlcoord 2, 15
+ ld de, .PressBToCancel
+ call PlaceString
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ xor a
+ ld [wPrinterStatusIndicator], a
+ ret
+
+.PressBToCancel:
+ db "Press B to Cancel@"
+
+.PrinterStatusMessages:
+ dw .Blank
+ dw .CheckingLink
+ dw .Transmitting
+ dw .Printing
+ dw .Error1
+ dw .Error2
+ dw .Error3
+ dw .Error4
+ dw .WrongDevice
+
+.Blank:
+ db "@"
+.CheckingLink:
+ db ""
+ next " CHECKING LINK...@"
+.Transmitting:
+ db ""
+ next " TRANSMITTING...@"
+.Printing:
+ db ""
+ next " PRINTING...@"
+.Error1:
+ db " Printer Error 1"
+ next ""
+ next "Check the Game Boy"
+ next "Printer Manual.@"
+.Error2:
+ db " Printer Error 2"
+ next ""
+ next "Check the Game Boy"
+ next "Printer Manual.@"
+.Error3:
+ db " Printer Error 3"
+ next ""
+ next "Check the Game Boy"
+ next "Printer Manual.@"
+.Error4:
+ db " Printer Error 4"
+ next ""
+ next "Check the Game Boy"
+ next "Printer Manual.@"
+.WrongDevice:
+ db "This is not the"
+ next "Game Boy Printer!@"
+
+Printer_PrepareSurfingMinigameHighScoreTileMap:
+ call GBPalWhiteOutWithDelay3
+ call ClearScreen
+ ld de, SurfingPikachu2Graphics
+ ld hl, vChars2
+ lb bc, BANK(SurfingPikachu2Graphics), (SurfingPikachu2GraphicsEnd - SurfingPikachu2Graphics) / $10
+ call CopyVideoData
+ hlcoord 0, 0
+ call .PlaceRowAlternatingTiles
+ hlcoord 0, 17
+ call .PlaceRowAlternatingTiles
+ hlcoord 0, 0
+ call .PlaceColumnAlternatingTiles
+ hlcoord 19, 0
+ call .PlaceColumnAlternatingTiles
+ ld a, $4
+ hlcoord 0, 0
+ ld [hl], a
+ hlcoord 0, 17
+ ld [hl], a
+ hlcoord 19, 0
+ ld [hl], a
+ hlcoord 19, 17
+ ld [hl], a
+ ld de, .Tilemap1
+ hlcoord 10, 8
+ lb bc, 3, 8
+ call Diploma_Surfing_CopyBox
+ ld de, .Tilemap2
+ hlcoord 2, 11
+ lb bc, 6, 16
+ call Diploma_Surfing_CopyBox
+ ld de, .PikachusBeachString
+ hlcoord 3, 2
+ call PlaceString
+ ld de, .HiScoreString
+ hlcoord 9, 4
+ call PlaceString
+ ld de, .PointsString
+ hlcoord 12, 6
+ call PlaceString
+ ld de, wPlayerName
+ ld hl, wPlayerName
+ ld bc, 0
+.find_end_of_name
+ ld a, [hli]
+ inc c
+ cp "@"
+ jr nz, .find_end_of_name
+ ld a, 8
+ sub c
+ jr nc, .got_name_length
+ xor a
+.got_name_length
+ ld c, a
+ hlcoord 2, 4
+ add hl, bc
+ call PlaceString
+ call CopySurfingMinigameScore
+ ld b, 8
+ call RunPaletteCommand
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call Delay3
+ call GBPalNormal
+ ret
+
+.PlaceRowAlternatingTiles:
+ ld c, SCREEN_WIDTH / 2
+.row_loop
+ ld [hl], $0
+ inc hl
+ ld [hl], $1
+ inc hl
+ dec c
+ jr nz, .row_loop
+ ret
+
+.PlaceColumnAlternatingTiles:
+ ld c, SCREEN_HEIGHT / 2
+ ld de, SCREEN_WIDTH
+.col_loop
+ ld [hl], $2
+ add hl, de
+ ld [hl], $3
+ add hl, de
+ dec c
+ jr nz, .col_loop
+ ret
+
+.Tilemap1:
+ 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
+ hlcoord 7, 6
+ ld a, [de]
+ call .BCDConvertScore
+ ld a, [de]
+.BCDConvertScore:
+ ld c, a
+ swap a
+ and $f
+ add -10
+ ld [hli], a
+ ld a, c
+ and $f
+ add -10
+ ld [hli], a
+ dec de
+ ret
+
+SurfingPikachu2Graphics: INCBIN "gfx/surfing_pikachu_2.2bpp"
+SurfingPikachu2GraphicsEnd:
+
+PrintPCBox_DrawPage1:
+ xor a
+ ld [wBoxNumString], a
+ call ClearScreen
+ call PrintPCBox_PlaceHorizontalLines
+ hlcoord 0, 0
+ ld bc, 11 * SCREEN_WIDTH
+ ld a, " "
+ call FillMemory
+ call PrintPCBox_DrawLeftAndRightBorders
+ call PrintPCBox_DrawTopBorder
+ hlcoord 4, 4
+ ld de, .PokemonListString
+ call PlaceString
+ hlcoord 7, 6
+ ld de, .BoxString
+ call PlaceString
+ hlcoord 11, 6
+ ld a, [wCurrentBoxNum]
+ and $7f
+ cp 9
+ jr c, .less_than_9
+ sub 9
+ ld [hl], "1"
+ inc hl
+ add "0"
+ jr .placed_box_number
+
+.less_than_9
+ add "1"
+.placed_box_number
+ ld [hl], a
+ hlcoord 4, 9
+ ld de, wBoxSpecies
+ ld c, $3
+ call PrintPCBox_PlaceBoxMonInfo
+ ret
+
+.PokemonListString: db "POKéMON LIST@"
+.BoxString: db "BOX@"
+
+PrintPCBox_DrawPage2:
+ call ClearScreen
+ call PrintPCBox_PlaceHorizontalLines
+ call PrintPCBox_DrawLeftAndRightBorders
+ ld a, [wBoxDataStart]
+ cp 4
+ ret c
+ hlcoord 4, 0
+ ld de, wBoxSpecies + 3
+ ld c, 6
+ call PrintPCBox_PlaceBoxMonInfo
+ ret
+
+PrintPCBox_DrawPage3:
+ call ClearScreen
+ call PrintPCBox_PlaceHorizontalLines
+ call PrintPCBox_DrawLeftAndRightBorders
+ ld a, [wBoxDataStart]
+ cp 10
+ ret c
+ hlcoord 4, 0
+ ld de, wBoxSpecies + 9
+ ld c, 6
+ call PrintPCBox_PlaceBoxMonInfo
+ ret
+
+PrintPCBox_DrawPage4:
+ call ClearScreen
+ call PrintPCBox_PlaceHorizontalLines
+ call PrintPCBox_DrawLeftAndRightBorders
+ hlcoord 0, 15
+ call PrintPCBox_DrawBottomBorderAtHL
+ hlcoord 0, 16
+ ld bc, 2 * SCREEN_WIDTH
+ ld a, " "
+ call FillMemory
+ ld a, [wBoxDataStart]
+ cp 16
+ ret c
+ hlcoord 4, 0
+ ld de, wBoxSpecies + 15
+ ld c, 5
+ call PrintPCBox_PlaceBoxMonInfo
+ ret
+
+PrintPCBox_PlaceBoxMonInfo:
+.loop
+ ld a, c
+ and a
+ jr z, .done
+ dec c
+ ld a, [de]
+ cp $ff
+ jr z, .done
+ ld [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:
+ hlcoord 0, 0
+ ld a, $79
+ ld [hli], a
+ ld a, $7a
+ ld c, SCREEN_WIDTH - 2
+.loop
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ld a, $7b
+ ld [hl], a
+ ret
+
+PrintPCBox_DrawLeftAndRightBorders:
+ hlcoord 0, 0
+ ld de, SCREEN_WIDTH - 1
+ ld c, SCREEN_HEIGHT
+.loop
+ ld a, $7c
+ ld [hl], a
+ add hl, de
+ ld a, $7c
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ret
+
+PrintPCBox_DrawBottomBorder:
+ hlcoord 0, 17
+PrintPCBox_DrawBottomBorderAtHL:
+ ld a, $7d
+ ld [hli], a
+ ld a, $7a
+ ld c, SCREEN_WIDTH - 2
+.loop
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ld a, $7e
+ ld [hl], a
+ ret
+
+PrintPCBox_PlaceHorizontalLines:
+ hlcoord 4, 0
+ ld c, 6
+ call .PlaceHorizontalLine
+ hlcoord 6, 1
+ ld c, 6
+.PlaceHorizontalLine:
+.loop
+ push bc
+ push hl
+ ld de, .HorizontalLineString
+ call PlaceString
+ pop hl
+ ld bc, 3 * SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+.HorizontalLineString:
+ db "----------@"
diff --git a/engine/printer/serial.asm b/engine/printer/serial.asm
new file mode 100755
index 00000000..97f655bb
--- /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
+ ldh [rSB], a
+ ldh [rSC], a
+ ld [wPrinterOpcode], a
+ ld hl, wPrinterConnectionOpen
+ set 0, [hl]
+ ld a, [wPrinterSettings]
+ ld [wPrinterSettingsTempCopy], a
+ pop af
+ ld [wPrinterQueueLength], a
+ ret
+
+PrinterTransmissionJumptable:
+ ld a, [wPrinterSendState]
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Jumptable:
+ dw Printer_InitSerial ; 00
+ dw Printer_CheckConnectionStatus ; 01
+ dw Printer_WaitSerial ; 02
+ dw Printer_StartTransmittingTilemap ; 03
+ dw Printer_TransmissionLoop ; 04
+ dw Printer_WaitSerialAndLoopBack2 ; 05
+ dw Printer_EndTilemapTransmission ; 06
+ dw Printer_TransmissionLoop ; 07
+ dw Printer_WaitSerial ; 08
+
+ dw Printer_SignalSendHeader ; 09
+ dw Printer_TransmissionLoop ; 0a
+ dw Printer_WaitSerial ; 0b
+ dw Printer_WaitUntilFinished ; 0c
+ dw Printer_Quit ; 0d
+
+ dw Printer_Next_ ; 0e
+ dw Printer_WaitSerial ; 0f
+ dw Printer_SignalLoopBack ; 10
+ dw Printer_LoopBack ; 11
+ dw Printer_WaitLoopBack ; 12
+ dw Printer_WaitLoopBack_ ; 13
+
+Printer_Next:
+ ld hl, wPrinterSendState
+ inc [hl]
+ ret
+
+Printer_Back:
+ ld hl, wPrinterSendState
+ dec [hl]
+ ret
+
+Printer_Quit:
+ xor a
+ ld [wPrinterStatusFlags], a
+ ld hl, wPrinterSendState
+ set 7, [hl]
+ ret
+
+Printer_Next_:
+ call Printer_Next
+ ret
+
+Printer_LoopBack:
+ ld a, $1
+ ld [wPrinterSendState], a
+ ret
+
+Printer_InitSerial:
+ call ResetPrinterData
+ ld hl, PrinterDataPacket1
+ call CopyPrinterDataHeader
+ xor a
+ ld [wPrinterDataSize], a
+ ld [wPrinterDataSize + 1], a
+ ld a, [wPrinterQueueLength]
+ ld [wPrinterRowIndex], a
+ call Printer_Next
+ call Printer_PrepareToSend
+ ld a, PRINTER_STATUS_CHECKING_LINK
+ ld [wPrinterStatusIndicator], a
+ ret
+
+Printer_StartTransmittingTilemap:
+ call ResetPrinterData
+ ld hl, wPrinterRowIndex
+ ld a, [hl]
+ and a
+ jr z, Printer_EndTilemapTransmission
+ ld hl, PrinterDataPacket3
+ call CopyPrinterDataHeader
+ call Printer_Convert2RowsTo2bpp
+ ld a, (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
+ ldh [rSB], a
+ ld a, $1
+ ldh [rSC], a
+ ld a, $81
+ ldh [rSC], a
+ ret
+
+CopyPrinterDataHeader:
+ ld a, [hli]
+ ld [wPrinterDataHeader], a
+ ld a, [hli]
+ ld [wPrinterDataHeader + 1], a
+ ld a, [hli]
+ ld [wPrinterDataHeader + 2], a
+ ld a, [hli]
+ ld [wPrinterDataHeader + 3], a
+ ld a, [hli]
+ ld [wPrinterChecksum], a
+ ld a, [hl]
+ ld [wPrinterChecksum + 1], a
+ ret
+
+ResetPrinterData:
+ xor a
+ ld hl, wPrinterDataHeader
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ld hl, wPrinterChecksum
+ ld [hli], a
+ ld [hl], a
+ xor a
+ ld [wPrinterDataSize], a
+ ld [wPrinterDataSize + 1], a
+ ld hl, wPrinterSendDataSource1
+ ld bc, wPrinterSendDataSource1End - wPrinterSendDataSource1
+ call Printer_FillMemory
+ ret
+
+ComputePrinterChecksum:
+ ld hl, $0
+ ld bc, $4
+ ld de, wPrinterDataHeader
+ call .AddToChecksum
+ ld a, [wPrinterDataSize]
+ ld c, a
+ ld a, [wPrinterDataSize + 1]
+ ld b, a
+ ld de, wPrinterSendDataSource1
+ call .AddToChecksum
+ ld a, l
+ ld [wPrinterChecksum], a
+ ld a, h
+ ld [wPrinterChecksum + 1], a
+ ret
+
+.AddToChecksum:
+.loop
+ ld a, [de]
+ inc de
+ add l
+ jr nc, .no_carry
+ inc h
+.no_carry
+ ld l, a
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ ret
+
+Printer_StageHeaderForSend:
+ ld a, $1
+ ld [wPrinterSendDataSource1], a
+ ld a, [wcae2]
+ ld [wPrinterSendDataSource1 + 1], a
+ ld a, %11100100
+ ld [wPrinterSendDataSource1 + 2], a
+ ld a, [wPrinterSettingsTempCopy]
+ ld [wPrinterSendDataSource1 + 3], a
+ ret
+
+Printer_Convert2RowsTo2bpp:
+ ld a, [wPrinterRowIndex]
+ ld b, a
+ ld a, [wPrinterQueueLength]
+ sub b
+ ld hl, wPrinterTileBuffer
+ ld de, 2 * SCREEN_WIDTH
+.get_row
+ and a
+ jr z, .got_row
+ add hl, de
+ dec a
+ jr .get_row
+
+.got_row
+ ld e, l
+ ld d, h
+ ld hl, wPrinterSendDataSource1
+ ld c, 2 * SCREEN_WIDTH
+.loop
+ ld a, [de]
+ inc de
+ push bc
+ push de
+ push hl
+ swap a
+ ld d, a
+ and $f0
+ ld e, a
+ ld a, d
+ and $f
+ ld d, a
+ and $8
+ ld a, d
+ jr nz, .vchars1
+ or $90
+ jr .got_addr
+
+.vchars1
+ or $80
+.got_addr
+ ld d, a
+ lb bc, BANK(Printer_Convert2RowsTo2bpp), 1
+ call CopyVideoData
+ pop hl
+ ld de, $10
+ add hl, de
+ pop de
+ pop bc
+ dec c
+ jr nz, .loop
+ ret
+
+Printer_FillMemory:
+ push de
+ ld e, a
+.loop
+ ld [hl], e
+ inc hl
+ dec bc
+ ld a, c
+ or b
+ jr nz, .loop
+ ld a, e
+ pop de
+ ret
+
+PrinterDataPacket1:
+ db 1, 0, $00, 0
+ dw 1
+PrinterDataPacket2:
+ db 2, 0, $04, 0
+ dw 0
+PrinterDataPacket3:
+ db 4, 0, $80, 2
+ dw 0
+PrinterDataPacket4:
+ db 4, 0, $00, 0
+ dw 4
+PrinterDataPacket5: ; unused
+ db 8, 0, $00, 0
+ dw 8
+PrinterDataPacket6: ; unused
+ db 15, 0, $00, 0
+ dw 15
+
+PrinterSerial_::
+ ld a, [wPrinterOpcode]
+ ld e, a
+ ld d, 0
+ ld hl, .Jumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.Jumptable:
+ dw .Nop
+
+ dw .SignalTransmissionStart
+ dw .SendHeaderByte1
+ dw .SendHeaderByte2
+ dw .SendHeaderByte3
+ dw .SendHeaderByte4
+ dw .DataByte
+ dw .SendChecksumLo
+ dw .SendChecksumHi
+ dw .SignalTransmissionEnd
+ dw .Receive1
+ dw .Receive2
+
+ dw .SignalTransmissionStart
+ dw .Send_0F
+ dw .Send_00
+ dw .Send_00
+ dw .Send_00
+ dw .Send_0F
+ dw .Send_00
+ dw .SignalTransmissionEnd
+ dw .Receive1
+ dw .Receive2_
+
+ dw .SignalTransmissionStart
+ dw .SignalQuit
+ dw .Send_00
+ dw .Send_00
+ dw .Send_00
+ dw .SignalQuit
+ dw .Send_00
+ dw .SignalTransmissionEnd
+ dw .Receive1
+ dw .Receive2
+
+.NextInstruction:
+ ld hl, wPrinterOpcode
+ inc [hl]
+ ret
+
+.Nop:
+ ret
+
+.SignalTransmissionStart:
+ ld a, $33
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.SendHeaderByte1:
+ ld a, [wPrinterDataHeader]
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.SendHeaderByte2:
+ ld a, [wPrinterDataHeader + 1]
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.SendHeaderByte3:
+ ld a, [wPrinterDataHeader + 2]
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.SendHeaderByte4:
+ ld a, [wPrinterDataHeader + 3]
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.DataByte:
+ ld hl, wPrinterDataSize
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ ld a, e
+ or d
+ jr z, .sent_last_byte
+ dec de
+ ld [hl], d
+ dec hl
+ ld [hl], e
+ ld a, [wPrinterSendByteOffset]
+ ld e, a
+ ld a, [wPrinterSendByteOffset + 1]
+ ld d, a
+ ld hl, wPrinterSendDataSource1
+ add hl, de
+ inc de
+ ld a, e
+ ld [wPrinterSendByteOffset], a
+ ld a, d
+ ld [wPrinterSendByteOffset + 1], a
+ ld a, [hl]
+ call .SendByte
+ ret
+
+.sent_last_byte
+ call .NextInstruction
+.SendChecksumLo:
+ ld a, [wPrinterChecksum]
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.SendChecksumHi:
+ ld a, [wPrinterChecksum + 1]
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.SignalTransmissionEnd:
+ ld a, $0
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.Receive1:
+ ldh a, [rSB]
+ ld [wPrinterHandshake], a
+ ld a, $0
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.Receive2:
+ ldh a, [rSB]
+ ld [wPrinterStatusFlags], a
+ xor a
+ ld [wPrinterOpcode], a
+ ret
+
+.Send_0F:
+ ld a, $f
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.Send_00:
+ ld a, $0
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.SignalQuit:
+ ld a, $8
+ call .SendByte
+ call .NextInstruction
+ ret
+
+.SendByte:
+ ldh [rSB], a
+ ld a, $1
+ ldh [rSC], a
+ ld a, $81
+ ldh [rSC], a
+ ret
+
+.Receive2_:
+ ldh a, [rSB]
+ ld [wPrinterStatusFlags], a
+ xor a
+ ld [wPrinterOpcode], a
+ ret
diff --git a/engine/slots/slot_machine.asm b/engine/slots/slot_machine.asm
index fe137632..ba007d9d 100755
--- a/engine/slots/slot_machine.asm
+++ b/engine/slots/slot_machine.asm
@@ -23,9 +23,11 @@ PromptUserToPlaySlots:
call LoadFontTilePatterns
ld b, SET_PAL_SLOTS
call RunPaletteCommand
+ call Delay3
call GBPalNormal
ld a, $e4
ldh [rOBP0], a
+ call UpdateGBCPal_OBP0
ld hl, wd730
set 6, [hl]
xor a
@@ -80,8 +82,7 @@ MainSlotMachineLoop:
ld [wLastMenuItem], a
ld [wMenuWatchMovingOutOfBounds], a
hlcoord 14, 11
- ld b, 5
- ld c, 4
+ lb bc, 5, 4
call TextBoxBorder
hlcoord 16, 12
ld de, CoinMultiplierSlotMachineText
@@ -457,6 +458,7 @@ SlotMachine_CheckForMatches:
ldh a, [rBGP]
xor $40
ldh [rBGP], a
+ call UpdateGBCPal_BGP
ld c, 5
call DelayFrames
dec b
@@ -473,6 +475,7 @@ SlotMachine_CheckForMatches:
call SlotMachine_PrintPayoutCoins
ld a, $e4
ldh [rOBP0], a
+ call UpdateGBCPal_OBP0
jp .done
SymbolLinedUpSlotMachineText:
@@ -698,6 +701,7 @@ SlotMachine_PayCoinsToPlayer:
ldh a, [rOBP0]
xor $40 ; make the slot wheel symbols flash
ldh [rOBP0], a
+ call UpdateGBCPal_OBP0
ld a, 5
.skip1
ld [wAnimCounter], a
@@ -852,17 +856,17 @@ LoadSlotMachineTiles:
ld de, vChars0
ld bc, $1c tiles ; should be SlotMachineTiles2End - SlotMachineTiles2, or $18 tiles
ld a, BANK(SlotMachineTiles2)
- call FarCopyData2
+ call FarCopyData
ld hl, SlotMachineTiles1
ld de, vChars2
ld bc, SlotMachineTiles1End - SlotMachineTiles1
ld a, BANK(SlotMachineTiles1)
- call FarCopyData2
+ call FarCopyData
ld hl, SlotMachineTiles2
ld de, vChars2 tile $25
ld bc, $1c tiles ; should be SlotMachineTiles2End - SlotMachineTiles2, or $18 tiles
ld a, BANK(SlotMachineTiles2)
- call FarCopyData2
+ call FarCopyData
ld hl, SlotMachineMap
decoord 0, 0
ld bc, SlotMachineMapEnd - SlotMachineMap
@@ -884,10 +888,5 @@ SlotMachineMapEnd:
INCLUDE "data/events/slot_machine_wheels.asm"
SlotMachineTiles1:
-IF DEF(_RED)
- INCBIN "gfx/slots/red_slots_1.2bpp"
-ENDC
-IF DEF(_BLUE)
- INCBIN "gfx/slots/blue_slots_1.2bpp"
-ENDC
+ INCBIN "gfx/slots/slots_1.2bpp"
SlotMachineTiles1End:
diff --git a/engine/surfing_minigame.asm b/engine/surfing_minigame.asm
new file mode 100755
index 00000000..578e6b1e
--- /dev/null
+++ b/engine/surfing_minigame.asm
@@ -0,0 +1,2862 @@
+SurfingPikachuMinigame:
+ call SurfingPikachuMinigame_BlankPals
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ ldh a, [hTilesetType]
+ push af
+ xor a
+ ldh [hTilesetType], a
+ ld a, [wUpdateSpritesEnabled]
+ push af
+ ld a, $ff
+ ld [wUpdateSpritesEnabled], a
+ ldh a, [rIE]
+ push af
+ xor a
+ ldh [rIF], a
+ ld a, $f
+ ldh [rIE], a
+ ld a, $8
+ ldh [rSTAT], a
+ ldh a, [hAutoBGTransferDest + 1]
+ push af
+ ld a, $98
+ ldh [hAutoBGTransferDest + 1], a
+ call SurfingPikachuMinigameIntro
+ call SurfingPikachuLoop
+ xor a
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ldh [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
+ call ClearObjectAnimationBuffers
+ call ClearSprites
+ xor a
+ ldh [hLCDCPointer], a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ld a, $90
+ ldh [hWY], a
+ call DelayFrame
+ pop af
+ ldh [hAutoBGTransferDest + 1], a
+ xor a
+ ldh [rIF], a
+ pop af
+ ldh [rIE], a
+ xor a
+ ldh [rSTAT], a
+ call RunDefaultPaletteCommand
+ call ReloadMapAfterSurfingMinigame
+ call PlayDefaultMusic
+ call GBPalNormal
+ pop af
+ ld [wUpdateSpritesEnabled], a
+ pop af
+ ldh [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
+ ldh a, [hJoyPressed]
+ and SELECT
+ ret
+
+Func_f80b7:
+ ldh 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
+ ldh [hAutoBGTransferEnabled], a
+ call ClearObjectAnimationBuffers
+
+ ld hl, SurfingPikachu1Graphics1
+ ld de, $9000
+ ld bc, $500
+ ld a, BANK(SurfingPikachu1Graphics1)
+ call FarCopyData
+
+ ld hl, SurfingPikachu1Graphics2
+ ld de, $8000
+ ld bc, $1000
+ ld a, BANK(SurfingPikachu1Graphics2)
+ call FarCopyData
+
+ ld a, 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
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ld a, $7e
+ ldh [hWY], a
+ ld a, rSCY - $ff00
+ ldh [hLCDCPointer], a
+ ld a, $40
+ ld [wSurfingMinigamePikachuSpeed], a
+ xor a
+ ld [wSurfingMinigamePikachuSpeed + 1], a
+ xor a
+ ld [wSurfingMinigamePikachuHP], a
+ ld a, $60
+ ld [wSurfingMinigamePikachuHP + 1], a
+ ld hl, wSurfingMinigameWaveHeight
+ ld bc, $14
+ ld a, $74
+ call FillMemory
+ call Func_f81ff
+ call Func_f8256
+ ld a, $e3
+ ldh [rLCDC], a
+ call SurfingPikachuMinigame_SetBGPals
+ ld a, $e4
+ ldh [rOBP0], a
+ ld a, $e0
+ ldh [rOBP1], a
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
+ ret
+
+SurfingPikachuMinigame_SetBGPals:
+ ld a, [wOnSGB]
+ and a
+ jr nz, .sgb
+ ld a, $d0
+ ldh [rBGP], a
+ call UpdateGBCPal_BGP
+ ret
+
+.sgb
+ ld a, $e4
+ ldh [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
+ ldh [hSCX], a
+ ld a, $72
+ ld [wSurfingMinigameWaveFunctionNumber], a
+ ld a, $4
+ ld [wc5d2], a
+ xor a
+ ldh [hLCDCPointer], a
+ ld [wSurfingMinigameSCX], a
+ ld [wSurfingMinigameSCX + 1], a
+ ld [wSurfingMinigameSCX + 2], a
+ ret
+
+Func_f835c:
+ ldh a, [hSCX]
+ and a
+ jr z, .asm_f837b
+ call SurfingMinigame_UpdateLYOverrides
+ call SurfingMinigame_SetPikachuHeight
+ call SurfingMinigame_ReadBGMapBuffer
+ ldh a, [hSCX]
+ dec a
+ dec a
+ dec a
+ dec a
+ ldh [hSCX], a
+ ld a, $e0
+ ld [wSurfingMinigameXOffset], a
+ call SurfingMinigame_GenerateBGMap
+ ret
+
+.asm_f837b
+ xor a
+ ld [wSurfingMinigamePikachuSpeed], a
+ ld [wSurfingMinigamePikachuSpeed + 1], a
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ ld a, $5
+ ld [wc5d2], a
+ ret
+
+SurfingMinigame_DrawResultsScreenAndWait:
+ call SurfingMinigame_DrawResultsScreen
+ ld a, 32
+ ld [wSurfingMinigameRoutineDelay], a
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ ret
+
+SurfingMinigame_WriteHPLeftAndWait:
+ call SurfingMinigame_RunDelayTimer
+ ret nc
+ call SurfingMinigame_WriteHPLeft
+ ld a, 64
+ ld [wSurfingMinigameRoutineDelay], a
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ ret
+
+SurfingMinigame_WriteRadnessAndWait:
+ call SurfingMinigame_RunDelayTimer
+ ret nc
+ call SurfingMinigame_WriteRadness
+ ld a, 64
+ ld [wSurfingMinigameRoutineDelay], a
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ ret
+
+SurfingMinigame_WriteTotalAndWait:
+ call SurfingMinigame_RunDelayTimer
+ ret nc
+ call SurfingMinigame_WriteTotal
+ ld a, 64
+ ld [wSurfingMinigameRoutineDelay], a
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ ret
+
+SurfingMinigame_AddRemainingHPToTotalAndWait:
+ call SurfingMinigame_RunDelayTimer
+ ret nc
+ call SurfingMinigame_AddRemainingHPToTotal
+ push af
+ call SurfingMinigame_BCDPrintTotalScore
+ pop af
+ ret nc
+ ld a, 64
+ ld [wSurfingMinigameRoutineDelay], a
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ ret
+
+SurfingMinigame_AddRadnessToTotalAndWait:
+ call SurfingMinigame_RunDelayTimer
+ ret nc
+ call SurfingMinigame_AddRadnessToTotal
+ push af
+ call SurfingMinigame_BCDPrintTotalScore
+ pop af
+ ret nc
+ ld a, 128
+ ld [wSurfingMinigameRoutineDelay], a
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ call DidPlayerGetAHighScore
+ ret nc
+ call SurfingMinigame_PrintTextHiScore
+ ld a, $6
+ ld [wc5d2], a
+ ret
+
+SurfingMinigame_WaitLast:
+ call SurfingMinigame_RunDelayTimer
+ ret nc
+ ld hl, wSurfingMinigameRoutineNumber
+ inc [hl]
+ ret
+
+SurfingMinigame_ExitOnPressA:
+ call SurfingMinigame_UpdateLYOverrides
+ ldh a, [hJoyPressed]
+ and 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
+ ldh 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_CRASH
+ call PlaySound
+ ret
+
+Func_f8516:
+ ld hl, ANIM_OBJ_FIELD_C
+ add hl, bc
+ ld a, [hl]
+ cp $20
+ jr nc, .asm_f8539
+ inc [hl]
+ inc [hl]
+ inc [hl]
+ inc [hl]
+ ld d, $4
+ call SurfingPikachu_Sine
+ ld hl, ANIM_OBJ_Y_OFFSET
+ add hl, bc
+ ld [hl], a
+ call Func_f87b5
+ ld a, [wSurfingMinigamePikachuObjectHeight]
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld [hl], a
+ ret
+
+.asm_f8539
+ ld hl, ANIM_OBJ_Y_OFFSET
+ add hl, bc
+ ld [hl], $0
+ ld a, $0
+ ld [wc5d2], a
+ ret
+
+Func_f8545:
+ ld hl, wc5e1
+ ld a, [hl]
+ and a
+ jr z, .asm_f8556
+ dec [hl]
+ ld a, [wSurfingMinigamePikachuObjectHeight]
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld [hl], a
+ ret
+
+.asm_f8556
+ ld a, $0
+ ld [wc5d2], a
+ ld a, $4
+ call SetCurrentAnimatedObjectCallbackAndResetFrameStateRegisters
+ ret
+
+Func_f8561:
+ ld a, [wSurfingMinigamePikachuObjectHeight]
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld [hl], a
+ call Func_f8742
+ ret
+
+Func_f856d:
+ ld a, $f
+ call SetCurrentAnimatedObjectCallbackAndResetFrameStateRegisters
+ ld hl, ANIM_OBJ_FIELD_C
+ add hl, bc
+ ld [hl], $0
+ ret
+
+Func_f8579:
+ ld hl, ANIM_OBJ_FIELD_C
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ inc [hl]
+ and $3f
+ cp $20
+ jr c, .asm_f8591
+ ld d, $10
+ call SurfingPikachu_Sine
+ ld hl, ANIM_OBJ_Y_OFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.asm_f8591
+ ld hl, ANIM_OBJ_Y_OFFSET
+ add hl, bc
+ ld [hl], $0
+ ret
+
+SurfingMinigame_DPadAction:
+ ld de, hJoy5
+ ld a, [de]
+ and 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_LAND
+ call PlaySound
+ and a
+ ret
+
+.action_0
+ ld a, $40
+ ld [wSurfingMinigamePikachuSpeed], a
+ xor a
+ ld [wSurfingMinigamePikachuSpeed + 1], a
+ scf
+ ret
+
+SurfingMinigame_SpeedUpPikachu:
+ ld a, [wSurfingMinigamePikachuSpeed + 1]
+ cp $2
+ ret nc
+ ld h, a
+ ld a, [wSurfingMinigamePikachuSpeed]
+ ld l, a
+ ld de, $2
+ add hl, de
+ ld a, h
+ ld [wSurfingMinigamePikachuSpeed + 1], a
+ ld a, l
+ ld [wSurfingMinigamePikachuSpeed], a
+ ret
+
+SufingMinigame_ReduceSpeedBy64:
+ ld a, [wSurfingMinigamePikachuSpeed + 1]
+ and a
+ jr nz, .go
+ ld a, [wSurfingMinigamePikachuSpeed]
+ cp $40
+ jr nc, .go
+ xor a
+ ld [wSurfingMinigamePikachuSpeed], a
+ ret
+
+.go
+ ld a, [wSurfingMinigamePikachuSpeed + 1]
+ ld h, a
+ ld a, [wSurfingMinigamePikachuSpeed]
+ ld l, a
+ ld de, -$40
+ add hl, de
+ ld a, h
+ ld [wSurfingMinigamePikachuSpeed + 1], a
+ ld a, l
+ ld [wSurfingMinigamePikachuSpeed], a
+ ret
+
+SufingMinigame_ReduceSpeedBy128:
+ ld a, [wSurfingMinigamePikachuSpeed + 1]
+ and a
+ jr nz, .go
+ ld a, [wSurfingMinigamePikachuSpeed]
+ cp $80
+ jr nc, .go
+ xor a
+ ld [wSurfingMinigamePikachuSpeed], a
+ ret
+
+.go
+ ld a, [wSurfingMinigamePikachuSpeed + 1]
+ ld h, a
+ ld a, [wSurfingMinigamePikachuSpeed]
+ ld l, a
+ ld de, -$80
+ add hl, de
+ ld a, h
+ ld [wSurfingMinigamePikachuSpeed + 1], a
+ ld a, l
+ ld [wSurfingMinigamePikachuSpeed], a
+ ret
+
+Func_f871e:
+ ldh a, [hSCX]
+ and $7
+ cp $3
+ jr c, .asm_f8740
+ cp $5
+ jr nc, .asm_f8740
+ ld a, [wSurfingMinigameBGMapReadBuffer]
+ cp $14
+ jr nz, .asm_f8740
+ call SufingMinigame_GetSpeedDividedBy32
+ cp $a
+ jr c, .asm_f8740
+ ld [wc5ec], a
+ call Func_f9284
+ scf
+ ret
+
+.asm_f8740
+ and a
+ ret
+
+Func_f8742:
+ ldh a, [hSCX]
+ and $7
+ cp $3
+ ret c
+ cp $5
+ ret nc
+ ld a, [wSurfingMinigameBGMapReadBuffer]
+ cp $6
+ jr z, .asm_f8766
+ cp $14
+ jr z, .asm_f8766
+ cp $7
+ jr z, .asm_f876a
+ call Func_f8778
+ ld a, $4
+ ld hl, ANIM_OBJ_FRAME_SET
+ add hl, bc
+ ld [hl], a
+ ret
+
+.asm_f8766
+ ld a, $6
+ jr .asm_f876c
+
+.asm_f876a
+ ld a, $2
+.asm_f876c
+ ld e, a
+ ld a, [wc5de]
+ dec a
+ add e
+ ld hl, ANIM_OBJ_FRAME_SET
+ add hl, bc
+ ld [hl], a
+ ret
+
+Func_f8778:
+ ld hl, wc5e0
+ ld a, [hl]
+ inc [hl]
+ and $7
+ ret nz
+ ld a, [wc5df]
+ and a
+ jr z, .asm_f8796
+ ld a, [wc5de]
+ and a
+ jr z, .asm_f8791
+ dec a
+ ld [wc5de], a
+ ret
+
+.asm_f8791
+ xor a
+ ld [wc5df], a
+ ret
+
+.asm_f8796
+ ld a, [wc5de]
+ cp $2
+ jr z, .asm_f87a2
+ inc a
+ ld [wc5de], a
+ ret
+
+.asm_f87a2
+ ld a, $1
+ ld [wc5df], a
+ ret
+
+SufingMinigame_GetSpeedDividedBy32:
+ ld a, [wSurfingMinigamePikachuSpeed]
+ ld l, a
+ ld a, [wSurfingMinigamePikachuSpeed + 1]
+ ld h, a
+ add hl, hl
+ add hl, hl
+ add hl, hl
+ ld a, h
+ ret
+
+Func_f87b5:
+ ld hl, wc5eb
+ ld a, [hl]
+ inc [hl]
+ and $3
+ ret nz
+ call .GetYCoord
+ ld d, a
+ ld hl, ANIM_OBJ_X_COORD
+ add hl, bc
+ ld e, [hl]
+ ld a, $a
+ push bc
+ call SpawnAnimatedObject
+ pop bc
+ ret
+
+.GetYCoord:
+ ldh a, [hSCX]
+ and $8
+ jr nz, .get_height_plus_9
+ ld hl, wSurfingMinigameWaveHeight + 8
+ jr .got_hl
+
+.get_height_plus_9
+ ld hl, wSurfingMinigameWaveHeight + 9
+.got_hl
+ ld a, [wSurfingMinigameBGMapReadBuffer + 1]
+ cp $6
+ jr z, .six_or_twenty
+ cp $14
+ jr z, .six_or_twenty
+ cp $7
+ jr z, .seven
+ ld a, [hl]
+ ret
+
+.six_or_twenty
+ ldh a, [hSCX]
+ and $7
+ ld e, a
+ ld a, [hl]
+ sub e
+ ret
+
+.seven
+ ldh a, [hSCX]
+ and $7
+ add [hl]
+ ret
+
+Func_f87fb:
+ ld hl, ANIM_OBJ_X_COORD
+ add hl, bc
+ ld a, [hl]
+ cp $58
+ ret z
+ add $4
+ ld [hl], a
+ ret
+
+Func_f8807: ; unreferenced
+ call MaskCurrentAnimatedObjectStruct
+ ret
+
+SurfingMinigameAnimatedObjectFn_FlippingPika:
+ ld hl, ANIM_OBJ_FIELD_B
+ add hl, bc
+ ld a, [hl]
+ and a
+ ret z
+ dec [hl]
+ dec [hl]
+ ld d, a
+ ld hl, ANIM_OBJ_FIELD_C
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ call SurfingPikachu_Sine
+ cp $80
+ jr nc, .positive
+ xor $ff
+ inc a
+.positive
+ ld hl, ANIM_OBJ_Y_OFFSET
+ add hl, bc
+ ld [hl], a
+ ret
+
+SurfingMinigameAnimatedObjectFn_IntroAnimationPikachu:
+ ld hl, ANIM_OBJ_FIELD_B
+ add hl, bc
+ ld a, [hl]
+ inc [hl]
+ and $1
+ ret z
+ ld hl, ANIM_OBJ_X_COORD
+ add hl, bc
+ ld a, [hl]
+ cp $c0
+ jr z, .done
+ inc [hl]
+ ret
+
+.done
+ ld a, $1
+ ld [wSurfingMinigameIntroAnimationFinished], a
+ call MaskCurrentAnimatedObjectStruct
+ ret
+
+SurfingMinigame_MoveClouds:
+ ld a, [wc635]
+ ld e, a
+ ld d, $0
+ ld a, [wSurfingMinigamePikachuSpeed]
+ ld l, a
+ ld a, [wSurfingMinigamePikachuSpeed + 1]
+ ld h, a
+ add hl, de
+ ld a, l
+ ld [wc635], a
+ ld d, h
+ ld hl, 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] ; ???
+ ldh a, [hSCX]
+ add $48
+ ld e, a
+ srl e
+ srl e
+ srl e
+ ld d, $0
+ ld hl, vBGMap0
+ add hl, de
+ ld a, [wSurfingMinigamePikachuObjectHeight]
+ srl a
+ srl a
+ srl a
+ ld c, a
+.loop
+ ld a, c
+ and a
+ jr z, .copy
+ dec c
+ ld de, $20
+ add hl, de
+ ld a, h
+ and $3
+ or $98
+ ld h, a
+ jr .loop
+
+.copy
+ ld de, wSurfingMinigameBGMapReadBuffer
+ ld a, e
+ ldh [hVBlankCopyDest], a
+ ld a, d
+ ldh [hVBlankCopyDest + 1], a
+ ld a, l
+ ldh [hVBlankCopySource], a
+ ld a, h
+ ldh [hVBlankCopySource + 1], a
+ ld a, 16 / $10
+ ldh [hVBlankCopySize], a
+ ret
+
+SurfingMinigame_SetPikachuHeight:
+ ldh a, [hSCX]
+ and $8
+ jr nz, .asm_f88b9
+ ld hl, wSurfingMinigameWaveHeight + 7
+ jr .asm_f88bc
+
+.asm_f88b9
+ ld hl, wSurfingMinigameWaveHeight + 8
+.asm_f88bc
+ ld a, [wSurfingMinigameBGMapReadBuffer]
+ cp $6
+ jr z, .asm_f88d0
+ cp $14
+ jr z, .asm_f88d0
+ cp $7
+ jr z, .asm_f88db
+ ld a, [hl]
+ ld [wSurfingMinigamePikachuObjectHeight], a
+ ret
+
+.asm_f88d0
+ ldh a, [hSCX]
+ and $7
+ ld e, a
+ ld a, [hl]
+ sub e
+ ld [wSurfingMinigamePikachuObjectHeight], a
+ ret
+
+.asm_f88db
+ ldh a, [hSCX]
+ and $7
+ add [hl]
+ ld [wSurfingMinigamePikachuObjectHeight], a
+ ret
+
+SurfingMinigame_Deduct1HP:
+ ld hl, wSurfingMinigamePikachuHP
+ ld e, $99
+ call .BCD_Deduct
+ ret nc
+ inc hl
+ ld e, $99
+.BCD_Deduct:
+ ld a, [hl]
+ and a
+ jr z, .roll_over
+ sub $1
+ daa
+ ld [hl], a
+ and a
+ ret
+
+.roll_over
+ ld [hl], e
+ scf
+ ret
+
+SurfingMinigame_DrawHP:
+ ld de, wSurfingMinigamePikachuHP + 1
+ ld hl, 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
+ decoord 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
+ ldh [hAutoBGTransferEnabled], a
+ ret
+
+.BeachTilemap:
+INCBIN "gfx/unknown_f8946.map"
+.BeachTilemapEnd:
+
+.PlaceTextbox:
+ hlcoord 1, 1
+ lb de, $3b, $3c
+ ld a, $40
+ call .place_row
+ hlcoord 1, 2
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ hlcoord 1, 3
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ hlcoord 1, 4
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ hlcoord 1, 5
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ hlcoord 1, 6
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ hlcoord 1, 7
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ hlcoord 1, 8
+ lb de, $3f, $3f
+ ld a, $ff
+ call .place_row
+ hlcoord 1, 9
+ lb de, $3d, $3e
+ ld a, $40
+ call .place_row
+ ret
+
+.place_row:
+ ld [hl], d
+ inc hl
+ ld c, $10
+.loop
+ ld [hli], a
+ dec c
+ jr nz, .loop
+ ld [hl], e
+ ret
+
+SurfingMinigame_PrintTextHiScore:
+ ld hl, .Hi_Score
+ decoord 6, 8
+ ld bc, $9
+ call CopyData
+ ret
+
+.Hi_Score:
+ db $20,$2e,$2f,$30,$31,$2c,$32,$23,$33 ; Hi-Score!!
+
+SurfingMinigame_WriteHPLeft:
+ ld hl, .HP_Left
+ decoord 2, 2
+ ld bc, $7
+ call CopyData
+ call SurfingMinigame_BCDPrintHPLeft
+ ret
+
+.HP_Left:
+ db $20,$21,$ff,$22,$23,$24,$25 ; HP Left
+
+SurfingMinigame_AddRemainingHPToTotal:
+ ld c, 99
+.loop
+ push bc
+ ld hl, wSurfingMinigamePikachuHP
+ ld a, [hli]
+ or [hl]
+ and a
+ jr z, .dead
+ call SurfingMinigame_Deduct1HP
+ ld e, $1
+ call SurfingMinigame_AddPointsToTotal
+ pop bc
+ dec c
+ jr nz, .loop
+ ld a, SFX_PRESS_AB
+ call PlaySound
+ and a
+ ret
+
+.dead
+ pop bc
+ scf
+ ret
+
+SurfingMinigame_BCDPrintHPLeft:
+ hlcoord 10, 2
+ ld de, wSurfingMinigamePikachuHP + 1
+ ld a, [de]
+ call SurfingPikachu_PlaceBCDNumber
+ inc hl
+ ld a, [de]
+ call SurfingPikachu_PlaceBCDNumber
+ inc hl
+ inc hl
+ ld [hl], $21 ; P
+ inc hl
+ ld [hl], $25 ; t
+ inc hl
+ ld [hl], $26 ; s
+ ret
+
+SurfingMinigame_WriteRadness:
+ ld hl, .Radness
+ decoord 2, 4
+ ld bc, $7
+ call CopyData
+ call SurfingMinigame_BCDPrintRadness
+ ret
+
+.Radness:
+ db $27,$28,$29,$2a,$23,$26,$26 ; Radness
+
+SurfingMinigame_AddRadnessToTotal:
+ ld c, 99
+.loop
+ push bc
+ ld hl, wSurfingMinigameRadnessScore
+ ld a, [hli]
+ ld e, a
+ or [hl]
+ jr z, .done
+ ld d, [hl]
+ ld a, e
+ sub $1
+ daa
+ ld e, a
+ ld a, d
+ sbc $0
+ daa
+ ld [hld], a
+ ld [hl], e
+ ld e, $1
+ call SurfingMinigame_AddPointsToTotal
+ pop bc
+ dec c
+ jr nz, .loop
+ ld a, SFX_PRESS_AB
+ call PlaySound
+ and a
+ ret
+
+.done
+ pop bc
+ scf
+ ret
+
+SurfingMinigame_BCDPrintRadness:
+ ld a, [wSurfingMinigameRadnessScore + 1]
+ hlcoord 10, 4
+ call SurfingPikachu_PlaceBCDNumber
+ ld a, [wSurfingMinigameRadnessScore]
+ hlcoord 12, 4
+ call SurfingPikachu_PlaceBCDNumber
+ inc hl
+ inc hl
+ ld [hl], $21 ; P
+ inc hl
+ ld [hl], $25 ; t
+ inc hl
+ ld [hl], $26 ; s
+ ret
+
+SurfingMinigame_AddPointsToTotal:
+ ld a, [wSurfingMinigameTotalScore]
+ add e
+ daa
+ ld [wSurfingMinigameTotalScore], a
+ ld a, [wSurfingMinigameTotalScore + 1]
+ adc $0
+ daa
+ ld [wSurfingMinigameTotalScore + 1], a
+ ret nc
+ ld a, $99
+ ld [wSurfingMinigameTotalScore], a
+ ld [wSurfingMinigameTotalScore + 1], a
+ ret
+
+SurfingMinigame_BCDPrintTotalScore:
+ ld a, [wSurfingMinigameTotalScore + 1]
+ hlcoord 10, 6
+ call SurfingPikachu_PlaceBCDNumber
+ ld a, [wSurfingMinigameTotalScore]
+ hlcoord 12, 6
+ call SurfingPikachu_PlaceBCDNumber
+ inc hl
+ inc hl
+ ld [hl], $21 ; P
+ inc hl
+ ld [hl], $25 ; t
+ inc hl
+ ld [hl], $26 ; s
+ ret
+
+SurfingMinigame_WriteTotal:
+ ld hl, .Total
+ decoord 2, 6
+ ld bc, $5
+ call CopyData
+ call SurfingMinigame_BCDPrintRadness
+ call SurfingMinigame_BCDPrintTotalScore
+ ret
+
+.Total:
+ db $2b,$2c,$25,$28,$2d ; Total
+
+DidPlayerGetAHighScore:
+ ld hl, wSurfingMinigameHiScore + 1
+ ld a, [wSurfingMinigameTotalScore + 1]
+ cp [hl]
+ jr c, .not_high_score
+ jr nz, .high_score
+ dec hl
+ ld a, [wSurfingMinigameTotalScore]
+ cp [hl]
+ jr c, .not_high_score
+ jr nz, .high_score
+.not_high_score
+ call WaitForSoundToFinish
+ ldpikacry e, PikachuCry28
+ call SurfingMinigame_PlayPikaCryIfSurfingPikaInParty
+ and a
+ ret
+
+.high_score
+ ld a, [wSurfingMinigameTotalScore]
+ ld [wSurfingMinigameHiScore], a
+ ld a, [wSurfingMinigameTotalScore + 1]
+ ld [wSurfingMinigameHiScore + 1], a
+ call WaitForSoundToFinish
+ ldpikacry e, PikachuCry34
+ call SurfingMinigame_PlayPikaCryIfSurfingPikaInParty
+ ld a, SFX_GET_ITEM2_4_2
+ call PlaySound
+ scf
+ ret
+
+SurfingMinigame_PlayPikaCryIfSurfingPikaInParty:
+ push de
+ callfar IsSurfingPikachuInThePlayersParty
+ pop de
+ ret nc
+ callfar PlayPikachuSoundClip
+ ret
+
+SurfingMinigame_IncreaseRadnessMeter:
+ ld a, [wSurfingMinigameRadnessMeter]
+ inc a
+ cp $4
+ jr c, .cap
+ ld a, $3
+.cap
+ ld [wSurfingMinigameRadnessMeter], a
+ ret
+
+SurfingMinigame_CalculateAndAddRadnessFromStunt:
+ ; Compute the amount of radness points from the
+ ; current trick based on the number of
+ ; consecutive flips
+ ; Single flip: +0050
+ ; 2 of the same flip: +0150
+ ; 3 or more of the same flip: +0350
+ ; 2 different flips: +0180
+ ; 3 or more different flips: +0500
+ ld a, [wSurfingMinigameRadnessMeter]
+ and a
+ ret z
+ ld a, [wSurfingMinigameTrickFlags]
+ and $3
+ cp $3 ; did a combination of front and back flips
+ jr z, .mixed_chain
+ ld a, [wSurfingMinigameRadnessMeter]
+ ld d, a
+ ld e, $1
+ ld a, $0
+.get_amount_of_radness
+ add e
+ sla e
+ dec d
+ jr nz, .get_amount_of_radness
+.add_radness_50_at_a_time
+ push af
+ ld e, $50
+ call SurfingMinigame_AddRadness
+ pop af
+ dec a
+ jr nz, .add_radness_50_at_a_time
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld a, [hl]
+ sub $10
+ ld d, a
+ ld hl, ANIM_OBJ_X_COORD
+ add hl, bc
+ ld e, [hl]
+ ld a, [wSurfingMinigameRadnessMeter]
+ add $3
+ push bc
+ call SpawnAnimatedObject
+ pop bc
+ ret
+
+.mixed_chain
+ ld a, [wSurfingMinigameRadnessMeter]
+ cp $3
+ jr c, .add_180_radness_points
+ ld a, 10
+.add_500_radness_50_at_a_time
+ push af
+ ld e, $50
+ call SurfingMinigame_AddRadness
+ pop af
+ dec a
+ jr nz, .add_500_radness_50_at_a_time
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld a, [hl]
+ sub $10
+ ld d, a
+ ld hl, ANIM_OBJ_X_COORD
+ add hl, bc
+ ld e, [hl]
+ ld a, $9
+ push bc
+ call SpawnAnimatedObject
+ pop bc
+ ret
+
+.add_180_radness_points
+ ld e, $50
+ call SurfingMinigame_AddRadness
+ ld e, $50
+ call SurfingMinigame_AddRadness
+ ld e, $50
+ call SurfingMinigame_AddRadness
+ ld e, $30
+ call SurfingMinigame_AddRadness
+ ld hl, ANIM_OBJ_Y_COORD
+ add hl, bc
+ ld a, [hl]
+ sub $10
+ ld d, a
+ ld hl, ANIM_OBJ_X_COORD
+ add hl, bc
+ ld e, [hl]
+ ld a, $8
+ push bc
+ call SpawnAnimatedObject
+ pop bc
+ ret
+
+SurfingMinigame_AddRadness:
+ ld a, [wSurfingMinigameRadnessScore]
+ add e
+ daa
+ ld [wSurfingMinigameRadnessScore], a
+ ld a, [wSurfingMinigameRadnessScore + 1]
+ adc $0
+ daa
+ ld [wSurfingMinigameRadnessScore + 1], a
+ ret nc
+ ld a, $99
+ ld [wSurfingMinigameRadnessScore], a
+ ld [wSurfingMinigameRadnessScore + 1], a
+ ret
+
+Func_f8c97:
+ ld a, $a0
+ ld [wSurfingMinigameXOffset], a
+ ldh a, [hSCX]
+ ld h, a
+ ld a, [wSurfingMinigameSCX]
+ ld l, a
+ ld de, $900
+ add hl, de
+ ld a, l
+ ld [wSurfingMinigameSCX], a
+ ld a, h
+ ldh [hSCX], a
+ jr SurfingMinigame_GenerateBGMap
+
+SurfingMinigame_ScrollAndGenerateBGMap:
+ ld a, $a0
+ ld [wSurfingMinigameXOffset], a
+ ldh a, [hSCX]
+ ld h, a
+ ld a, [wSurfingMinigameSCX]
+ ld l, a
+ ld de, $180
+ add hl, de
+ ld a, l
+ ld [wSurfingMinigameSCX], a
+ ld a, h
+ ldh [hSCX], a
+SurfingMinigame_GenerateBGMap:
+ ld hl, wSurfingMinigameSCX + 1
+ ldh 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
+ ldh a, [hSCX]
+ add e
+ and $f0
+ srl a
+ srl a
+ srl a
+ ld e, a
+ ld d, $0
+ ld hl, vBGMap0
+ add hl, de
+ ld a, l
+ ldh [hRedrawRowOrColumnDest], a
+ ld a, h
+ ldh [hRedrawRowOrColumnDest + 1], a
+ ld a, $1
+ ldh [hRedrawRowOrColumnMode], a
+ ret
+
+.CopyRedrawSrcTiles:
+ push de
+ push hl
+ ld l, a
+ ld h, $0
+ ld de, Unkn_f96e5
+ add hl, hl
+ add hl, hl
+ add hl, de
+ ld e, l
+ ld d, h
+ pop hl
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ inc de
+ ld [hli], a
+ ld a, [de]
+ inc de
+ ld [hli], a
+ pop de
+ ret
+
+SurfingMinigame_GetWaveDataPointers:
+ ld a, [wSurfingMinigameWaveFunctionNumber]
+ ld e, a
+ ld d, $0
+ ld hl, Jumptable_f8d53
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+Jumptable_f8d53:
+ dw SurfingMinigameWaveFunction_NoWave ; 00
+
+ dw Func_f8f28 ; 01
+ dw Func_f8f31 ; 02
+ dw Func_f8f3a ; 03
+ dw Func_f8f43 ; 04
+ dw Func_f8e7d ; 05
+ dw Func_f8f4c ; 06
+ dw Func_f8f55 ; 07
+ dw Func_f8f5e ; 08
+ dw Func_f8e7d ; 09
+ dw Func_f8e7d ; 0a
+ dw Func_f8e7d ; 0b
+ dw Func_f8e7d ; 0c
+ dw Func_f8f94 ; 0d
+
+ dw Func_f8ec5 ; 0e
+ dw Func_f8ece ; 0f
+ dw Func_f8ed7 ; 10
+ dw Func_f8ee0 ; 11
+ dw Func_f8ee9 ; 12
+ dw Func_f8ef2 ; 13
+ dw Func_f8e7d ; 14
+ dw Func_f8e7d ; 15
+ dw Func_f8e7d ; 16
+ dw Func_f8e7d ; 17
+ dw Func_f8e7d ; 18
+ dw Func_f8f94 ; 19
+
+ dw Func_f8efb ; 1a
+ dw Func_f8f04 ; 1b
+ dw Func_f8f0d ; 1c
+ dw Func_f8f16 ; 1d
+ dw Func_f8f1f ; 1e
+ dw Func_f8efb ; 1f
+ dw Func_f8f04 ; 20
+ dw Func_f8f0d ; 21
+ dw Func_f8f16 ; 22
+ dw Func_f8f1f ; 23
+ dw Func_f8e7d ; 24
+ dw Func_f8e7d ; 25
+ dw Func_f8e7d ; 26
+ dw Func_f8e7d ; 27
+ dw Func_f8f94 ; 28
+
+ dw Func_f8f28 ; 29
+ dw Func_f8f31 ; 2a
+ dw Func_f8f3a ; 2b
+ dw Func_f8f43 ; 2c
+ dw Func_f8e7d ; 2d
+ dw Func_f8e7d ; 2e
+ dw Func_f8e7d ; 2f
+ dw Func_f8e7d ; 30
+ dw Func_f8f94 ; 31
+
+ dw Func_f8f4c ; 32
+ dw Func_f8f55 ; 33
+ dw Func_f8f5e ; 34
+ dw Func_f8f4c ; 35
+ dw Func_f8f55 ; 36
+ dw Func_f8f5e ; 37
+ dw Func_f8f4c ; 38
+ dw Func_f8f55 ; 39
+ dw Func_f8f5e ; 3a
+ dw Func_f8e7d ; 3b
+ dw Func_f8e7d ; 3c
+ dw Func_f8e7d ; 3d
+ dw Func_f8e7d ; 3e
+ dw Func_f8f94 ; 3f
+
+ dw Func_f8f67 ; 40
+ dw Func_f8f70 ; 41
+ dw Func_f8efb ; 42
+ dw Func_f8f04 ; 43
+ dw Func_f8f0d ; 44
+ dw Func_f8f16 ; 45
+ dw Func_f8f1f ; 46
+ dw Func_f8f67 ; 47
+ dw Func_f8f70 ; 48
+ dw Func_f8e7d ; 49
+ dw Func_f8e7d ; 4a
+ dw Func_f8e7d ; 4b
+ dw Func_f8f94 ; 4c
+
+ dw Func_f8ec5 ; 4d
+ dw Func_f8ece ; 4e
+ dw Func_f8ed7 ; 4f
+ dw Func_f8ee0 ; 50
+ dw Func_f8ee9 ; 51
+ dw Func_f8ef2 ; 52
+ dw Func_f8e7d ; 53
+ dw Func_f8f67 ; 54
+ dw Func_f8f70 ; 55
+ dw Func_f8f67 ; 56
+ dw Func_f8f70 ; 57
+ dw Func_f8e7d ; 58
+ dw Func_f8e7d ; 59
+ dw Func_f8e7d ; 5a
+ dw Func_f8f94 ; 5b
+
+ dw Func_f8efb ; 5c
+ dw Func_f8f04 ; 5d
+ dw Func_f8f0d ; 5e
+ dw Func_f8f16 ; 5f
+ dw Func_f8f1f ; 60
+ dw Func_f8f28 ; 61
+ dw Func_f8f31 ; 62
+ dw Func_f8f3a ; 63
+ dw Func_f8f43 ; 64
+ dw Func_f8e7d ; 65
+ dw Func_f8e7d ; 66
+ dw Func_f8e7d ; 67
+ dw Func_f8e7d ; 68
+ dw Func_f8f94 ; 69
+
+ dw Func_f8e86 ; 6a
+ dw Func_f8e8f ; 6b
+ dw Func_f8e98 ; 6c
+ dw Func_f8ea1 ; 6d
+ dw Func_f8eaa ; 6e
+ dw Func_f8eb3 ; 6f
+ dw Func_f8ebc ; 70
+ dw Func_f8f9d ; 71
+
+ dw Func_f8e7d ; 72
+ dw Func_f8f79 ; 73
+ dw Func_f8f82 ; 74
+ dw Func_f8f82 ; 75
+ dw Func_f8f82 ; 76
+ dw Func_f8f82 ; 77
+ dw Func_f8f82 ; 78
+ dw Func_f8f82 ; 79
+ dw Func_f8f82 ; 7a
+ dw Func_f8f8b ; 7b
+
+SurfingMinigameWaveFunction_NoWave:
+ ld a, [wc5e5]
+ cp $16
+ jr c, .check_param
+ jr z, .big_kahuna
+ jr nc, .got_wave
+.big_kahuna
+ ld a, $6a
+ jr .got_next_fn
+
+.check_param
+ ld a, [wc5d5]
+ and a
+ jr z, .got_wave
+ dec a
+ and $7
+ ld e, a
+ ld d, $0
+ ld hl, Unkn_f8e75
+ add hl, de
+ ld a, [hl]
+.got_next_fn
+ ld [wSurfingMinigameWaveFunctionNumber], a
+.got_wave
+ lb bc, $74, $74
+ ld de, Unkn_f973d
+ ret
+
+Unkn_f8e75:
+ db $01,$0e,$1a,$29,$32,$40,$4d,$5c
+
+Func_f8e7d:
+ lb bc, $74, $74
+ ld de, Unkn_f973d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8e86:
+ lb bc, $74, $6c
+ ld de, Unkn_f9745
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8e8f:
+ lb bc, $64, $5c
+ ld de, Unkn_f974d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8e98:
+ lb bc, $54, $4c
+ ld de, Unkn_f9755
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8ea1:
+ lb bc, $44, $44
+ ld de, Unkn_f975d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8eaa:
+ lb bc, $44, $4c
+ ld de, Unkn_f9765
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8eb3:
+ lb bc, $54, $5c
+ ld de, Unkn_f976d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8ebc:
+ lb bc, $64, $6c
+ ld de, Unkn_f9775
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8ec5:
+ lb bc, $74, $6c
+ ld de, Unkn_f977d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8ece:
+ lb bc, $64, $5c
+ ld de, Unkn_f9785
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8ed7:
+ lb bc, $54, $4c
+ ld de, Unkn_f978d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8ee0:
+ lb bc, $4c, $4c
+ ld de, Unkn_f9795
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8ee9:
+ lb bc, $54, $5c
+ ld de, Unkn_f979d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8ef2:
+ lb bc, $64, $6c
+ ld de, Unkn_f97a5
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8efb:
+ lb bc, $74, $6c
+ ld de, Unkn_f97ad
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f04:
+ lb bc, $64, $5c
+ ld de, Unkn_f97b5
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f0d:
+ lb bc, $54, $54
+ ld de, Unkn_f97bd
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f16:
+ lb bc, $54, $5c
+ ld de, Unkn_f97c5
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f1f:
+ lb bc, $64, $6c
+ ld de, Unkn_f97cd
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f28:
+ lb bc, $74, $6c
+ ld de, Unkn_f97d5
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f31:
+ lb bc, $64, $5c
+ ld de, Unkn_f97dd
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f3a:
+ lb bc, $5c, $5c
+ ld de, Unkn_f97e5
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f43:
+ lb bc, $64, $6c
+ ld de, Unkn_f97ed
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f4c:
+ lb bc, $74, $6c
+ ld de, Unkn_f97f5
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f55:
+ lb bc, $64, $64
+ ld de, Unkn_f97fd
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f5e:
+ lb bc, $64, $6c
+ ld de, Unkn_f9805
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f67:
+ lb bc, $74, $6c
+ ld de, Unkn_f980d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f70:
+ lb bc, $6c, $6c
+ ld de, Unkn_f9815
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f79:
+ lb bc, $74, $74
+ ld de, Unkn_f981d
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f82:
+ lb bc, $74, $74
+ ld de, Unkn_f9825
+ jp SurfingMinigameWaveFunction_GoToNextWaveFunction
+
+Func_f8f8b:
+ lb bc, $74, $74
+ ld de, Unkn_f9825
+ jp SurfingMinigameWaveFunction_ResetWaveFunction
+
+Func_f8f94:
+ lb bc, $74, $74
+ ld de, Unkn_f973d
+ jp SurfingMinigameWaveFunction_ResetWaveFunction
+
+Func_f8f9d:
+ lb bc, $74, $74
+ ld de, Unkn_f973d
+ ret
+
+Func_f8fa4: ; unused
+ inc a
+ ld [wSurfingMinigameWaveFunctionNumber], a
+ ret
+
+SurfingMinigameWaveFunction_GoToNextWaveFunction:
+ ld hl, wSurfingMinigameWaveFunctionNumber
+ inc [hl]
+ ret
+
+SurfingMinigameWaveFunction_ResetWaveFunction:
+ xor a
+ ld [wSurfingMinigameWaveFunctionNumber], a
+ ret
+
+SurfingPikachuMinigameIntro:
+ call SurfingPikachu_ClearTileMap
+ call ClearSprites
+ call DisableLCD
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ call ClearObjectAnimationBuffers
+ ld hl, SurfingPikachu1Graphics3
+ ld de, $8800
+ ld bc, $900
+ ld a, BANK(SurfingPikachu1Graphics3)
+ call FarCopyData
+ ld a, 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
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ld a, $90
+ ldh [hWY], a
+ ld b, $f
+ call RunPaletteCommand
+ ld a, $e3
+ ldh [rLCDC], a
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ call SurfingPikachuMinigame_SetBGPals
+ ld a, $e4
+ ldh [rOBP0], a
+ ld a, $e0
+ ldh [rOBP1], a
+ call 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
+ decoord 0, 6
+ ld bc, 12 * SCREEN_WIDTH
+ call CopyData
+ ld de, Tilemap_f91c8
+ hlcoord 4, 0
+ lb bc, 6, 12
+ call .CopyBox
+ hlcoord 3, 7
+ lb bc, 3, 15
+ call .FillBoxWithFF
+ ld hl, Tilemap_f91ac
+ decoord 3, 7
+ ld bc, 15
+ call CopyData
+ ld hl, Tilemap_f91bb
+ decoord 4, 9
+ ld bc, 13
+ call CopyData
+ ret
+
+.CopyBox:
+.copy_row
+ push bc
+ push hl
+.copy_col
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .copy_col
+ ld bc, SCREEN_WIDTH
+ pop hl
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .copy_row
+ ret
+
+.FillBoxWithFF:
+.fill_row
+ push bc
+ push hl
+.fill_col
+ ld [hl], $ff
+ inc hl
+ dec c
+ jr nz, .fill_col
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .fill_row
+ ret
+
+Tilemap_f90bc: INCBIN "gfx/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
+ ldh a, [hFrameCounter]
+ and a
+ jr nz, .delayed
+ ldh a, [hJoyHeld]
+ ldh [hJoy5], a
+ ld a, $2
+ ldh [hFrameCounter], a
+ ret
+
+.delayed
+ xor a
+ ldh [hJoy5], a
+ ret
+
+SurfingPikachuMinigame_BlankPals:
+ xor a
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ldh [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
+ ret
+
+SurfingPikachuMinigame_NormalPals:
+ ld a, $e4
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ld a, $e0
+ ldh [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/unknown_ea3ea.asm b/engine/unknown_ea3ea.asm
new file mode 100755
index 00000000..c10f1555
--- /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
+ ldh [hAutoBGTransferEnabled], a
+ xor a
+ ld [wWhichTradeMonSelectionMenu], a
+ call LoadMonData
+
+ ld hl, wTileMap
+ lb bc, 16, 18
+ call TextBoxBorder
+
+ hlcoord 0, 12
+ lb bc, 4, 18
+ call TextBoxBorder
+
+ hlcoord 3, 10
+ call PrintLevelFull
+
+ hlcoord 2, 10
+ ld a, $6e
+ ld [hli], a
+ ld [hl], " "
+
+ hlcoord 2, 11
+ ld [hl], "’"
+
+ hlcoord 4, 11
+ ld de, wLoadedMonMaxHP
+ lb bc, 2, 3
+ call PrintNumber
+
+ ld a, [wMonHeader]
+ ld [wPokeBallAnimData], a
+ ld [wd0b5], a
+ ld hl, wPartyMonNicks
+ call .GetNamePointer
+ hlcoord 8, 2
+ call PlaceString
+
+ call GetMonName
+ hlcoord 9, 3
+ call PlaceString
+
+ predef IndexToPokedex
+ hlcoord 2, 8
+ ld [hl], "№"
+ inc hl
+ ld [hl], $f2
+ inc hl
+ ld de, wPokeBallAnimData
+ lb bc, $80 | 1, 3
+ call PrintNumber
+
+ hlcoord 8, 4
+ ld de, .OT
+ call PlaceString
+
+ ld hl, wPartyMonOT
+ call .GetNamePointer
+ hlcoord 9, 5
+ call PlaceString
+
+ hlcoord 9, 6
+ ld de, .IDNo
+ call PlaceString
+
+ hlcoord 13, 6
+ ld de, wLoadedMonOTID
+ lb bc, $80 | 2, 5
+ call PrintNumber
+
+ hlcoord 9, 8
+ ld de, .Stats
+ ldh a, [hFlagsFFFA]
+ set 2, a
+ ldh [hFlagsFFFA], a
+ call PlaceString
+ ldh a, [hFlagsFFFA]
+ res 2, a
+ ldh [hFlagsFFFA], a
+
+ hlcoord 16, 8
+ ld de, wLoadedMonAttack
+ ld a, 4
+.loop
+ push af
+ push de
+
+ push hl
+ lb bc, 2, 3
+ call PrintNumber
+ pop hl
+ ld bc, SCREEN_WIDTH
+ add hl, bc
+
+ pop de
+ inc de
+ inc de
+ pop af
+ dec a
+ jr nz, .loop
+
+ hlcoord 1, 13
+ ld a, [wLoadedMonMoves]
+ call .PlaceMoveName
+
+ hlcoord 1, 14
+ ld a, [wLoadedMonMoves + 1]
+ call .PlaceMoveName
+
+ hlcoord 1, 15
+ ld a, [wLoadedMonMoves + 2]
+ call .PlaceMoveName
+
+ hlcoord 1, 16
+ ld a, [wLoadedMonMoves + 3]
+ call .PlaceMoveName
+
+ ld b, $4 ; SET_PAL_STATUS_SCREEN
+ call RunPaletteCommand
+
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call Delay3
+ call GBPalNormal
+ hlcoord 1, 1
+ call LoadFlippedFrontSpriteByMonIndex
+ ret
+
+.GetNamePointer:
+ ld bc, NAME_LENGTH
+ ld a, [wWhichPokemon]
+ call AddNTimes
+ ld e, l
+ ld d, h
+ ret
+
+.PlaceMoveName:
+ and a
+ jr z, .no_move
+ ld [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
+ ldh [rSB], a
+ ld a, $1
+ ldh [rSC], a
+ ld a, $81
+ ldh [rSC], a
+ ret
+
+Func_ea76b:
+ ld a, [hli]
+ ld [wPrinterDataHeader], a
+ ld a, [hli]
+ ld [wPrinterDataHeader + 1], a
+ ld a, [hli]
+ ld [wPrinterDataHeader + 2], a
+ ld a, [hli]
+ ld [wPrinterDataHeader + 3], a
+ ld a, [hli]
+ ld [wPrinterDataHeader + 4], a
+ ld a, [hl]
+ ld [wPrinterDataHeader + 5], a
+ ret
+
+Func_ea784:
+ xor a
+ ld hl, wPrinterDataHeader
+ ld [hli], a
+ ld [hli], a
+ ld [hli], a
+ ld [hl], a
+ ld hl, wPrinterDataHeader + 4
+ ld [hli], a
+ ld [hl], a
+ xor a
+ ld [wPrinterDataSize], a
+ ld [wPrinterDataSize + 1], a
+ ld hl, wPrinterSendDataSource1
+ ld bc, $280
+ call FillMemory
+ ret
+
+Func_ea7a2:
+ ld hl, $0
+ ld bc, $4
+ ld de, wPrinterDataHeader
+ call Func_ea7c5
+ ld a, [wPrinterDataSize]
+ ld c, a
+ ld a, [wPrinterDataSize + 1]
+ ld b, a
+ ld de, wPrinterSendDataSource1
+ call Func_ea7c5
+ ld a, l
+ ld [wPrinterDataHeader + 4], a
+ ld a, h
+ ld [wPrinterDataHeader + 5], a
+ ret
+
+Func_ea7c5:
+.asm_ea7c5
+ ld a, [de]
+ inc de
+ add l
+ jr nc, .asm_ea7cb
+ inc h
+.asm_ea7cb
+ ld l, a
+ dec bc
+ ld a, c
+ or b
+ jr nz, .asm_ea7c5
+ ret
+
+Func_ea7d2:
+ ld a, $1
+ ld [wPrinterSendDataSource1], a
+ ld a, [wcae2]
+ ld [wPrinterStatusReceived], a
+ ld a, $e4
+ ld [wc6f2], a
+ ld a, [wPrinterSettingsTempCopy]
+ ld [wc6f3], a
+ ret
+
+PrinterDebug_PrepOAMForPrinting:
+ ld a, [wPrinterRowIndex]
+ ld b, a
+ ld a, [wPrinterQueueLength]
+ sub b
+ ld hl, wPrinterTileBuffer
+ ld de, $28
+.get_start_addr
+ and a
+ jr z, .start_working
+ add hl, de
+ dec a
+ jr .get_start_addr
+
+.start_working
+ ld e, l
+ ld d, h
+ ld hl, wPrinterSendDataSource1
+ ld c, $28
+.prep_loop
+ ld a, [de]
+ inc de
+ push bc
+ push de
+ push hl
+ swap a
+ ld d, a
+ and $f0
+ ld e, a
+ ld a, d
+ and $f
+ ld d, a
+ and $8
+ ld a, d
+ jr nz, .vtiles1
+ or $90
+ jr .got_vram_address
+
+.vtiles1
+ or $80
+.got_vram_address
+ ld d, a
+ lb bc, BANK(PrinterDebug_PrepOAMForPrinting), $1
+ call CopyVideoData
+ pop hl
+ ld de, $10
+ add hl, de
+ pop de
+ pop bc
+ dec c
+ jr nz, .prep_loop
+ call .UnnecessaryCall
+ ret
+
+.UnnecessaryCall:
+ ld hl, wcbdc
+ ld bc, $20
+ xor a
+ call FillMemory
+ ld hl, 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:
+ ldh a, [rOBP0]
+ and $3
+ ret
+
+.Pal2:
+ ldh a, [rOBP0]
+ and $c
+ srl a
+ srl a
+ ret
+
+.Pal1:
+ ldh a, [rOBP0]
+ and $30
+ swap a
+ ret
+
+.Pal3:
+ ldh a, [rOBP0]
+ and $c0
+ rlca
+ rlca
+ ret
+
+.ApplyPaletteFunction:
+ ld e, a
+ ld d, 0
+ ld hl, .PalFunJumptable
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+ jp hl
+
+.PalFunJumptable:
+ dw .zero_zero
+ dw .xflip_zero
+ dw .zero_xflip
+ dw .xflip_xflip
+
+.zero_zero:
+ sla b
+ sla c
+ ret
+
+.xflip_zero:
+ scf
+ rl b
+ sla c
+ ret
+
+.zero_xflip:
+ sla b
+ scf
+ rl c
+ ret
+
+.xflip_xflip:
+ scf
+ rl b
+ scf
+ rl c
+ ret
+
+.PlaceObject:
+ push hl
+ ld a, [hli]
+ ld c, [hl]
+ and $8
+ jr nz, .use_source_2
+ ld hl, wPrinterSendDataSource1
+ jr .got_data_source
+
+.use_source_2
+ ld hl, wPrinterSendDataSource2
+.got_data_source
+ ld b, $0
+ ld a, c
+ and %11111000
+ sub $8
+ ld c, a
+ sla c
+ rl b
+ add hl, bc
+ ld e, l
+ ld d, h
+ ld hl, wcbec
+ ld c, $8
+.coord_copy_loop
+ call .GetBitMask
+ ld a, [de]
+ and b
+ or [hl]
+ ld [de], a
+ inc hl
+ inc de
+ ld a, [de]
+ and b
+ or [hl]
+ ld [de], a
+ inc hl
+ inc de
+ dec c
+ jr nz, .coord_copy_loop
+ pop hl
+ ret
+
+.GetBitMask:
+ push hl
+ push de
+ ld de, -$10
+ add hl, de
+ ld a, [hli]
+ or [hl]
+ xor $ff
+ ld b, a
+ pop de
+ pop hl
+ ret
+
+Data_ea9de:
+ db 1, 0, $00, 0
+ dw 1
+Data_ea9e4:
+ db 2, 0, $04, 0
+ dw 0
+Data_ea9ea:
+ db 4, 0, $80, 2
+ dw 0
+Data_ea9f0:
+ db 4, 0, $00, 0
+ dw 4
+Data_ea9f6:
+ db 8, 0, $00, 0
+ dw 8
+Data_ea9fc:
+ db 15, 0, $00, 0
+ dw 15
diff --git a/engine/vermilion_gym_trash_cans.asm b/engine/vermilion_gym_trash_cans.asm
new file mode 100755
index 00000000..1bc0590b
--- /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]
+ ldh [hGymTrashCanRandNumMask], a
+ ld e, a
+ push hl
+ call TrashCanRandom
+ pop hl
+ add hl, de
+ add hl, de
+ ld a, [hli]
+ ld [wSecondLockTrashCanIndex], a
+ ld a, [hl]
+ ld [wSecondLockTrashCanIndex + 1], a
+ ret
+
+GymTrashCans3c:
+; First byte: number of trashcan entries
+; Following four byte pairs: indices for the second trash can.
+; BUG: Rows that have 3 trashcan entries are sampled incorrectly.
+; The sampling occurs by taking a random number and seeing which
+; third of the range 0-255 the number falls in. However, it returns
+; that value to the wrong register, so the result is never used.
+; Instead of using an offset in [0,1,2], the offset is instead
+; in the full range 0-255. This results in truly random behavior.
+ db 4
+ db 1,3, 3,1, 1,-1, 3,-1
+ db 3
+ db 0,2, 2,4, 4,0, -1,-1
+ db 4
+ db 1,5, 5,1, 1,-1, 5,-1
+ db 3
+ db 0,4, 4,6, 6,0, -1,-1
+ db 4
+ db 1,3, 3,1, 5,5, 7,7
+ db 3
+ db 2,4, 4,8, 8,2, -1,-1
+ db 3
+ db 3,7, 7,9, 9,3, -1,-1
+ db 4
+ db 4,8, 6,10, 8,4, 10,6
+ db 3
+ db 5,7, 7,11, 11,5, -1,-1
+ db 3
+ db 6,10, 10,12, 12,6, -1,-1
+ db 4
+ db 7,9, 9,7, 11,13, 13,11
+ db 3
+ db 8,10, 10,14, 14,8, -1,-1
+ db 4
+ db 9,13, 13,9, 9,-1, 13,-1
+ db 3
+ db 10,12, 12,14, 14,10, -1,-1
+ db 4
+ db 11,13, 13,11, 11,-1, 13,-1
diff --git a/engine/yellow_intro.asm b/engine/yellow_intro.asm
new file mode 100755
index 00000000..324ba86d
--- /dev/null
+++ b/engine/yellow_intro.asm
@@ -0,0 +1,1081 @@
+PlayIntroScene:
+ ldh a, [rIE]
+ push af
+ xor a
+ ldh [rIF], a
+ ld a, $f
+ ldh [rIE], a
+ ld a, $8
+ ldh [rSTAT], a
+ call InitYellowIntroGFXAndMusic
+ call DelayFrame
+.loop
+ ld a, [wYellowIntroCurrentScene]
+ bit 7, a
+ jr nz, .go_to_title_screen
+ call JoypadLowSensitivity
+ ldh a, [hJoyPressed]
+ and 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
+ ldh [hLCDCPointer], a
+ call DelayFrame
+ xor a
+ ldh [rIF], a
+ pop af
+ ldh [rIE], a
+ ld a, $90
+ ldh [hWY], a
+ call ClearObjectAnimationBuffers
+ ld hl, wTileMap
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ xor a
+ call Bank3E_FillMemory
+ call YellowIntro_BlankOAMBuffer
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ret
+
+Func_f98a2:
+ ld a, [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
+ ldh [hLCDCPointer], a
+ lb de, $58, $58
+ ld a, $1
+ call YellowIntro_SpawnAnimatedObjectAndSavePointer
+ xor a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ld a, $90
+ ldh [hWY], a
+ ld a, $e4
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ld a, $c4
+ ldh [rOBP1], a
+ call 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
+ ldh [hLCDCPointer], a
+ ld hl, vBGMap0
+ ld bc, $400
+ xor a
+ call Bank3E_FillMemory
+ call YellowIntroScene2_PlaceGraphic
+ lb de, $58, $b8 ; overloaded
+ ld a, $4 ; overloaded
+ call LoadYellowIntroFlyingSpeedBars
+ ld a, $1
+ call Func_f9e9a
+ call YellowIntro_SetTimerFor128Frames
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene2_PlaceGraphic:
+ ld hl, $98d4 ; (20, 6)
+ ld de, $20
+ ld b, $6
+ ld a, $90
+.row
+ ld c, $6
+ push af
+ push hl
+.col
+ ld [hli], a
+ inc a
+ dec c
+ jr nz, .col
+ pop hl
+ add hl, de
+ pop af
+ add $10
+ dec b
+ jr nz, .row
+ ldh a, [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
+ ldh [rVBK], a
+.attr_row
+ ld c, $6
+ push hl
+.attr_col
+ ld [hli], a
+ dec c
+ jr nz, .attr_col
+ pop hl
+ add hl, de
+ dec b
+ jr nz, .attr_row
+ xor a
+ ldh [rVBK], a
+.dmg_sgb
+ ret
+
+LoadYellowIntroFlyingSpeedBars:
+ ld hl, YellowIntroFlyingSpeedBarData
+ ld a, $8
+.loop
+; Spawn object $8 at indicated coordinates with indicated speeds
+ push af
+ ld e, [hl]
+ inc hl
+ ld d, [hl]
+ inc hl
+ ld a, [hli]
+ push hl
+ push af
+ ld a, $8
+ call SpawnAnimatedObject
+ pop af
+ ld hl, $b
+ add hl, bc
+ ld [hl], a
+ pop hl
+ pop af
+ dec a
+ jr nz, .loop
+ ret
+
+YellowIntroFlyingSpeedBarData:
+ ; y, x, speed
+ db $d0, $20, $02
+ db $f0, $30, $04
+ db $d0, $40, $06
+ db $c0, $50, $08
+ db $e0, $60, $08
+ db $c0, $70, $06
+ db $e0, $80, $04
+ db $f0, $90, $02
+
+YellowIntroScene3:
+ call YellowIntro_CheckFrameTimerDecrement
+ jr c, .expired
+ ldh a, [hSCX]
+ cp $68
+ ret z
+ add $4
+ ldh [hSCX], a
+ ret
+
+.expired
+ call MaskAllAnimatedObjectStructs
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene4:
+ call YellowIntro_BlankPalsDelay2AndDisableLCD
+ ld c, $5
+ call UpdateMusicCTimes
+ ldh a, [hGBC]
+ and a
+ jr z, .dmg_sgb
+ ; We can actually set palettes!
+ ld hl, $98d4
+ ld de, $20
+ ld b, $6
+ ld a, $1
+ ldh [rVBK], a
+ xor a
+.attr_row
+ ld c, $6
+ push hl
+.attr_col
+ ld [hli], a
+ dec c
+ jr nz, .attr_col
+ pop hl
+ add hl, de
+ dec b
+ jr nz, .attr_row
+ xor a
+ ldh [rVBK], a
+.dmg_sgb
+ xor a
+ ldh [hLCDCPointer], a
+ call Func_f9e5f
+ lb de, $58, $58
+ ld a, $2
+ call YellowIntro_SpawnAnimatedObjectAndSavePointer
+ xor a
+ call Func_f9e9a
+ call YellowIntro_SetTimerFor128Frames
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene5:
+ call YellowIntro_CheckFrameTimerDecrement
+ ret nc
+ call YellowIntro_MaskCurrentAnimatedObjectStruct
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene6:
+ call YellowIntro_BlankPalsDelay2AndDisableLCD
+ ld c, $5
+ call UpdateMusicCTimes
+ ld a, rSCY - $ff00
+ ldh [hLCDCPointer], a
+ call YellowIntro_Copy8BitSineWave
+ ld hl, vBGMap0
+ ld bc, $60
+ xor a
+ call Bank3E_FillMemory
+ ld hl, $9860
+ ld c, $10
+ ld a, $20
+.asm_f9a8b
+ ld [hli], a
+ inc a
+ ld [hli], a
+ dec a
+ dec c
+ jr nz, .asm_f9a8b
+ ld hl, $9880
+ ld bc, $300
+ ld a, $10
+ call Bank3E_FillMemory
+ lb de, $40, $f8
+ ld a, $5
+ call YellowIntro_SpawnAnimatedObjectAndSavePointer
+ ld a, $1
+ call Func_f9e9a
+ call YellowIntro_SetTimerFor88Frames
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene7:
+ call YellowIntro_CheckFrameTimerDecrement
+ jr c, .expired
+ ld hl, hSCX
+ inc [hl]
+ inc [hl]
+ ld hl, wLYOverridesBuffer
+ ld de, wLYOverridesBuffer + 1
+ ld a, [hl]
+ push af
+ ld c, $ff
+.shift_loop
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .shift_loop
+ pop af
+ ld [hl], a
+ call Request7TileTransferFromC810ToC710
+ ret
+
+.expired
+ call YellowIntro_MaskCurrentAnimatedObjectStruct
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene8:
+ call YellowIntro_BlankPalsDelay2AndDisableLCD
+ ld c, $5
+ call UpdateMusicCTimes
+ xor a
+ ldh [hLCDCPointer], a
+ call Func_f9e5f
+ lb de, $58, $58
+ ld a, $3
+ call YellowIntro_SpawnAnimatedObjectAndSavePointer
+ xor a
+ call Func_f9e9a
+ call YellowIntro_SetTimerFor128Frames
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene9:
+ call YellowIntro_CheckFrameTimerDecrement
+ ret nc
+ call YellowIntro_MaskCurrentAnimatedObjectStruct
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene10:
+ call YellowIntro_BlankPalsDelay2AndDisableLCD
+ ld c, $5
+ call UpdateMusicCTimes
+ xor a
+ ldh [hLCDCPointer], a
+ ld hl, vBGMap0
+ ld bc, $400
+ xor a
+ call Bank3E_FillMemory
+ ld hl, vBGMap0
+ ld bc, $100
+ ld a, $2
+ call Bank3E_FillMemory
+ ld hl, $9900
+ ld de, Unkn_f9b6e
+ lb bc, 6, 20
+ call .FillBGMapBox
+ ld hl, $988c
+ ld de, Unkn_f9be6
+ lb bc, 3, 4
+ call .FillBGMapBox
+ ld hl, $98e3
+ ld de, Unkn_f9bf2
+ lb bc, 2, 2
+ call .FillBGMapBox
+ lb de, $98, $58
+ ld a, $6
+ call YellowIntro_SpawnAnimatedObjectAndSavePointer
+ ld a, $1
+ call Func_f9e9a
+ call YellowIntro_SetTimerFor128Frames
+ call YellowIntro_NextScene
+ ret
+
+.FillBGMapBox:
+.fill_row
+ push bc
+ push hl
+.fill_col
+ ld a, [de]
+ inc de
+ ld [hli], a
+ dec c
+ jr nz, .fill_col
+ pop hl
+ ld bc, $20
+ add hl, bc
+ pop bc
+ dec b
+ jr nz, .fill_row
+ ret
+
+Unkn_f9b6e: INCBIN "gfx/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
+ ldh [hVBlankCopySource], a
+ ld a, h
+ ldh [hVBlankCopySource + 1], a
+ xor a
+ ldh [hVBlankCopyDest], a
+ ld a, $96
+ ldh [hVBlankCopyDest + 1], a
+ ld a, $4
+ ldh [hVBlankCopySize], a
+ ret
+
+.expired
+ call YellowIntro_MaskCurrentAnimatedObjectStruct
+ call YellowIntro_NextScene
+ ret
+
+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
+ ldh [hLCDCPointer], a
+ ld hl, vBGMap0
+ ld bc, $80
+ ld a, $1
+ call Bank3E_FillMemory
+ ld hl, $9880
+ ld bc, $140
+ xor a
+ call Bank3E_FillMemory
+ ld hl, $99c0
+ ld bc, $80
+ ld a, $1
+ call Bank3E_FillMemory
+
+ ; paste 8x12 graphic into vBGMap0 at (5, 6) starting at tile 4, skipping 4 vtiles at the end of each row
+ ld hl, $98c5
+ ld de, $20
+ ld a, $4
+ ld b, 8
+.row
+ ld c, 12
+ push hl
+.col
+ ld [hli], a
+ inc a
+ dec c
+ jr nz, .col
+ pop hl
+ add hl, de
+ add $4
+ dec b
+ jr nz, .row
+
+ ld hl, $98c4 ; (4, 6)
+ ld [hl], $3
+ ld hl, $98e4 ; (4, 7)
+ ld [hl], $74
+ ld hl, $99a5 ; (5, 5)
+ ld [hl], $0
+ lb de, $60, $58
+ ld a, $9
+ call YellowIntro_SpawnAnimatedObjectAndSavePointer
+ xor a
+ call Func_f9e9a
+ call YellowIntro_SetTimerFor128Frames
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene13:
+ call YellowIntro_CheckFrameTimerDecrement
+ ret nc
+ lb de, $68, $58
+ ld a, $a
+ call SpawnAnimatedObject
+ call YellowIntro_NextScene
+ ret
+
+YellowIntroScene14:
+ ld de, YellowIntroPalSequence_f9dd6
+ call YellowIntro_LoadDMGPalAndIncrementCounter
+ jr c, .expired
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ and $f0
+ ldh [rOBP1], a
+ call 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
+ hlcoord 0, 4
+ ld bc, CopyVideoDataAlternate
+ xor a
+ call Bank3E_FillMemory
+ hlcoord 0, 14
+ ld bc, $50
+ ld a, $1
+ call Bank3E_FillMemory
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ld a, $e4
+ ldh [rOBP0], a
+ ldh [rBGP], a
+ call 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
+ ldh a, [rOBP0]
+ xor $ff
+ ldh [rOBP0], a
+ ldh a, [rBGP]
+ xor $3
+ ldh [rBGP], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ ret
+
+.expired
+ xor a
+ ldh [hLCDCPointer], a
+ ld a, $e4
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call YellowIntro_NextScene
+YellowIntroScene16:
+ ld de, YellowIntroPalSequence_f9e0a
+ call YellowIntro_LoadDMGPalAndIncrementCounter
+ jr c, .expired
+ ldh [rOBP0], a
+ ldh [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
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ldh [rOBP1], a
+ call UpdateGBCPal_BGP
+ call UpdateGBCPal_OBP0
+ call UpdateGBCPal_OBP1
+ call DelayFrame
+ call DelayFrame
+ call DisableLCD
+ ret
+
+Func_f9e9a:
+ ld e, a
+ callfar YellowIntroPaletteAction
+ xor a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ld a, $90
+ ldh [hWY], a
+ ld a, $e3
+ ldh [rLCDC], a
+ ld a, $e4
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ld a, $e0
+ ldh [rOBP1], a
+ call 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
+ ldh [hVBlankCopySource], a
+ ld a, wLYOverridesBuffer / $100
+ ldh [hVBlankCopySource + 1], a
+ ld a, $10
+ ldh [hVBlankCopyDest], a
+ ld a, wLYOverrides / $100
+ ldh [hVBlankCopyDest + 1], a
+ ld a, $7
+ ldh [hVBlankCopySize], a
+ ret
+
+InitYellowIntroGFXAndMusic:
+ xor a
+ ldh [hAutoBGTransferEnabled], a
+ ldh [hSCX], a
+ ldh [hSCY], a
+ ldh [hAutoBGTransferDest], a
+ ld a, $98
+ ldh [hAutoBGTransferDest + 1], a
+ call YellowIntro_BlankTileMap
+ ld hl, wTileMap
+ ld bc, SCREEN_WIDTH * SCREEN_HEIGHT
+ ld a, $1
+ call Bank3E_FillMemory
+ hlcoord 0, 4
+ ld bc, CopyVideoDataAlternate
+ xor a
+ call Bank3E_FillMemory
+ ld a, $1
+ ldh [hAutoBGTransferEnabled], a
+ call DelayFrame
+ call DelayFrame
+ call DelayFrame
+ xor a
+ ldh [hAutoBGTransferEnabled], 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
+ ldh [rBGP], a
+ ldh [rOBP0], a
+ ldh [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