From f275790aec4a796ed969b099364abfdf25385967 Mon Sep 17 00:00:00 2001 From: Rangi Date: Thu, 2 Jul 2020 23:30:21 -0400 Subject: Add subdirectories to engine/ similar to pokecrystal --- audio.asm | 234 +- audio/alternate_tempo.asm | 50 + audio/low_health_alarm.asm | 75 + audio/notes.asm | 2 + audio/play_battle_music.asm | 34 + audio/poke_flute.asm | 18 + audio/pokedex_rating_sfx.asm | 36 + audio/wave_instruments.asm | 2 + data/hm_moves.asm | 7 + engine/HoF_room_pc.asm | 270 -- engine/add_mon.asm | 516 ---- engine/battle/bank_e_misc.asm | 122 - engine/battle/misc.asm | 122 + engine/battle/moveEffects/conversion_effect.asm | 35 - engine/battle/moveEffects/drain_hp_effect.asm | 104 - engine/battle/moveEffects/focus_energy_effect.asm | 22 - engine/battle/moveEffects/haze_effect.asm | 81 - engine/battle/moveEffects/heal_effect.asm | 120 - engine/battle/moveEffects/leech_seed_effect.asm | 40 - engine/battle/moveEffects/mist_effect.asm | 19 - engine/battle/moveEffects/one_hit_ko_effect.asm | 38 - engine/battle/moveEffects/paralyze_effect.asm | 47 - engine/battle/moveEffects/pay_day_effect.asm | 45 - engine/battle/moveEffects/recoil_effect.asm | 70 - .../moveEffects/reflect_light_screen_effect.asm | 45 - engine/battle/moveEffects/substitute_effect.asm | 77 - engine/battle/moveEffects/transform_effect.asm | 148 - engine/battle/move_effects/conversion.asm | 35 + engine/battle/move_effects/drain_hp.asm | 104 + engine/battle/move_effects/focus_energy.asm | 22 + engine/battle/move_effects/haze.asm | 81 + engine/battle/move_effects/heal.asm | 120 + engine/battle/move_effects/leech_seed.asm | 40 + engine/battle/move_effects/mist.asm | 19 + engine/battle/move_effects/one_hit_ko.asm | 38 + engine/battle/move_effects/paralyze.asm | 47 + engine/battle/move_effects/pay_day.asm | 45 + engine/battle/move_effects/recoil.asm | 70 + .../battle/move_effects/reflect_light_screen.asm | 45 + engine/battle/move_effects/substitute.asm | 77 + engine/battle/move_effects/transform.asm | 148 + engine/battle/trainer_ai.asm | 2 +- engine/bcd.asm | 214 -- engine/black_out.asm | 46 - engine/cable_club.asm | 977 ------- engine/clear_save.asm | 23 - engine/debug/debug_party.asm | 33 + engine/debug/test_battle.asm | 45 + engine/debug1.asm | 33 - engine/display_pokedex.asm | 19 - engine/display_text_id_init.asm | 78 - engine/events/black_out.asm | 46 + engine/events/card_key.asm | 112 + engine/events/cinnabar_lab.asm | 123 + engine/events/diploma.asm | 113 + engine/events/display_pokedex.asm | 19 + engine/events/elevator.asm | 48 + engine/events/evolve_trade.asm | 44 + engine/events/give_pokemon.asm | 82 + engine/events/heal_party.asm | 99 + engine/events/hidden_items.asm | 161 ++ engine/events/hidden_object_functions14.asm | 100 + engine/events/hidden_object_functions17.asm | 475 ++++ engine/events/hidden_object_functions18.asm | 198 ++ engine/events/hidden_object_functions3.asm | 117 + engine/events/hidden_object_functions7.asm | 467 +++ engine/events/in_game_trades.asm | 330 +++ engine/events/oaks_aide.asm | 71 + engine/events/pewter_guys.asm | 102 + engine/events/pick_up_item.asm | 54 + engine/events/poison.asm | 112 + engine/events/pokecenter.asm | 68 + engine/events/pokedex_rating.asm | 154 + engine/events/pokemart.asm | 272 ++ engine/events/prize_menu.asm | 306 ++ engine/events/saffron_guards.asm | 15 + engine/events/set_blackout_map.asm | 25 + engine/events/starter_dex.asm | 9 + engine/events/vending_machine.asm | 133 + engine/evolution.asm | 160 -- engine/evolve_trade.asm | 44 - engine/evos_moves.asm | 513 ---- engine/experience.asm | 149 - engine/game_corner_slots.asm | 54 - engine/game_corner_slots2.asm | 31 - engine/gamefreak.asm | 243 -- engine/get_bag_item_quantity.asm | 18 - engine/gfx/hp_bar.asm | 270 ++ engine/gfx/load_pokedex_tiles.asm | 11 + engine/gfx/mon_icons.asm | 295 ++ engine/gfx/oam_dma.asm | 26 + engine/gfx/palettes.asm | 641 +++++ engine/gfx/screen_effects.asm | 71 + engine/gfx/sprite_oam.asm | 189 ++ engine/give_pokemon.asm | 82 - engine/hall_of_fame.asm | 288 -- engine/heal_party.asm | 99 - engine/hidden_object_functions14.asm | 100 - engine/hidden_object_functions17.asm | 475 ---- engine/hidden_object_functions18.asm | 198 -- engine/hidden_object_functions3.asm | 117 - engine/hidden_object_functions7.asm | 467 --- engine/hp_bar.asm | 270 -- engine/in_game_trades.asm | 330 --- engine/init_player_data.asm | 55 - engine/intro.asm | 470 --- engine/items/get_bag_item_quantity.asm | 18 + engine/items/item_effects.asm | 2986 ++++++++++++++++++++ engine/items/items.asm | 2986 -------------------- engine/items/subtract_paid_money.asm | 17 + engine/items/town_map.asm | 618 ++++ engine/learn_move.asm | 226 -- engine/link/cable_club.asm | 977 +++++++ engine/link/cable_club_npc.asm | 151 + engine/link/print_waiting_text.asm | 20 + engine/load_mon_data.asm | 49 - engine/load_pokedex_tiles.asm | 11 - engine/math/bcd.asm | 214 ++ engine/math/multiply_divide.asm | 143 + engine/math/random.asm | 13 + engine/menu/bills_pc.asm | 554 ---- engine/menu/diploma.asm | 113 - engine/menu/draw_badges.asm | 120 - engine/menu/draw_start_menu.asm | 89 - engine/menu/league_pc.asm | 120 - engine/menu/main_menu.asm | 712 ----- engine/menu/naming_screen.asm | 494 ---- engine/menu/oaks_pc.asm | 28 - engine/menu/party_menu.asm | 325 --- engine/menu/pc.asm | 141 - engine/menu/players_pc.asm | 303 -- engine/menu/pokedex.asm | 665 ----- engine/menu/prize_menu.asm | 306 -- engine/menu/start_menu.asm | 85 - engine/menu/start_sub_menus.asm | 808 ------ engine/menu/status_screen.asm | 481 ---- engine/menu/swap_items.asm | 149 - engine/menu/text_box.asm | 767 ----- engine/menu/vending_machine.asm | 133 - engine/menus/display_text_id_init.asm | 78 + engine/menus/draw_badges.asm | 120 + engine/menus/draw_start_menu.asm | 89 + engine/menus/league_pc.asm | 120 + engine/menus/main_menu.asm | 712 +++++ engine/menus/naming_screen.asm | 494 ++++ engine/menus/oaks_pc.asm | 28 + engine/menus/party_menu.asm | 325 +++ engine/menus/pc.asm | 141 + engine/menus/players_pc.asm | 303 ++ engine/menus/pokedex.asm | 665 +++++ engine/menus/save.asm | 708 +++++ engine/menus/start_sub_menus.asm | 808 ++++++ engine/menus/swap_items.asm | 149 + engine/menus/text_box.asm | 767 +++++ engine/mon_party_sprites.asm | 295 -- engine/movie/clear_save.asm | 23 + engine/movie/credits.asm | 270 ++ engine/movie/evolution.asm | 160 ++ engine/movie/gamefreak.asm | 243 ++ engine/movie/hall_of_fame.asm | 288 ++ engine/movie/init_player_data.asm | 55 + engine/movie/intro.asm | 470 +++ engine/movie/oak_speech.asm | 233 ++ engine/movie/oak_speech2.asm | 219 ++ engine/movie/titlescreen.asm | 403 +++ engine/movie/titlescreen2.asm | 120 + engine/movie/trade.asm | 853 ++++++ engine/movie/trade2.asm | 48 + engine/multiply_divide.asm | 143 - engine/oak_speech.asm | 233 -- engine/oak_speech2.asm | 219 -- engine/oam_dma.asm | 26 - engine/overworld/auto_movement.asm | 292 ++ engine/overworld/cable_club_npc.asm | 151 - engine/overworld/card_key.asm | 112 - engine/overworld/cinnabar_lab.asm | 123 - engine/overworld/dust_smoke.asm | 93 + engine/overworld/hidden_items.asm | 161 -- engine/overworld/item.asm | 54 - engine/overworld/map_sprite_functions1.asm | 356 --- engine/overworld/npc_movement.asm | 292 -- engine/overworld/oaks_aide.asm | 71 - engine/overworld/oam.asm | 189 -- engine/overworld/pathfinding.asm | 201 ++ engine/overworld/pewter_guys.asm | 102 - engine/overworld/poison.asm | 112 - engine/overworld/pokecenter.asm | 68 - engine/overworld/pokemart.asm | 272 -- engine/overworld/saffron_guards.asm | 15 - engine/overworld/set_blackout_map.asm | 25 - engine/overworld/special_warps.asm | 149 + engine/overworld/sprite_collisions.asm | 356 +++ engine/overworld/ssanne.asm | 93 - engine/overworld/tileset_header.asm | 60 - engine/overworld/tilesets.asm | 60 + engine/overworld/trainer_sight.asm | 349 +++ engine/overworld/trainers.asm | 349 --- engine/overworld/turn_sprite.asm | 25 + engine/palettes.asm | 641 ----- engine/pathfinding.asm | 201 -- engine/pokedex_rating.asm | 154 - engine/pokemon/add_mon.asm | 516 ++++ engine/pokemon/bills_pc.asm | 548 ++++ engine/pokemon/evos_moves.asm | 513 ++++ engine/pokemon/experience.asm | 149 + engine/pokemon/learn_move.asm | 226 ++ engine/pokemon/load_mon_data.asm | 49 + engine/pokemon/remove_mon.asm | 95 + engine/pokemon/set_types.asm | 15 + engine/pokemon/status_ailments.asm | 46 + engine/pokemon/status_screen.asm | 481 ++++ engine/predefs12.asm | 71 - engine/predefs17.asm | 9 - engine/predefs17_2.asm | 15 - engine/predefs7.asm | 48 - engine/print_waiting_text.asm | 20 - engine/random.asm | 13 - engine/remove_pokemon.asm | 95 - engine/save.asm | 708 ----- engine/slot_machine.asm | 892 ------ engine/slots/game_corner_slots.asm | 54 + engine/slots/game_corner_slots2.asm | 31 + engine/slots/slot_machine.asm | 892 ++++++ engine/special_warps.asm | 149 - engine/status_ailments.asm | 46 - engine/subtract_paid_money.asm | 17 - engine/test_battle.asm | 45 - engine/titlescreen.asm | 403 --- engine/titlescreen2.asm | 120 - engine/town_map.asm | 618 ---- engine/trade.asm | 853 ------ engine/trade2.asm | 48 - engine/turn_sprite.asm | 25 - home.asm | 2 +- home/start_menu.asm | 85 + main.asm | 218 +- 236 files changed, 26064 insertions(+), 26068 deletions(-) create mode 100644 audio/alternate_tempo.asm create mode 100644 audio/low_health_alarm.asm create mode 100644 audio/play_battle_music.asm create mode 100644 audio/poke_flute.asm create mode 100644 audio/pokedex_rating_sfx.asm create mode 100644 data/hm_moves.asm delete mode 100755 engine/HoF_room_pc.asm delete mode 100644 engine/add_mon.asm delete mode 100755 engine/battle/bank_e_misc.asm create mode 100755 engine/battle/misc.asm delete mode 100644 engine/battle/moveEffects/conversion_effect.asm delete mode 100644 engine/battle/moveEffects/drain_hp_effect.asm delete mode 100644 engine/battle/moveEffects/focus_energy_effect.asm delete mode 100644 engine/battle/moveEffects/haze_effect.asm delete mode 100644 engine/battle/moveEffects/heal_effect.asm delete mode 100644 engine/battle/moveEffects/leech_seed_effect.asm delete mode 100644 engine/battle/moveEffects/mist_effect.asm delete mode 100644 engine/battle/moveEffects/one_hit_ko_effect.asm delete mode 100644 engine/battle/moveEffects/paralyze_effect.asm delete mode 100644 engine/battle/moveEffects/pay_day_effect.asm delete mode 100644 engine/battle/moveEffects/recoil_effect.asm delete mode 100644 engine/battle/moveEffects/reflect_light_screen_effect.asm delete mode 100644 engine/battle/moveEffects/substitute_effect.asm delete mode 100644 engine/battle/moveEffects/transform_effect.asm create mode 100644 engine/battle/move_effects/conversion.asm create mode 100644 engine/battle/move_effects/drain_hp.asm create mode 100644 engine/battle/move_effects/focus_energy.asm create mode 100644 engine/battle/move_effects/haze.asm create mode 100644 engine/battle/move_effects/heal.asm create mode 100644 engine/battle/move_effects/leech_seed.asm create mode 100644 engine/battle/move_effects/mist.asm create mode 100644 engine/battle/move_effects/one_hit_ko.asm create mode 100644 engine/battle/move_effects/paralyze.asm create mode 100644 engine/battle/move_effects/pay_day.asm create mode 100644 engine/battle/move_effects/recoil.asm create mode 100644 engine/battle/move_effects/reflect_light_screen.asm create mode 100644 engine/battle/move_effects/substitute.asm create mode 100644 engine/battle/move_effects/transform.asm delete mode 100644 engine/bcd.asm delete mode 100644 engine/black_out.asm delete mode 100755 engine/cable_club.asm delete mode 100755 engine/clear_save.asm create mode 100644 engine/debug/debug_party.asm create mode 100644 engine/debug/test_battle.asm delete mode 100644 engine/debug1.asm delete mode 100644 engine/display_pokedex.asm delete mode 100644 engine/display_text_id_init.asm create mode 100644 engine/events/black_out.asm create mode 100755 engine/events/card_key.asm create mode 100755 engine/events/cinnabar_lab.asm create mode 100755 engine/events/diploma.asm create mode 100644 engine/events/display_pokedex.asm create mode 100755 engine/events/elevator.asm create mode 100755 engine/events/evolve_trade.asm create mode 100755 engine/events/give_pokemon.asm create mode 100644 engine/events/heal_party.asm create mode 100755 engine/events/hidden_items.asm create mode 100755 engine/events/hidden_object_functions14.asm create mode 100755 engine/events/hidden_object_functions17.asm create mode 100755 engine/events/hidden_object_functions18.asm create mode 100755 engine/events/hidden_object_functions3.asm create mode 100755 engine/events/hidden_object_functions7.asm create mode 100755 engine/events/in_game_trades.asm create mode 100755 engine/events/oaks_aide.asm create mode 100755 engine/events/pewter_guys.asm create mode 100644 engine/events/pick_up_item.asm create mode 100644 engine/events/poison.asm create mode 100755 engine/events/pokecenter.asm create mode 100755 engine/events/pokedex_rating.asm create mode 100755 engine/events/pokemart.asm create mode 100755 engine/events/prize_menu.asm create mode 100755 engine/events/saffron_guards.asm create mode 100644 engine/events/set_blackout_map.asm create mode 100755 engine/events/starter_dex.asm create mode 100755 engine/events/vending_machine.asm delete mode 100755 engine/evolution.asm delete mode 100755 engine/evolve_trade.asm delete mode 100755 engine/evos_moves.asm delete mode 100755 engine/experience.asm delete mode 100755 engine/game_corner_slots.asm delete mode 100755 engine/game_corner_slots2.asm delete mode 100755 engine/gamefreak.asm delete mode 100644 engine/get_bag_item_quantity.asm create mode 100755 engine/gfx/hp_bar.asm create mode 100755 engine/gfx/load_pokedex_tiles.asm create mode 100755 engine/gfx/mon_icons.asm create mode 100644 engine/gfx/oam_dma.asm create mode 100755 engine/gfx/palettes.asm create mode 100755 engine/gfx/screen_effects.asm create mode 100644 engine/gfx/sprite_oam.asm delete mode 100755 engine/give_pokemon.asm delete mode 100755 engine/hall_of_fame.asm delete mode 100644 engine/heal_party.asm delete mode 100755 engine/hidden_object_functions14.asm delete mode 100755 engine/hidden_object_functions17.asm delete mode 100755 engine/hidden_object_functions18.asm delete mode 100755 engine/hidden_object_functions3.asm delete mode 100755 engine/hidden_object_functions7.asm delete mode 100755 engine/hp_bar.asm delete mode 100755 engine/in_game_trades.asm delete mode 100644 engine/init_player_data.asm delete mode 100755 engine/intro.asm create mode 100644 engine/items/get_bag_item_quantity.asm create mode 100755 engine/items/item_effects.asm delete mode 100755 engine/items/items.asm create mode 100644 engine/items/subtract_paid_money.asm create mode 100755 engine/items/town_map.asm delete mode 100755 engine/learn_move.asm create mode 100755 engine/link/cable_club.asm create mode 100755 engine/link/cable_club_npc.asm create mode 100644 engine/link/print_waiting_text.asm delete mode 100644 engine/load_mon_data.asm delete mode 100755 engine/load_pokedex_tiles.asm create mode 100644 engine/math/bcd.asm create mode 100755 engine/math/multiply_divide.asm create mode 100755 engine/math/random.asm delete mode 100644 engine/menu/bills_pc.asm delete mode 100755 engine/menu/diploma.asm delete mode 100644 engine/menu/draw_badges.asm delete mode 100644 engine/menu/draw_start_menu.asm delete mode 100755 engine/menu/league_pc.asm delete mode 100755 engine/menu/main_menu.asm delete mode 100755 engine/menu/naming_screen.asm delete mode 100755 engine/menu/oaks_pc.asm delete mode 100755 engine/menu/party_menu.asm delete mode 100755 engine/menu/pc.asm delete mode 100755 engine/menu/players_pc.asm delete mode 100755 engine/menu/pokedex.asm delete mode 100755 engine/menu/prize_menu.asm delete mode 100755 engine/menu/start_menu.asm delete mode 100755 engine/menu/start_sub_menus.asm delete mode 100755 engine/menu/status_screen.asm delete mode 100644 engine/menu/swap_items.asm delete mode 100644 engine/menu/text_box.asm delete mode 100755 engine/menu/vending_machine.asm create mode 100644 engine/menus/display_text_id_init.asm create mode 100644 engine/menus/draw_badges.asm create mode 100644 engine/menus/draw_start_menu.asm create mode 100755 engine/menus/league_pc.asm create mode 100755 engine/menus/main_menu.asm create mode 100755 engine/menus/naming_screen.asm create mode 100755 engine/menus/oaks_pc.asm create mode 100755 engine/menus/party_menu.asm create mode 100755 engine/menus/pc.asm create mode 100755 engine/menus/players_pc.asm create mode 100755 engine/menus/pokedex.asm create mode 100755 engine/menus/save.asm create mode 100755 engine/menus/start_sub_menus.asm create mode 100644 engine/menus/swap_items.asm create mode 100644 engine/menus/text_box.asm delete mode 100755 engine/mon_party_sprites.asm create mode 100755 engine/movie/clear_save.asm create mode 100755 engine/movie/credits.asm create mode 100755 engine/movie/evolution.asm create mode 100755 engine/movie/gamefreak.asm create mode 100755 engine/movie/hall_of_fame.asm create mode 100644 engine/movie/init_player_data.asm create mode 100755 engine/movie/intro.asm create mode 100755 engine/movie/oak_speech.asm create mode 100755 engine/movie/oak_speech2.asm create mode 100755 engine/movie/titlescreen.asm create mode 100755 engine/movie/titlescreen2.asm create mode 100755 engine/movie/trade.asm create mode 100755 engine/movie/trade2.asm delete mode 100755 engine/multiply_divide.asm delete mode 100755 engine/oak_speech.asm delete mode 100755 engine/oak_speech2.asm delete mode 100644 engine/oam_dma.asm create mode 100755 engine/overworld/auto_movement.asm delete mode 100755 engine/overworld/cable_club_npc.asm delete mode 100755 engine/overworld/card_key.asm delete mode 100755 engine/overworld/cinnabar_lab.asm create mode 100755 engine/overworld/dust_smoke.asm delete mode 100755 engine/overworld/hidden_items.asm delete mode 100644 engine/overworld/item.asm delete mode 100644 engine/overworld/map_sprite_functions1.asm delete mode 100755 engine/overworld/npc_movement.asm delete mode 100755 engine/overworld/oaks_aide.asm delete mode 100644 engine/overworld/oam.asm create mode 100644 engine/overworld/pathfinding.asm delete mode 100755 engine/overworld/pewter_guys.asm delete mode 100644 engine/overworld/poison.asm delete mode 100755 engine/overworld/pokecenter.asm delete mode 100755 engine/overworld/pokemart.asm delete mode 100755 engine/overworld/saffron_guards.asm delete mode 100644 engine/overworld/set_blackout_map.asm create mode 100644 engine/overworld/special_warps.asm create mode 100644 engine/overworld/sprite_collisions.asm delete mode 100755 engine/overworld/ssanne.asm delete mode 100644 engine/overworld/tileset_header.asm create mode 100644 engine/overworld/tilesets.asm create mode 100755 engine/overworld/trainer_sight.asm delete mode 100755 engine/overworld/trainers.asm create mode 100755 engine/overworld/turn_sprite.asm delete mode 100755 engine/palettes.asm delete mode 100644 engine/pathfinding.asm delete mode 100755 engine/pokedex_rating.asm create mode 100644 engine/pokemon/add_mon.asm create mode 100644 engine/pokemon/bills_pc.asm create mode 100755 engine/pokemon/evos_moves.asm create mode 100755 engine/pokemon/experience.asm create mode 100755 engine/pokemon/learn_move.asm create mode 100644 engine/pokemon/load_mon_data.asm create mode 100644 engine/pokemon/remove_mon.asm create mode 100755 engine/pokemon/set_types.asm create mode 100755 engine/pokemon/status_ailments.asm create mode 100755 engine/pokemon/status_screen.asm delete mode 100755 engine/predefs12.asm delete mode 100755 engine/predefs17.asm delete mode 100755 engine/predefs17_2.asm delete mode 100755 engine/predefs7.asm delete mode 100644 engine/print_waiting_text.asm delete mode 100755 engine/random.asm delete mode 100644 engine/remove_pokemon.asm delete mode 100755 engine/save.asm delete mode 100755 engine/slot_machine.asm create mode 100755 engine/slots/game_corner_slots.asm create mode 100755 engine/slots/game_corner_slots2.asm create mode 100755 engine/slots/slot_machine.asm delete mode 100644 engine/special_warps.asm delete mode 100755 engine/status_ailments.asm delete mode 100644 engine/subtract_paid_money.asm delete mode 100644 engine/test_battle.asm delete mode 100755 engine/titlescreen.asm delete mode 100755 engine/titlescreen2.asm delete mode 100755 engine/town_map.asm delete mode 100755 engine/trade.asm delete mode 100755 engine/trade2.asm delete mode 100755 engine/turn_sprite.asm create mode 100755 home/start_menu.asm diff --git a/audio.asm b/audio.asm index 9675c98a..effcb6f7 100644 --- a/audio.asm +++ b/audio.asm @@ -352,248 +352,27 @@ INCLUDE "audio/sfx/cry21_3.asm" INCLUDE "audio/sfx/cry22_3.asm" - SECTION "Audio Engine 1", ROMX -PlayBattleMusic:: - xor a - ld [wAudioFadeOutControl], a - ld [wLowHealthAlarm], a - dec a - ld [wNewSoundID], a - call PlaySound ; stop music - call DelayFrame - ld c, BANK(Music_GymLeaderBattle) - ld a, [wGymLeaderNo] - and a - jr z, .notGymLeaderBattle - ld a, MUSIC_GYM_LEADER_BATTLE - jr .playSong -.notGymLeaderBattle - ld a, [wCurOpponent] - cp OPP_ID_OFFSET - jr c, .wildBattle - cp OPP_SONY3 - jr z, .finalBattle - cp OPP_LANCE - jr nz, .normalTrainerBattle - ld a, MUSIC_GYM_LEADER_BATTLE ; lance also plays gym leader theme - jr .playSong -.normalTrainerBattle - ld a, MUSIC_TRAINER_BATTLE - jr .playSong -.finalBattle - ld a, MUSIC_FINAL_BATTLE - jr .playSong -.wildBattle - ld a, MUSIC_WILD_BATTLE -.playSong - jp PlayMusic - - +INCLUDE "audio/play_battle_music.asm" INCLUDE "audio/engine_1.asm" - - -; an alternate start for MeetRival which has a different first measure -Music_RivalAlternateStart:: - ld c, BANK(Music_MeetRival) - ld a, MUSIC_MEET_RIVAL - call PlayMusic - ld hl, wChannelCommandPointers - ld de, Music_MeetRival_branch_b1a2 - call Audio1_OverwriteChannelPointer - ld de, Music_MeetRival_branch_b21d - call Audio1_OverwriteChannelPointer - ld de, Music_MeetRival_branch_b2b5 - -Audio1_OverwriteChannelPointer: - ld a, e - ld [hli], a - ld a, d - ld [hli], a - ret - -; an alternate tempo for MeetRival which is slightly slower -Music_RivalAlternateTempo:: - ld c, BANK(Music_MeetRival) - ld a, MUSIC_MEET_RIVAL - call PlayMusic - ld hl, wChannelCommandPointers - ld de, Music_MeetRival_branch_b119 - jp Audio1_OverwriteChannelPointer - -; applies both the alternate start and alternate tempo -Music_RivalAlternateStartAndTempo:: - call Music_RivalAlternateStart - ld hl, wChannelCommandPointers - ld de, Music_MeetRival_branch_b19b - jp Audio1_OverwriteChannelPointer - -; an alternate tempo for Cities1 which is used for the Hall of Fame room -Music_Cities1AlternateTempo:: - ld a, 10 - ld [wAudioFadeOutCounterReloadValue], a - ld [wAudioFadeOutCounter], a - ld a, $ff ; stop playing music after the fade-out is finished - ld [wAudioFadeOutControl], a - ld c, 100 - call DelayFrames ; wait for the fade-out to finish - ld c, BANK(Music_Cities1) - ld a, MUSIC_CITIES1 - call PlayMusic - ld hl, wChannelCommandPointers - ld de, Music_Cities1_branch_aa6f - jp Audio1_OverwriteChannelPointer +INCLUDE "audio/alternate_tempo.asm" SECTION "Audio Engine 2", ROMX -Music_DoLowHealthAlarm:: - ld a, [wLowHealthAlarm] - cp $ff - jr z, .disableAlarm - - bit 7, a ;alarm enabled? - ret z ;nope - - and $7f ;low 7 bits are the timer. - jr nz, .asm_21383 ;if timer > 0, play low tone. - - call .playToneHi - ld a, 30 ;keep this tone for 30 frames. - jr .asm_21395 ;reset the timer. - -.asm_21383 - cp 20 - jr nz, .asm_2138a ;if timer == 20, - call .playToneLo ;actually set the sound registers. - -.asm_2138a - ld a, $86 - ld [wChannelSoundIDs + Ch5], a ;disable sound channel? - ld a, [wLowHealthAlarm] - and $7f ;decrement alarm timer. - dec a - -.asm_21395 - ; reset the timer and enable flag. - set 7, a - ld [wLowHealthAlarm], a - ret - -.disableAlarm - xor a - ld [wLowHealthAlarm], a ;disable alarm - ld [wChannelSoundIDs + Ch5], a ;re-enable sound channel? - ld de, .toneDataSilence - jr .playTone - -;update the sound registers to change the frequency. -;the tone set here stays until we change it. -.playToneHi - ld de, .toneDataHi - jr .playTone - -.playToneLo - ld de, .toneDataLo - -;update sound channel 1 to play the alarm, overriding all other sounds. -.playTone - ld hl, rNR10 ;channel 1 sound register - ld c, $5 - xor a - -.copyLoop - ld [hli], a - ld a, [de] - inc de - dec c - jr nz, .copyLoop - ret - -;bytes to write to sound channel 1 registers for health alarm. -;starting at FF11 (FF10 is always zeroed), so these bytes are: -;length, envelope, freq lo, freq hi -.toneDataHi - db $A0,$E2,$50,$87 - -.toneDataLo - db $B0,$E2,$EE,$86 - -;written to stop the alarm -.toneDataSilence - db $00,$00,$00,$80 - - -INCLUDE "engine/menu/bills_pc.asm" - +INCLUDE "audio/low_health_alarm.asm" +INCLUDE "engine/pokemon/bills_pc.asm" INCLUDE "audio/engine_2.asm" - - -Music_PokeFluteInBattle:: - ; begin playing the "caught mon" sound effect - ld a, SFX_CAUGHT_MON - call PlaySoundWaitForCurrent - ; then immediately overwrite the channel pointers - ld hl, wChannelCommandPointers + Ch5 * 2 - ld de, SFX_Pokeflute_Ch5 - call Audio2_OverwriteChannelPointer - ld de, SFX_Pokeflute_Ch6 - call Audio2_OverwriteChannelPointer - ld de, SFX_Pokeflute_Ch7 - -Audio2_OverwriteChannelPointer: - ld a, e - ld [hli], a - ld a, d - ld [hli], a - ret +INCLUDE "audio/poke_flute.asm" SECTION "Audio Engine 3", ROMX -PlayPokedexRatingSfx:: - ld a, [$ffdc] - ld c, $0 - ld hl, OwnedMonValues -.getSfxPointer - cp [hl] - jr c, .gotSfxPointer - inc c - inc hl - jr .getSfxPointer -.gotSfxPointer - push bc - ld a, $ff - ld [wNewSoundID], a - call PlaySoundWaitForCurrent - pop bc - ld b, $0 - ld hl, PokedexRatingSfxPointers - add hl, bc - add hl, bc - ld a, [hli] - ld c, [hl] - call PlayMusic - jp PlayDefaultMusic - -PokedexRatingSfxPointers: - db SFX_DENIED, BANK(SFX_Denied_3) - db SFX_POKEDEX_RATING, BANK(SFX_Pokedex_Rating_1) - db SFX_GET_ITEM_1, BANK(SFX_Get_Item1_1) - db SFX_CAUGHT_MON, BANK(SFX_Caught_Mon) - db SFX_LEVEL_UP, BANK(SFX_Level_Up) - db SFX_GET_KEY_ITEM, BANK(SFX_Get_Key_Item_1) - db SFX_GET_ITEM_2, BANK(SFX_Get_Item2_1) - -OwnedMonValues: - db 10, 40, 60, 90, 120, 150, $ff - - +INCLUDE "audio/pokedex_rating_sfx.asm" INCLUDE "audio/engine_3.asm" - SECTION "Music 1", ROMX INCLUDE "audio/music/pkmnhealed.asm" @@ -663,4 +442,3 @@ INCLUDE "audio/music/surfing.asm" INCLUDE "audio/music/jigglypuffsong.asm" INCLUDE "audio/music/halloffame.asm" INCLUDE "audio/music/credits.asm" - diff --git a/audio/alternate_tempo.asm b/audio/alternate_tempo.asm new file mode 100644 index 00000000..6c2cdc49 --- /dev/null +++ b/audio/alternate_tempo.asm @@ -0,0 +1,50 @@ +; an alternate start for MeetRival which has a different first measure +Music_RivalAlternateStart:: + ld c, BANK(Music_MeetRival) + ld a, MUSIC_MEET_RIVAL + call PlayMusic + ld hl, wChannelCommandPointers + ld de, Music_MeetRival_branch_b1a2 + call Audio1_OverwriteChannelPointer + ld de, Music_MeetRival_branch_b21d + call Audio1_OverwriteChannelPointer + ld de, Music_MeetRival_branch_b2b5 + +Audio1_OverwriteChannelPointer: + ld a, e + ld [hli], a + ld a, d + ld [hli], a + ret + +; an alternate tempo for MeetRival which is slightly slower +Music_RivalAlternateTempo:: + ld c, BANK(Music_MeetRival) + ld a, MUSIC_MEET_RIVAL + call PlayMusic + ld hl, wChannelCommandPointers + ld de, Music_MeetRival_branch_b119 + jp Audio1_OverwriteChannelPointer + +; applies both the alternate start and alternate tempo +Music_RivalAlternateStartAndTempo:: + call Music_RivalAlternateStart + ld hl, wChannelCommandPointers + ld de, Music_MeetRival_branch_b19b + jp Audio1_OverwriteChannelPointer + +; an alternate tempo for Cities1 which is used for the Hall of Fame room +Music_Cities1AlternateTempo:: + ld a, 10 + ld [wAudioFadeOutCounterReloadValue], a + ld [wAudioFadeOutCounter], a + ld a, $ff ; stop playing music after the fade-out is finished + ld [wAudioFadeOutControl], a + ld c, 100 + call DelayFrames ; wait for the fade-out to finish + ld c, BANK(Music_Cities1) + ld a, MUSIC_CITIES1 + call PlayMusic + ld hl, wChannelCommandPointers + ld de, Music_Cities1_branch_aa6f + jp Audio1_OverwriteChannelPointer diff --git a/audio/low_health_alarm.asm b/audio/low_health_alarm.asm new file mode 100644 index 00000000..514db55f --- /dev/null +++ b/audio/low_health_alarm.asm @@ -0,0 +1,75 @@ +Music_DoLowHealthAlarm:: + ld a, [wLowHealthAlarm] + cp $ff + jr z, .disableAlarm + + bit 7, a ;alarm enabled? + ret z ;nope + + and $7f ;low 7 bits are the timer. + jr nz, .asm_21383 ;if timer > 0, play low tone. + + call .playToneHi + ld a, 30 ;keep this tone for 30 frames. + jr .asm_21395 ;reset the timer. + +.asm_21383 + cp 20 + jr nz, .asm_2138a ;if timer == 20, + call .playToneLo ;actually set the sound registers. + +.asm_2138a + ld a, $86 + ld [wChannelSoundIDs + Ch5], a ;disable sound channel? + ld a, [wLowHealthAlarm] + and $7f ;decrement alarm timer. + dec a + +.asm_21395 + ; reset the timer and enable flag. + set 7, a + ld [wLowHealthAlarm], a + ret + +.disableAlarm + xor a + ld [wLowHealthAlarm], a ;disable alarm + ld [wChannelSoundIDs + Ch5], a ;re-enable sound channel? + ld de, .toneDataSilence + jr .playTone + +;update the sound registers to change the frequency. +;the tone set here stays until we change it. +.playToneHi + ld de, .toneDataHi + jr .playTone + +.playToneLo + ld de, .toneDataLo + +;update sound channel 1 to play the alarm, overriding all other sounds. +.playTone + ld hl, rNR10 ;channel 1 sound register + ld c, $5 + xor a + +.copyLoop + ld [hli], a + ld a, [de] + inc de + dec c + jr nz, .copyLoop + ret + +;bytes to write to sound channel 1 registers for health alarm. +;starting at FF11 (FF10 is always zeroed), so these bytes are: +;length, envelope, freq lo, freq hi +.toneDataHi + db $A0,$E2,$50,$87 + +.toneDataLo + db $B0,$E2,$EE,$86 + +;written to stop the alarm +.toneDataSilence + db $00,$00,$00,$80 diff --git a/audio/notes.asm b/audio/notes.asm index 025eb6a8..75e1a0b7 100644 --- a/audio/notes.asm +++ b/audio/notes.asm @@ -1,3 +1,5 @@ +; This file is INCLUDEd three times, once in each audio engine. + dw $F82C ; C_ dw $F89D ; C# dw $F907 ; D_ diff --git a/audio/play_battle_music.asm b/audio/play_battle_music.asm new file mode 100644 index 00000000..35dd19ad --- /dev/null +++ b/audio/play_battle_music.asm @@ -0,0 +1,34 @@ +PlayBattleMusic:: + xor a + ld [wAudioFadeOutControl], a + ld [wLowHealthAlarm], a + dec a + ld [wNewSoundID], a + call PlaySound ; stop music + call DelayFrame + ld c, BANK(Music_GymLeaderBattle) + ld a, [wGymLeaderNo] + and a + jr z, .notGymLeaderBattle + ld a, MUSIC_GYM_LEADER_BATTLE + jr .playSong +.notGymLeaderBattle + ld a, [wCurOpponent] + cp OPP_ID_OFFSET + jr c, .wildBattle + cp OPP_SONY3 + jr z, .finalBattle + cp OPP_LANCE + jr nz, .normalTrainerBattle + ld a, MUSIC_GYM_LEADER_BATTLE ; lance also plays gym leader theme + jr .playSong +.normalTrainerBattle + ld a, MUSIC_TRAINER_BATTLE + jr .playSong +.finalBattle + ld a, MUSIC_FINAL_BATTLE + jr .playSong +.wildBattle + ld a, MUSIC_WILD_BATTLE +.playSong + jp PlayMusic diff --git a/audio/poke_flute.asm b/audio/poke_flute.asm new file mode 100644 index 00000000..f55a2a1f --- /dev/null +++ b/audio/poke_flute.asm @@ -0,0 +1,18 @@ +Music_PokeFluteInBattle:: + ; begin playing the "caught mon" sound effect + ld a, SFX_CAUGHT_MON + call PlaySoundWaitForCurrent + ; then immediately overwrite the channel pointers + ld hl, wChannelCommandPointers + Ch5 * 2 + ld de, SFX_Pokeflute_Ch5 + call Audio2_OverwriteChannelPointer + ld de, SFX_Pokeflute_Ch6 + call Audio2_OverwriteChannelPointer + ld de, SFX_Pokeflute_Ch7 + +Audio2_OverwriteChannelPointer: + ld a, e + ld [hli], a + ld a, d + ld [hli], a + ret diff --git a/audio/pokedex_rating_sfx.asm b/audio/pokedex_rating_sfx.asm new file mode 100644 index 00000000..a218d5e6 --- /dev/null +++ b/audio/pokedex_rating_sfx.asm @@ -0,0 +1,36 @@ +PlayPokedexRatingSfx:: + ld a, [$ffdc] + ld c, $0 + ld hl, OwnedMonValues +.getSfxPointer + cp [hl] + jr c, .gotSfxPointer + inc c + inc hl + jr .getSfxPointer +.gotSfxPointer + push bc + ld a, $ff + ld [wNewSoundID], a + call PlaySoundWaitForCurrent + pop bc + ld b, $0 + ld hl, PokedexRatingSfxPointers + add hl, bc + add hl, bc + ld a, [hli] + ld c, [hl] + call PlayMusic + jp PlayDefaultMusic + +PokedexRatingSfxPointers: + db SFX_DENIED, BANK(SFX_Denied_3) + db SFX_POKEDEX_RATING, BANK(SFX_Pokedex_Rating_1) + db SFX_GET_ITEM_1, BANK(SFX_Get_Item1_1) + db SFX_CAUGHT_MON, BANK(SFX_Caught_Mon) + db SFX_LEVEL_UP, BANK(SFX_Level_Up) + db SFX_GET_KEY_ITEM, BANK(SFX_Get_Key_Item_1) + db SFX_GET_ITEM_2, BANK(SFX_Get_Item2_1) + +OwnedMonValues: + db 10, 40, 60, 90, 120, 150, $ff diff --git a/audio/wave_instruments.asm b/audio/wave_instruments.asm index fede06af..c915f18a 100644 --- a/audio/wave_instruments.asm +++ b/audio/wave_instruments.asm @@ -1,3 +1,5 @@ +; This file is INCLUDEd three times, once for each audio engine. + dw .wave0 dw .wave1 dw .wave2 diff --git a/data/hm_moves.asm b/data/hm_moves.asm new file mode 100644 index 00000000..d72eddfe --- /dev/null +++ b/data/hm_moves.asm @@ -0,0 +1,7 @@ +HMMoveArray: + db CUT + db FLY + db SURF + db STRENGTH + db FLASH + db -1 diff --git a/engine/HoF_room_pc.asm b/engine/HoF_room_pc.asm deleted file mode 100755 index f820aae3..00000000 --- a/engine/HoF_room_pc.asm +++ /dev/null @@ -1,270 +0,0 @@ -HallOfFamePC: - callba AnimateHallOfFame - call ClearScreen - ld c, 100 - call DelayFrames - call DisableLCD - ld hl, vFont - ld bc, $800 / 2 - call ZeroMemory - ld hl, vChars2 + $600 - ld bc, $200 / 2 - call ZeroMemory - ld hl, vChars2 + $7e0 - ld bc, $10 - ld a, $ff - call FillMemory - coord hl, 0, 0 - call FillFourRowsWithBlack - coord hl, 0, 14 - call FillFourRowsWithBlack - ld a, %11000000 - ld [rBGP], a - call EnableLCD - ld a, $ff - call PlaySoundWaitForCurrent - ld c, BANK(Music_Credits) - ld a, MUSIC_CREDITS - call PlayMusic - ld c, 128 - call DelayFrames - xor a - ld [wUnusedCD3D], a ; not read - ld [wNumCreditsMonsDisplayed], a - jp Credits - -FadeInCreditsText: - ld hl, HoFGBPalettes - ld b, 4 -.loop - ld a, [hli] - ld [rBGP], a - ld c, 5 - call DelayFrames - dec b - jr nz, .loop - ret - -DisplayCreditsMon: - xor a - ld [H_AUTOBGTRANSFERENABLED], a - call SaveScreenTilesToBuffer1 - call FillMiddleOfScreenWithWhite - - ; display the next monster from CreditsMons - ld hl, wNumCreditsMonsDisplayed - ld c, [hl] ; how many monsters have we displayed so far? - inc [hl] - ld b, 0 - ld hl, CreditsMons - add hl, bc ; go that far in the list of monsters and get the next one - ld a, [hl] - ld [wcf91], a - ld [wd0b5], a - coord hl, 8, 6 - call GetMonHeader - call LoadFrontSpriteByMonIndex - ld hl, vBGMap0 + $c - call CreditsCopyTileMapToVRAM - xor a - ld [H_AUTOBGTRANSFERENABLED], a - call LoadScreenTilesFromBuffer1 - ld hl, vBGMap0 - call CreditsCopyTileMapToVRAM - ld a, $A7 - ld [rWX], a - ld hl, vBGMap1 - call CreditsCopyTileMapToVRAM - call FillMiddleOfScreenWithWhite - ld a, %11111100 ; make the mon a black silhouette - ld [rBGP], a - -; scroll the mon left by one tile 7 times - ld bc, 7 -.scrollLoop1 - call 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 ScrollCreditsMonLeft - ld a, [rWX] - sub 8 - ld [rWX], a - dec c - jr nz, .scrollLoop2 - - xor a - ld [hWY], a - ld a, %11000000 - ld [rBGP], a - ret - -INCLUDE "data/credit_mons.asm" - -ScrollCreditsMonLeft: - ld h, b - ld l, $20 - call ScrollCreditsMonLeft_SetSCX - ld h, $0 - ld l, $70 - call ScrollCreditsMonLeft_SetSCX - ld a, b - add $8 - ld b, a - ret - -ScrollCreditsMonLeft_SetSCX: - ld a, [rLY] - cp l - jr nz, ScrollCreditsMonLeft_SetSCX - ld a, h - ld [rSCX], a -.loop - ld a, [rLY] - cp h - jr z, .loop - ret - -HoFGBPalettes: - db %11000000 - db %11010000 - db %11100000 - db %11110000 - -CreditsCopyTileMapToVRAM: - ld a, l - ld [H_AUTOBGTRANSFERDEST], a - ld a, h - ld [H_AUTOBGTRANSFERDEST + 1], a - ld a, 1 - ld [H_AUTOBGTRANSFERENABLED], a - jp Delay3 - -ZeroMemory: -; zero bc bytes at hl - ld [hl], 0 - inc hl - inc hl - dec bc - ld a, b - or c - jr nz, ZeroMemory - ret - -FillFourRowsWithBlack: - ld bc, SCREEN_WIDTH * 4 - ld a, $7e - jp FillMemory - -FillMiddleOfScreenWithWhite: - coord hl, 0, 4 - ld bc, SCREEN_WIDTH * 10 - ld a, " " - jp FillMemory - -Credits: - ld de, CreditsOrder - push de -.nextCreditsScreen - pop de - coord hl, 9, 6 - push hl - call FillMiddleOfScreenWithWhite - pop hl -.nextCreditsCommand - ld a, [de] - inc de - push de - cp $ff - jr z, .fadeInTextAndShowMon - cp $fe - jr z, .showTextAndShowMon - cp $fd - jr z, .fadeInText - cp $fc - jr z, .showText - cp $fb - jr z, .showCopyrightText - cp $fa - jr z, .showTheEnd - push hl - push hl - ld hl, CreditsTextPointers - add a - ld c, a - ld b, 0 - add hl, bc - ld e, [hl] - inc hl - ld d, [hl] - ld a, [de] - inc de - ld c, a - ld b, $ff - pop hl - add hl, bc - call PlaceString - pop hl - ld bc, SCREEN_WIDTH * 2 - add hl, bc - pop de - jr .nextCreditsCommand -.fadeInTextAndShowMon - call FadeInCreditsText - ld c, 90 - jr .next1 -.showTextAndShowMon - ld c, 110 -.next1 - call DelayFrames - call DisplayCreditsMon - jr .nextCreditsScreen -.fadeInText - call FadeInCreditsText - ld c, 120 - jr .next2 -.showText - ld c, 140 -.next2 - call DelayFrames - jr .nextCreditsScreen -.showCopyrightText - push de - callba LoadCopyrightTiles - pop de - pop de - jr .nextCreditsCommand -.showTheEnd - ld c, 16 - call DelayFrames - call FillMiddleOfScreenWithWhite - pop de - ld de, TheEndGfx - ld hl, vChars2 + $600 - lb bc, BANK(TheEndGfx), (TheEndGfxEnd - TheEndGfx) / $10 - call CopyVideoData - coord hl, 4, 8 - ld de, TheEndTextString - call PlaceString - coord hl, 4, 9 - inc de - call PlaceString - jp FadeInCreditsText - -TheEndTextString: -; "T H E E N D" - db $60," ",$62," ",$64," ",$64," ",$66," ",$68,"@" - db $61," ",$63," ",$65," ",$65," ",$67," ",$69,"@" - -INCLUDE "data/credits_order.asm" - -INCLUDE "text/credits_text.asm" - -TheEndGfx: - INCBIN "gfx/intro_credits/the_end.2bpp" -TheEndGfxEnd: diff --git a/engine/add_mon.asm b/engine/add_mon.asm deleted file mode 100644 index 7627136b..00000000 --- a/engine/add_mon.asm +++ /dev/null @@ -1,516 +0,0 @@ -_AddPartyMon:: -; Adds a new mon to the player's or enemy's party. -; [wMonDataLocation] is used in an unusual way in this function. -; If the lower nybble is 0, the mon is added to the player's party, else the enemy's. -; If the entire value is 0, then the player is allowed to name the mon. - ld de, wPartyCount - ld a, [wMonDataLocation] - and $f - jr z, .next - ld de, wEnemyPartyCount -.next - ld a, [de] - inc a - cp PARTY_LENGTH + 1 - ret nc ; return if the party is already full - ld [de], a - ld a, [de] - ld [hNewPartyLength], a - add e - ld e, a - jr nc, .noCarry - inc d -.noCarry - ld a, [wcf91] - ld [de], a ; write species of new mon in party list - inc de - ld a, $ff ; terminator - ld [de], a - ld hl, wPartyMonOT - ld a, [wMonDataLocation] - and $f - jr z, .next2 - ld hl, wEnemyMonOT -.next2 - ld a, [hNewPartyLength] - dec a - call SkipFixedLengthTextEntries - ld d, h - ld e, l - ld hl, wPlayerName - ld bc, NAME_LENGTH - call CopyData - ld a, [wMonDataLocation] - and a - jr nz, .skipNaming - ld hl, wPartyMonNicks - ld a, [hNewPartyLength] - dec a - call SkipFixedLengthTextEntries - ld a, NAME_MON_SCREEN - ld [wNamingScreenType], a - predef AskName -.skipNaming - ld hl, wPartyMons - ld a, [wMonDataLocation] - and $f - jr z, .next3 - ld hl, wEnemyMons -.next3 - ld a, [hNewPartyLength] - dec a - ld bc, wPartyMon2 - wPartyMon1 - call AddNTimes - ld e, l - ld d, h - push hl - ld a, [wcf91] - ld [wd0b5], a - call GetMonHeader - ld hl, wMonHeader - ld a, [hli] - ld [de], a ; species - inc de - pop hl - push hl - ld a, [wMonDataLocation] - and $f - ld a, $98 ; set enemy trainer mon IVs to fixed average values - ld b, $88 - jr nz, .next4 - -; If the mon is being added to the player's party, update the pokedex. - ld a, [wcf91] - ld [wd11e], a - push de - predef IndexToPokedex - pop de - ld a, [wd11e] - dec a - ld c, a - ld b, FLAG_TEST - ld hl, wPokedexOwned - call FlagAction - ld a, c ; whether the mon was already flagged as owned - ld [wUnusedD153], a ; not read - ld a, [wd11e] - dec a - ld c, a - ld b, FLAG_SET - push bc - call FlagAction - pop bc - ld hl, wPokedexSeen - call FlagAction - - pop hl - push hl - - ld a, [wIsInBattle] - and a ; is this a wild mon caught in battle? - jr nz, .copyEnemyMonData - -; Not wild. - call Random ; generate random IVs - ld b, a - call Random - -.next4 - push bc - ld bc, wPartyMon1DVs - wPartyMon1 - add hl, bc - pop bc - ld [hli], a - ld [hl], b ; write IVs - ld bc, (wPartyMon1HPExp - 1) - (wPartyMon1DVs + 1) - add hl, bc - ld a, 1 - ld c, a - xor a - ld b, a - call CalcStat ; calc HP stat (set cur Hp to max HP) - ld a, [H_MULTIPLICAND+1] - ld [de], a - inc de - ld a, [H_MULTIPLICAND+2] - ld [de], a - inc de - xor a - ld [de], a ; box level - inc de - ld [de], a ; status ailments - inc de - jr .copyMonTypesAndMoves -.copyEnemyMonData - ld bc, wEnemyMon1DVs - wEnemyMon1 - add hl, bc - ld a, [wEnemyMonDVs] ; copy IVs from cur enemy mon - ld [hli], a - ld a, [wEnemyMonDVs + 1] - ld [hl], a - ld a, [wEnemyMonHP] ; copy HP from cur enemy mon - ld [de], a - inc de - ld a, [wEnemyMonHP+1] - ld [de], a - inc de - xor a - ld [de], a ; box level - inc de - ld a, [wEnemyMonStatus] ; copy status ailments from cur enemy mon - ld [de], a - inc de -.copyMonTypesAndMoves - ld hl, wMonHTypes - ld a, [hli] ; type 1 - ld [de], a - inc de - ld a, [hli] ; type 2 - ld [de], a - inc de - ld a, [hli] ; catch rate (held item in gen 2) - ld [de], a - ld hl, wMonHMoves - ld a, [hli] - inc de - push de - ld [de], a - ld a, [hli] - inc de - ld [de], a - ld a, [hli] - inc de - ld [de], a - ld a, [hli] - inc de - ld [de], a - push de - dec de - dec de - dec de - xor a - ld [wLearningMovesFromDayCare], a - predef WriteMonMoves - pop de - ld a, [wPlayerID] ; set trainer ID to player ID - inc de - ld [de], a - ld a, [wPlayerID + 1] - inc de - ld [de], a - push de - ld a, [wCurEnemyLVL] - ld d, a - callab CalcExperience - pop de - inc de - ld a, [hExperience] ; write experience - ld [de], a - inc de - ld a, [hExperience + 1] - ld [de], a - inc de - ld a, [hExperience + 2] - ld [de], a - xor a - ld b, NUM_STATS * 2 -.writeEVsLoop ; set all EVs to 0 - inc de - ld [de], a - dec b - jr nz, .writeEVsLoop - inc de - inc de - pop hl - call AddPartyMon_WriteMovePP - inc de - ld a, [wCurEnemyLVL] - ld [de], a - inc de - ld a, [wIsInBattle] - dec a - jr nz, .calcFreshStats - ld hl, wEnemyMonMaxHP - ld bc, $a - call CopyData ; copy stats of cur enemy mon - pop hl - jr .done -.calcFreshStats - pop hl - ld bc, wPartyMon1HPExp - 1 - wPartyMon1 - add hl, bc - ld b, $0 - call CalcStats ; calculate fresh set of stats -.done - scf - ret - -LoadMovePPs: - call GetPredefRegisters - ; fallthrough -AddPartyMon_WriteMovePP: - ld b, NUM_MOVES -.pploop - ld a, [hli] ; read move ID - and a - jr z, .empty - dec a - push hl - push de - push bc - ld hl, Moves - ld bc, MoveEnd - Moves - call AddNTimes - ld de, wcd6d - ld a, BANK(Moves) - call FarCopyData - pop bc - pop de - pop hl - ld a, [wcd6d + 5] ; PP is byte 5 of move data -.empty - inc de - ld [de], a - dec b - jr nz, .pploop ; there are still moves to read - ret - -; adds enemy mon [wcf91] (at position [wWhichPokemon] in enemy list) to own party -; used in the cable club trade center -_AddEnemyMonToPlayerParty:: - ld hl, wPartyCount - ld a, [hl] - cp PARTY_LENGTH - scf - ret z ; party full, return failure - inc a - ld [hl], a ; add 1 to party members - ld c, a - ld b, $0 - add hl, bc - ld a, [wcf91] - ld [hli], a ; add mon as last list entry - ld [hl], $ff ; write new sentinel - ld hl, wPartyMons - ld a, [wPartyCount] - dec a - ld bc, wPartyMon2 - wPartyMon1 - call AddNTimes - ld e, l - ld d, h - ld hl, wLoadedMon - call CopyData ; write new mon's data (from wLoadedMon) - ld hl, wPartyMonOT - ld a, [wPartyCount] - dec a - call SkipFixedLengthTextEntries - ld d, h - ld e, l - ld hl, wEnemyMonOT - ld a, [wWhichPokemon] - call SkipFixedLengthTextEntries - ld bc, NAME_LENGTH - call CopyData ; write new mon's OT name (from an enemy mon) - ld hl, wPartyMonNicks - ld a, [wPartyCount] - dec a - call SkipFixedLengthTextEntries - ld d, h - ld e, l - ld hl, wEnemyMonNicks - ld a, [wWhichPokemon] - call SkipFixedLengthTextEntries - ld bc, NAME_LENGTH - call CopyData ; write new mon's nickname (from an enemy mon) - ld a, [wcf91] - ld [wd11e], a - predef IndexToPokedex - ld a, [wd11e] - dec a - ld c, a - ld b, FLAG_SET - ld hl, wPokedexOwned - push bc - call FlagAction ; add to owned pokemon - pop bc - ld hl, wPokedexSeen - call FlagAction ; add to seen pokemon - and a - ret ; return success - -_MoveMon:: - ld a, [wMoveMonType] - and a ; BOX_TO_PARTY - jr z, .checkPartyMonSlots - cp DAYCARE_TO_PARTY - jr z, .checkPartyMonSlots - cp PARTY_TO_DAYCARE - ld hl, wDayCareMon - jr z, .findMonDataSrc - ; else it's PARTY_TO_BOX - ld hl, wNumInBox - ld a, [hl] - cp MONS_PER_BOX - jr nz, .partyOrBoxNotFull - jr .boxFull -.checkPartyMonSlots - ld hl, wPartyCount - ld a, [hl] - cp PARTY_LENGTH - jr nz, .partyOrBoxNotFull -.boxFull - scf - ret -.partyOrBoxNotFull - inc a - ld [hl], a ; increment number of mons in party/box - ld c, a - ld b, 0 - add hl, bc - ld a, [wMoveMonType] - cp DAYCARE_TO_PARTY - ld a, [wDayCareMon] - jr z, .copySpecies - ld a, [wcf91] -.copySpecies - ld [hli], a ; write new mon ID - ld [hl], $ff ; write new sentinel -.findMonDataDest - ld a, [wMoveMonType] - dec a - ld hl, wPartyMons - ld bc, wPartyMon2 - wPartyMon1 ; $2c - ld a, [wPartyCount] - jr nz, .addMonOffset - ; if it's PARTY_TO_BOX - ld hl, wBoxMons - ld bc, wBoxMon2 - wBoxMon1 ; $21 - ld a, [wNumInBox] -.addMonOffset - dec a - call AddNTimes -.findMonDataSrc - push hl - ld e, l - ld d, h - ld a, [wMoveMonType] - and a - ld hl, wBoxMons - ld bc, wBoxMon2 - wBoxMon1 ; $21 - jr z, .addMonOffset2 - cp DAYCARE_TO_PARTY - ld hl, wDayCareMon - jr z, .copyMonData - ld hl, wPartyMons - ld bc, wPartyMon2 - wPartyMon1 ; $2c -.addMonOffset2 - ld a, [wWhichPokemon] - call AddNTimes -.copyMonData - push hl - push de - ld bc, wBoxMon2 - wBoxMon1 - call CopyData - pop de - pop hl - ld a, [wMoveMonType] - and a ; BOX_TO_PARTY - jr z, .findOTdest - cp DAYCARE_TO_PARTY - jr z, .findOTdest - ld bc, wBoxMon2 - wBoxMon1 - add hl, bc - ld a, [hl] ; hl = Level - inc de - inc de - inc de - ld [de], a ; de = BoxLevel -.findOTdest - ld a, [wMoveMonType] - cp PARTY_TO_DAYCARE - ld de, wDayCareMonOT - jr z, .findOTsrc - dec a - ld hl, wPartyMonOT - ld a, [wPartyCount] - jr nz, .addOToffset - ld hl, wBoxMonOT - ld a, [wNumInBox] -.addOToffset - dec a - call SkipFixedLengthTextEntries - ld d, h - ld e, l -.findOTsrc - ld hl, wBoxMonOT - ld a, [wMoveMonType] - and a - jr z, .addOToffset2 - ld hl, wDayCareMonOT - cp DAYCARE_TO_PARTY - jr z, .copyOT - ld hl, wPartyMonOT -.addOToffset2 - ld a, [wWhichPokemon] - call SkipFixedLengthTextEntries -.copyOT - ld bc, NAME_LENGTH - call CopyData - ld a, [wMoveMonType] -.findNickDest - cp PARTY_TO_DAYCARE - ld de, wDayCareMonName - jr z, .findNickSrc - dec a - ld hl, wPartyMonNicks - ld a, [wPartyCount] - jr nz, .addNickOffset - ld hl, wBoxMonNicks - ld a, [wNumInBox] -.addNickOffset - dec a - call SkipFixedLengthTextEntries - ld d, h - ld e, l -.findNickSrc - ld hl, wBoxMonNicks - ld a, [wMoveMonType] - and a - jr z, .addNickOffset2 - ld hl, wDayCareMonName - cp DAYCARE_TO_PARTY - jr z, .copyNick - ld hl, wPartyMonNicks -.addNickOffset2 - ld a, [wWhichPokemon] - call SkipFixedLengthTextEntries -.copyNick - ld bc, NAME_LENGTH - call CopyData - pop hl - ld a, [wMoveMonType] - cp PARTY_TO_BOX - jr z, .done - cp PARTY_TO_DAYCARE - jr z, .done - push hl - srl a - add $2 - ld [wMonDataLocation], a - call LoadMonData - callba CalcLevelFromExperience - ld a, d - ld [wCurEnemyLVL], a - pop hl - ld bc, wBoxMon2 - wBoxMon1 - add hl, bc - ld [hli], a - ld d, h - ld e, l - ld bc, -18 - add hl, bc - ld b, $1 - call CalcStats -.done - and a - ret diff --git a/engine/battle/bank_e_misc.asm b/engine/battle/bank_e_misc.asm deleted file mode 100755 index 33af6f6f..00000000 --- a/engine/battle/bank_e_misc.asm +++ /dev/null @@ -1,122 +0,0 @@ -; formats a string at wMovesString that lists the moves at wMoves -FormatMovesString: - ld hl, wMoves - ld de, wMovesString - ld b, $0 -.printMoveNameLoop - ld a, [hli] - and a ; end of move list? - jr z, .printDashLoop ; print dashes when no moves are left - push hl - ld [wd0b5], a - ld a, BANK(MoveNames) - ld [wPredefBank], a - ld a, MOVE_NAME - ld [wNameListType], a - call GetName - ld hl, wcd6d -.copyNameLoop - ld a, [hli] - cp $50 - jr z, .doneCopyingName - ld [de], a - inc de - jr .copyNameLoop -.doneCopyingName - ld a, b - ld [wNumMovesMinusOne], a - inc b - ld a, $4e ; line break - ld [de], a - inc de - pop hl - ld a, b - cp NUM_MOVES - jr z, .done - jr .printMoveNameLoop -.printDashLoop - ld a, "-" - ld [de], a - inc de - inc b - ld a, b - cp NUM_MOVES - jr z, .done - ld a, $4e ; line break - ld [de], a - inc de - jr .printDashLoop -.done - ld a, "@" - ld [de], a - ret - -; XXX this is called in a few places, but it doesn't appear to do anything useful -InitList: - ld a, [wInitListType] - cp INIT_ENEMYOT_LIST - jr nz, .notEnemy - ld hl, wEnemyPartyCount - ld de, wEnemyMonOT - ld a, ENEMYOT_NAME - jr .done -.notEnemy - cp INIT_PLAYEROT_LIST - jr nz, .notPlayer - ld hl, wPartyCount - ld de, wPartyMonOT - ld a, PLAYEROT_NAME - jr .done -.notPlayer - cp INIT_MON_LIST - jr nz, .notMonster - ld hl, wItemList - ld de, MonsterNames - ld a, MONSTER_NAME - jr .done -.notMonster - cp INIT_BAG_ITEM_LIST - jr nz, .notBag - ld hl, wNumBagItems - ld de, ItemNames - ld a, ITEM_NAME - jr .done -.notBag - ld hl, wItemList - ld de, ItemNames - ld a, ITEM_NAME -.done - ld [wNameListType], a - ld a, l - ld [wListPointer], a - ld a, h - ld [wListPointer + 1], a - ld a, e - ld [wUnusedCF8D], a - ld a, d - ld [wUnusedCF8D + 1], a - ld bc, ItemPrices - ld a, c - ld [wItemPrices], a - 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/misc.asm b/engine/battle/misc.asm new file mode 100755 index 00000000..33af6f6f --- /dev/null +++ b/engine/battle/misc.asm @@ -0,0 +1,122 @@ +; formats a string at wMovesString that lists the moves at wMoves +FormatMovesString: + ld hl, wMoves + ld de, wMovesString + ld b, $0 +.printMoveNameLoop + ld a, [hli] + and a ; end of move list? + jr z, .printDashLoop ; print dashes when no moves are left + push hl + ld [wd0b5], a + ld a, BANK(MoveNames) + ld [wPredefBank], a + ld a, MOVE_NAME + ld [wNameListType], a + call GetName + ld hl, wcd6d +.copyNameLoop + ld a, [hli] + cp $50 + jr z, .doneCopyingName + ld [de], a + inc de + jr .copyNameLoop +.doneCopyingName + ld a, b + ld [wNumMovesMinusOne], a + inc b + ld a, $4e ; line break + ld [de], a + inc de + pop hl + ld a, b + cp NUM_MOVES + jr z, .done + jr .printMoveNameLoop +.printDashLoop + ld a, "-" + ld [de], a + inc de + inc b + ld a, b + cp NUM_MOVES + jr z, .done + ld a, $4e ; line break + ld [de], a + inc de + jr .printDashLoop +.done + ld a, "@" + ld [de], a + ret + +; XXX this is called in a few places, but it doesn't appear to do anything useful +InitList: + ld a, [wInitListType] + cp INIT_ENEMYOT_LIST + jr nz, .notEnemy + ld hl, wEnemyPartyCount + ld de, wEnemyMonOT + ld a, ENEMYOT_NAME + jr .done +.notEnemy + cp INIT_PLAYEROT_LIST + jr nz, .notPlayer + ld hl, wPartyCount + ld de, wPartyMonOT + ld a, PLAYEROT_NAME + jr .done +.notPlayer + cp INIT_MON_LIST + jr nz, .notMonster + ld hl, wItemList + ld de, MonsterNames + ld a, MONSTER_NAME + jr .done +.notMonster + cp INIT_BAG_ITEM_LIST + jr nz, .notBag + ld hl, wNumBagItems + ld de, ItemNames + ld a, ITEM_NAME + jr .done +.notBag + ld hl, wItemList + ld de, ItemNames + ld a, ITEM_NAME +.done + ld [wNameListType], a + ld a, l + ld [wListPointer], a + ld a, h + ld [wListPointer + 1], a + ld a, e + ld [wUnusedCF8D], a + ld a, d + ld [wUnusedCF8D + 1], a + ld bc, ItemPrices + ld a, c + ld [wItemPrices], a + 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/moveEffects/conversion_effect.asm b/engine/battle/moveEffects/conversion_effect.asm deleted file mode 100644 index f23c3d70..00000000 --- a/engine/battle/moveEffects/conversion_effect.asm +++ /dev/null @@ -1,35 +0,0 @@ -ConversionEffect_: - ld hl, wEnemyMonType1 - ld de, wBattleMonType1 - ld a, [H_WHOSETURN] - and a - ld a, [wEnemyBattleStatus1] - jr z, .conversionEffect - push hl - ld h, d - ld l, e - pop de - ld a, [wPlayerBattleStatus1] -.conversionEffect - bit INVULNERABLE, a ; is mon immune to typical attacks (dig/fly) - jr nz, PrintButItFailedText -; copy target's types to user - ld a, [hli] - ld [de], a - inc de - ld a, [hl] - ld [de], a - ld hl, PlayCurrentMoveAnimation - call CallBankF - ld hl, ConvertedTypeText - jp PrintText - -ConvertedTypeText: - TX_FAR _ConvertedTypeText - db "@" - -PrintButItFailedText: - ld hl, PrintButItFailedText_ -CallBankF: - ld b, BANK(PrintButItFailedText_) - jp Bankswitch diff --git a/engine/battle/moveEffects/drain_hp_effect.asm b/engine/battle/moveEffects/drain_hp_effect.asm deleted file mode 100644 index e5f4681a..00000000 --- a/engine/battle/moveEffects/drain_hp_effect.asm +++ /dev/null @@ -1,104 +0,0 @@ -DrainHPEffect_: - ld hl, wDamage - ld a, [hl] - srl a ; divide damage by 2 - ld [hli], a - ld a, [hl] - rr a - ld [hld], a - or [hl] ; is damage 0? - jr nz, .getAttackerHP -; if damage is 0, increase to 1 so that the attacker gains at least 1 HP - inc hl - inc [hl] -.getAttackerHP - ld hl, wBattleMonHP - ld de, wBattleMonMaxHP - ld a, [H_WHOSETURN] - and a - jp z, .addDamageToAttackerHP - ld hl, wEnemyMonHP - ld de, wEnemyMonMaxHP -.addDamageToAttackerHP - ld bc, wHPBarOldHP+1 -; copy current HP to wHPBarOldHP - ld a, [hli] - ld [bc], a - ld a, [hl] - dec bc - ld [bc], a -; copy max HP to wHPBarMaxHP - ld a, [de] - dec bc - ld [bc], a - inc de - ld a, [de] - dec bc - ld [bc], a -; add damage to attacker's HP and copy new HP to wHPBarNewHP - ld a, [wDamage + 1] - ld b, [hl] - add b - ld [hld], a - ld [wHPBarNewHP], a - ld a, [wDamage] - ld b, [hl] - adc b - ld [hli], a - ld [wHPBarNewHP+1], a - jr c, .capToMaxHP ; if HP > 65,535, cap to max HP -; compare HP with max HP - ld a, [hld] - ld b, a - ld a, [de] - dec de - sub b - ld a, [hli] - ld b, a - ld a, [de] - inc de - sbc b - jr nc, .next -.capToMaxHP - ld a, [de] - ld [hld], a - ld [wHPBarNewHP], a - dec de - ld a, [de] - ld [hli], a - ld [wHPBarNewHP+1], a - inc de -.next - ld a, [H_WHOSETURN] - and a - coord hl, 10, 9 - ld a, $1 - jr z, .next2 - coord hl, 2, 2 - xor a -.next2 - ld [wHPBarType], a - predef UpdateHPBar2 - predef DrawPlayerHUDAndHPBar - predef DrawEnemyHUDAndHPBar - callab ReadPlayerMonCurHPAndStatus - ld hl, SuckedHealthText - ld a, [H_WHOSETURN] - and a - ld a, [wPlayerMoveEffect] - jr z, .next3 - ld a, [wEnemyMoveEffect] -.next3 - cp DREAM_EATER_EFFECT - jr nz, .printText - ld hl, DreamWasEatenText -.printText - jp PrintText - -SuckedHealthText: - TX_FAR _SuckedHealthText - db "@" - -DreamWasEatenText: - TX_FAR _DreamWasEatenText - db "@" diff --git a/engine/battle/moveEffects/focus_energy_effect.asm b/engine/battle/moveEffects/focus_energy_effect.asm deleted file mode 100644 index 16dad7bb..00000000 --- a/engine/battle/moveEffects/focus_energy_effect.asm +++ /dev/null @@ -1,22 +0,0 @@ -FocusEnergyEffect_: - ld hl, wPlayerBattleStatus2 - ld a, [H_WHOSETURN] - and a - jr z, .notEnemy - ld hl, wEnemyBattleStatus2 -.notEnemy - bit GETTING_PUMPED, [hl] ; is mon already using focus energy? - jr nz, .alreadyUsing - set GETTING_PUMPED, [hl] ; mon is now using focus energy - callab PlayCurrentMoveAnimation - ld hl, GettingPumpedText - jp PrintText -.alreadyUsing - ld c, 50 - call DelayFrames - jpab PrintButItFailedText_ - -GettingPumpedText: - TX_DELAY - TX_FAR _GettingPumpedText - db "@" diff --git a/engine/battle/moveEffects/haze_effect.asm b/engine/battle/moveEffects/haze_effect.asm deleted file mode 100644 index 47723ba2..00000000 --- a/engine/battle/moveEffects/haze_effect.asm +++ /dev/null @@ -1,81 +0,0 @@ -HazeEffect_: - ld a, $7 -; store 7 on every stat mod - ld hl, wPlayerMonAttackMod - call ResetStatMods - ld hl, wEnemyMonAttackMod - call ResetStatMods -; copy unmodified stats to battle stats - ld hl, wPlayerMonUnmodifiedAttack - ld de, wBattleMonAttack - call ResetStats - ld hl, wEnemyMonUnmodifiedAttack - ld de, wEnemyMonAttack - call ResetStats -; cure non-volatile status, but only for the target - ld hl, wEnemyMonStatus - ld de, wEnemySelectedMove - ld a, [H_WHOSETURN] - and a - jr z, .cureStatuses - ld hl, wBattleMonStatus - dec de ; wPlayerSelectedMove - -.cureStatuses - ld a, [hl] - ld [hl], $0 - and SLP | (1 << FRZ) - jr z, .cureVolatileStatuses -; prevent the Pokemon from executing a move if it was asleep or frozen - ld a, $ff - ld [de], a - -.cureVolatileStatuses - xor a - ld [wPlayerDisabledMove], a - ld [wEnemyDisabledMove], a - ld hl, wPlayerDisabledMoveNumber - ld [hli], a - ld [hl], a - ld hl, wPlayerBattleStatus1 - call CureVolatileStatuses - ld hl, wEnemyBattleStatus1 - call CureVolatileStatuses - ld hl, PlayCurrentMoveAnimation - call CallBankF - ld hl, StatusChangesEliminatedText - jp PrintText - -CureVolatileStatuses: - res CONFUSED, [hl] - inc hl ; BATTSTATUS2 - ld a, [hl] - ; clear USING_X_ACCURACY, PROTECTED_BY_MIST, GETTING_PUMPED, and SEEDED statuses - and $ff ^((1 << USING_X_ACCURACY) | (1 << PROTECTED_BY_MIST) | (1 << GETTING_PUMPED) | (1 << SEEDED)) - ld [hli], a ; BATTSTATUS3 - ld a, [hl] - and %11110000 | (1 << TRANSFORMED) ; clear Bad Poison, Reflect and Light Screen statuses - ld [hl], a - ret - -ResetStatMods: - ld b, $8 -.loop - ld [hli], a - dec b - jr nz, .loop - ret - -ResetStats: - ld b, $8 -.loop - ld a, [hli] - ld [de], a - inc de - dec b - jr nz, .loop - ret - -StatusChangesEliminatedText: - TX_FAR _StatusChangesEliminatedText - db "@" diff --git a/engine/battle/moveEffects/heal_effect.asm b/engine/battle/moveEffects/heal_effect.asm deleted file mode 100644 index 2e68acc0..00000000 --- a/engine/battle/moveEffects/heal_effect.asm +++ /dev/null @@ -1,120 +0,0 @@ -HealEffect_: - ld a, [H_WHOSETURN] - and a - ld de, wBattleMonHP - ld hl, wBattleMonMaxHP - ld a, [wPlayerMoveNum] - jr z, .healEffect - ld de, wEnemyMonHP - ld hl, wEnemyMonMaxHP - ld a, [wEnemyMoveNum] -.healEffect - ld b, a - ld a, [de] - cp [hl] ; most significant bytes comparison is ignored - ; causes the move to miss if max HP is 255 or 511 points higher than the current HP - inc de - inc hl - ld a, [de] - sbc [hl] - jp z, .failed ; no effect if user's HP is already at its maximum - ld a, b - cp REST - jr nz, .healHP - push hl - push de - push af - ld c, 50 - call DelayFrames - ld hl, wBattleMonStatus - ld a, [H_WHOSETURN] - and a - jr z, .restEffect - ld hl, wEnemyMonStatus -.restEffect - ld a, [hl] - and a - ld [hl], 2 ; clear status and set number of turns asleep to 2 - ld hl, StartedSleepingEffect ; if mon didn't have an status - jr z, .printRestText - ld hl, FellAsleepBecameHealthyText ; if mon had an status -.printRestText - call PrintText - pop af - pop de - pop hl -.healHP - ld a, [hld] - ld [wHPBarMaxHP], a - ld c, a - ld a, [hl] - ld [wHPBarMaxHP+1], a - ld b, a - jr z, .gotHPAmountToHeal -; Recover and Softboiled only heal for half the mon's max HP - srl b - rr c -.gotHPAmountToHeal -; update HP - ld a, [de] - ld [wHPBarOldHP], a - add c - ld [de], a - ld [wHPBarNewHP], a - dec de - ld a, [de] - ld [wHPBarOldHP+1], a - adc b - ld [de], a - ld [wHPBarNewHP+1], a - inc hl - inc de - ld a, [de] - dec de - sub [hl] - dec hl - ld a, [de] - sbc [hl] - jr c, .playAnim -; copy max HP to current HP if an overflow occurred - ld a, [hli] - ld [de], a - ld [wHPBarNewHP+1], a - inc de - ld a, [hl] - ld [de], a - ld [wHPBarNewHP], a -.playAnim - ld hl, PlayCurrentMoveAnimation - call BankswitchEtoF - ld a, [H_WHOSETURN] - and a - coord hl, 10, 9 - ld a, $1 - jr z, .updateHPBar - coord hl, 2, 2 - xor a -.updateHPBar - ld [wHPBarType], a - predef UpdateHPBar2 - ld hl, DrawHUDsAndHPBars - call BankswitchEtoF - ld hl, RegainedHealthText - jp PrintText -.failed - ld c, 50 - call DelayFrames - ld hl, PrintButItFailedText_ - jp BankswitchEtoF - -StartedSleepingEffect: - TX_FAR _StartedSleepingEffect - db "@" - -FellAsleepBecameHealthyText: - TX_FAR _FellAsleepBecameHealthyText - db "@" - -RegainedHealthText: - TX_FAR _RegainedHealthText - db "@" diff --git a/engine/battle/moveEffects/leech_seed_effect.asm b/engine/battle/moveEffects/leech_seed_effect.asm deleted file mode 100644 index f4d3ee9c..00000000 --- a/engine/battle/moveEffects/leech_seed_effect.asm +++ /dev/null @@ -1,40 +0,0 @@ -LeechSeedEffect_: - callab MoveHitTest - ld a, [wMoveMissed] - and a - jr nz, .moveMissed - ld hl, wEnemyBattleStatus2 - ld de, wEnemyMonType1 - ld a, [H_WHOSETURN] - and a - jr z, .leechSeedEffect - ld hl, wPlayerBattleStatus2 - ld de, wBattleMonType1 -.leechSeedEffect -; miss if the target is grass-type or already seeded - ld a, [de] - cp GRASS - jr z, .moveMissed - inc de - ld a, [de] - cp GRASS - jr z, .moveMissed - bit SEEDED, [hl] - jr nz, .moveMissed - set SEEDED, [hl] - callab PlayCurrentMoveAnimation - ld hl, WasSeededText - jp PrintText -.moveMissed - ld c, 50 - call DelayFrames - ld hl, EvadedAttackText - jp PrintText - -WasSeededText: - TX_FAR _WasSeededText - db "@" - -EvadedAttackText: - TX_FAR _EvadedAttackText - db "@" diff --git a/engine/battle/moveEffects/mist_effect.asm b/engine/battle/moveEffects/mist_effect.asm deleted file mode 100644 index 65070a3e..00000000 --- a/engine/battle/moveEffects/mist_effect.asm +++ /dev/null @@ -1,19 +0,0 @@ -MistEffect_: - ld hl, wPlayerBattleStatus2 - ld a, [H_WHOSETURN] - and a - jr z, .mistEffect - ld hl, wEnemyBattleStatus2 -.mistEffect - bit PROTECTED_BY_MIST, [hl] ; is mon protected by mist? - jr nz, .mistAlreadyInUse - set PROTECTED_BY_MIST, [hl] ; mon is now protected by mist - callab PlayCurrentMoveAnimation - ld hl, ShroudedInMistText - jp PrintText -.mistAlreadyInUse - jpab PrintButItFailedText_ - -ShroudedInMistText: - TX_FAR _ShroudedInMistText - db "@" diff --git a/engine/battle/moveEffects/one_hit_ko_effect.asm b/engine/battle/moveEffects/one_hit_ko_effect.asm deleted file mode 100644 index 827e2197..00000000 --- a/engine/battle/moveEffects/one_hit_ko_effect.asm +++ /dev/null @@ -1,38 +0,0 @@ -OneHitKOEffect_: - ld hl, wDamage - xor a - ld [hli], a - ld [hl], a ; set the damage output to zero - dec a - ld [wCriticalHitOrOHKO], a - ld hl, wBattleMonSpeed + 1 - ld de, wEnemyMonSpeed + 1 - ld a, [H_WHOSETURN] - and a - jr z, .compareSpeed - ld hl, wEnemyMonSpeed + 1 - ld de, wBattleMonSpeed + 1 -.compareSpeed -; set damage to 65535 and OHKO flag is the user's current speed is higher than the target's - ld a, [de] - dec de - ld b, a - ld a, [hld] - sub b - ld a, [de] - ld b, a - ld a, [hl] - sbc b - jr c, .userIsSlower - ld hl, wDamage - ld a, $ff - ld [hli], a - ld [hl], a - ld a, $2 - ld [wCriticalHitOrOHKO], a - ret -.userIsSlower -; keep damage at 0 and set move missed flag if target's current speed is higher instead - ld a, $1 - ld [wMoveMissed], a - ret diff --git a/engine/battle/moveEffects/paralyze_effect.asm b/engine/battle/moveEffects/paralyze_effect.asm deleted file mode 100644 index 95979ae6..00000000 --- a/engine/battle/moveEffects/paralyze_effect.asm +++ /dev/null @@ -1,47 +0,0 @@ -ParalyzeEffect_: - ld hl, wEnemyMonStatus - ld de, wPlayerMoveType - ld a, [H_WHOSETURN] - and a - jp z, .next - ld hl, wBattleMonStatus - ld de, wEnemyMoveType -.next - ld a, [hl] - and a ; does the target already have a status ailment? - jr nz, .didntAffect -; check if the target is immune due to types - ld a, [de] - cp ELECTRIC - jr nz, .hitTest - ld b, h - ld c, l - inc bc - ld a, [bc] - cp GROUND - jr z, .doesntAffect - inc bc - ld a, [bc] - cp GROUND - jr z, .doesntAffect -.hitTest - push hl - callab MoveHitTest - pop hl - ld a, [wMoveMissed] - and a - jr nz, .didntAffect - set PAR, [hl] - callab QuarterSpeedDueToParalysis - ld c, 30 - call DelayFrames - callab PlayCurrentMoveAnimation - jpab PrintMayNotAttackText -.didntAffect - ld c, 50 - call DelayFrames - jpab PrintDidntAffectText -.doesntAffect - ld c, 50 - call DelayFrames - jpab PrintDoesntAffectText diff --git a/engine/battle/moveEffects/pay_day_effect.asm b/engine/battle/moveEffects/pay_day_effect.asm deleted file mode 100644 index e5daf014..00000000 --- a/engine/battle/moveEffects/pay_day_effect.asm +++ /dev/null @@ -1,45 +0,0 @@ -PayDayEffect_: - xor a - ld hl, wcd6d - ld [hli], a - ld a, [H_WHOSETURN] - and a - ld a, [wBattleMonLevel] - jr z, .payDayEffect - ld a, [wEnemyMonLevel] -.payDayEffect -; level * 2 - add a - ld [H_DIVIDEND + 3], a - xor a - ld [H_DIVIDEND], a - ld [H_DIVIDEND + 1], a - ld [H_DIVIDEND + 2], a -; convert to BCD - ld a, 100 - ld [H_DIVISOR], a - ld b, $4 - call Divide - ld a, [H_QUOTIENT + 3] - ld [hli], a - ld a, [H_REMAINDER] - ld [H_DIVIDEND + 3], a - ld a, 10 - ld [H_DIVISOR], a - ld b, $4 - call Divide - ld a, [H_QUOTIENT + 3] - swap a - ld b, a - ld a, [H_REMAINDER] - add b - ld [hl], a - ld de, wTotalPayDayMoney + 2 - ld c, $3 - predef AddBCDPredef - ld hl, CoinsScatteredText - jp PrintText - -CoinsScatteredText: - TX_FAR _CoinsScatteredText - db "@" diff --git a/engine/battle/moveEffects/recoil_effect.asm b/engine/battle/moveEffects/recoil_effect.asm deleted file mode 100644 index 0f2f087b..00000000 --- a/engine/battle/moveEffects/recoil_effect.asm +++ /dev/null @@ -1,70 +0,0 @@ -RecoilEffect_: - ld a, [H_WHOSETURN] - and a - ld a, [wPlayerMoveNum] - ld hl, wBattleMonMaxHP - jr z, .recoilEffect - ld a, [wEnemyMoveNum] - ld hl, wEnemyMonMaxHP -.recoilEffect - ld d, a - ld a, [wDamage] - ld b, a - ld a, [wDamage + 1] - ld c, a - srl b - rr c - ld a, d - cp STRUGGLE ; struggle deals 50% recoil damage - jr z, .gotRecoilDamage - srl b - rr c -.gotRecoilDamage - ld a, b - or c - jr nz, .updateHP - inc c ; minimum recoil damage is 1 -.updateHP -; subtract HP from user due to the recoil damage - ld a, [hli] - ld [wHPBarMaxHP+1], a - ld a, [hl] - ld [wHPBarMaxHP], a - push bc - ld bc, wBattleMonHP - wBattleMonMaxHP - add hl, bc - pop bc - ld a, [hl] - ld [wHPBarOldHP], a - sub c - ld [hld], a - ld [wHPBarNewHP], a - ld a, [hl] - ld [wHPBarOldHP+1], a - sbc b - ld [hl], a - ld [wHPBarNewHP+1], a - jr nc, .getHPBarCoords -; if recoil damage is higher than the Pokemon's HP, set its HP to 0 - xor a - ld [hli], a - ld [hl], a - ld hl, wHPBarNewHP - ld [hli], a - ld [hl], a -.getHPBarCoords - coord hl, 10, 9 - ld a, [H_WHOSETURN] - and a - ld a, $1 - jr z, .updateHPBar - coord hl, 2, 2 - xor a -.updateHPBar - ld [wHPBarType], a - predef UpdateHPBar2 - ld hl, HitWithRecoilText - jp PrintText -HitWithRecoilText: - TX_FAR _HitWithRecoilText - db "@" diff --git a/engine/battle/moveEffects/reflect_light_screen_effect.asm b/engine/battle/moveEffects/reflect_light_screen_effect.asm deleted file mode 100644 index 2805a969..00000000 --- a/engine/battle/moveEffects/reflect_light_screen_effect.asm +++ /dev/null @@ -1,45 +0,0 @@ -ReflectLightScreenEffect_: - ld hl, wPlayerBattleStatus3 - ld de, wPlayerMoveEffect - ld a, [H_WHOSETURN] - and a - jr z, .reflectLightScreenEffect - ld hl, wEnemyBattleStatus3 - ld de, wEnemyMoveEffect -.reflectLightScreenEffect - ld a, [de] - cp LIGHT_SCREEN_EFFECT - jr nz, .reflect - bit HAS_LIGHT_SCREEN_UP, [hl] ; is mon already protected by light screen? - jr nz, .moveFailed - set HAS_LIGHT_SCREEN_UP, [hl] ; mon is now protected by light screen - ld hl, LightScreenProtectedText - jr .playAnim -.reflect - bit HAS_REFLECT_UP, [hl] ; is mon already protected by reflect? - jr nz, .moveFailed - set HAS_REFLECT_UP, [hl] ; mon is now protected by reflect - ld hl, ReflectGainedArmorText -.playAnim - push hl - ld hl, PlayCurrentMoveAnimation - call BankswitchEtoF - pop hl - jp PrintText -.moveFailed - ld c, 50 - call DelayFrames - ld hl, PrintButItFailedText_ - jp BankswitchEtoF - -LightScreenProtectedText: - TX_FAR _LightScreenProtectedText - db "@" - -ReflectGainedArmorText: - TX_FAR _ReflectGainedArmorText - db "@" - -BankswitchEtoF: - ld b, BANK(BattleCore) - jp Bankswitch diff --git a/engine/battle/moveEffects/substitute_effect.asm b/engine/battle/moveEffects/substitute_effect.asm deleted file mode 100644 index 1bb6c887..00000000 --- a/engine/battle/moveEffects/substitute_effect.asm +++ /dev/null @@ -1,77 +0,0 @@ -SubstituteEffect_: - ld c, 50 - call DelayFrames - ld hl, wBattleMonMaxHP - ld de, wPlayerSubstituteHP - ld bc, wPlayerBattleStatus2 - ld a, [H_WHOSETURN] - and a - jr z, .notEnemy - ld hl, wEnemyMonMaxHP - ld de, wEnemySubstituteHP - ld bc, wEnemyBattleStatus2 -.notEnemy - ld a, [bc] - bit HAS_SUBSTITUTE_UP, a ; user already has substitute? - jr nz, .alreadyHasSubstitute -; quarter health to remove from user -; assumes max HP is 1023 or lower - push bc - ld a, [hli] - ld b, [hl] - srl a - rr b - srl a - rr b ; max hp / 4 - push de - ld de, wBattleMonHP - wBattleMonMaxHP - add hl, de ; point hl to current HP low byte - pop de - ld a, b - ld [de], a ; save copy of HP to subtract in wPlayerSubstituteHP/wEnemySubstituteHP - ld a, [hld] -; subtract [max hp / 4] to current HP - sub b - ld d, a - ld a, [hl] - sbc 0 - pop bc - jr c, .notEnoughHP ; underflow means user would be left with negative health - ; bug: since it only branches on carry, it will possibly leave user with 0 HP -.userHasZeroOrMoreHP - ldi [hl], a ; save resulting HP after subtraction into current HP - ld [hl], d - ld h, b - ld l, c - set HAS_SUBSTITUTE_UP, [hl] - ld a, [wOptions] - bit 7, a ; battle animation is enabled? - ld hl, PlayCurrentMoveAnimation - ld b, BANK(PlayCurrentMoveAnimation) - jr z, .animationEnabled - ld hl, AnimationSubstitute - ld b, BANK(AnimationSubstitute) -.animationEnabled - call Bankswitch ; jump to routine depending on animation setting - ld hl, SubstituteText - call PrintText - jpab DrawHUDsAndHPBars -.alreadyHasSubstitute - ld hl, HasSubstituteText - jr .printText -.notEnoughHP - ld hl, TooWeakSubstituteText -.printText - jp PrintText - -SubstituteText: - TX_FAR _SubstituteText - db "@" - -HasSubstituteText: - TX_FAR _HasSubstituteText - db "@" - -TooWeakSubstituteText: - TX_FAR _TooWeakSubstituteText - db "@" diff --git a/engine/battle/moveEffects/transform_effect.asm b/engine/battle/moveEffects/transform_effect.asm deleted file mode 100644 index 9a5de9cc..00000000 --- a/engine/battle/moveEffects/transform_effect.asm +++ /dev/null @@ -1,148 +0,0 @@ -TransformEffect_: - ld hl, wBattleMonSpecies - ld de, wEnemyMonSpecies - ld bc, wEnemyBattleStatus3 - ld a, [wEnemyBattleStatus1] - ld a, [H_WHOSETURN] - and a - jr nz, .hitTest - ld hl, wEnemyMonSpecies - ld de, wBattleMonSpecies - ld bc, wPlayerBattleStatus3 - ld [wPlayerMoveListIndex], a - ld a, [wPlayerBattleStatus1] -.hitTest - bit INVULNERABLE, a ; is mon invulnerable to typical attacks? (fly/dig) - jp nz, .failed - push hl - push de - push bc - ld hl, wPlayerBattleStatus2 - ld a, [H_WHOSETURN] - and a - jr z, .transformEffect - ld hl, wEnemyBattleStatus2 -.transformEffect -; animation(s) played are different if target has Substitute up - bit HAS_SUBSTITUTE_UP, [hl] - push af - ld hl, HideSubstituteShowMonAnim - ld b, BANK(HideSubstituteShowMonAnim) - call nz, Bankswitch - ld a, [wOptions] - add a - ld hl, PlayCurrentMoveAnimation - ld b, BANK(PlayCurrentMoveAnimation) - jr nc, .gotAnimToPlay - ld hl, AnimationTransformMon - ld b, BANK(AnimationTransformMon) -.gotAnimToPlay - call Bankswitch - ld hl, ReshowSubstituteAnim - ld b, BANK(ReshowSubstituteAnim) - pop af - call nz, Bankswitch - pop bc - ld a, [bc] - set TRANSFORMED, a ; mon is now transformed - ld [bc], a - pop de - pop hl - push hl -; transform user into opposing Pokemon -; species - ld a, [hl] - ld [de], a -; type 1, type 2, catch rate, and moves - ld bc, $5 - add hl, bc - inc de - inc de - inc de - inc de - inc de - inc bc - inc bc - call CopyData - ld a, [H_WHOSETURN] - and a - jr z, .next -; save enemy mon DVs at wTransformedEnemyMonOriginalDVs - ld a, [de] - ld [wTransformedEnemyMonOriginalDVs], a - inc de - ld a, [de] - ld [wTransformedEnemyMonOriginalDVs + 1], a - dec de -.next -; DVs - ld a, [hli] - ld [de], a - inc de - ld a, [hli] - ld [de], a - inc de -; Attack, Defense, Speed, and Special stats - inc hl - inc hl - inc hl - inc de - inc de - inc de - ld bc, $8 - call CopyData - ld bc, wBattleMonMoves - wBattleMonPP - add hl, bc ; ld hl, wBattleMonMoves - ld b, NUM_MOVES -.copyPPLoop -; 5 PP for all moves - ld a, [hli] - 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 -.copyStats -; original (unmodified) stats and stat mods - pop hl - ld a, [hl] - ld [wd11e], a - call GetMonName - ld hl, wEnemyMonUnmodifiedAttack - ld de, wPlayerMonUnmodifiedAttack - call .copyBasedOnTurn ; original (unmodified) stats - ld hl, wEnemyMonStatMods - ld de, wPlayerMonStatMods - call .copyBasedOnTurn ; stat mods - ld hl, TransformedText - jp PrintText - -.copyBasedOnTurn - ld a, [H_WHOSETURN] - and a - jr z, .gotStatsOrModsToCopy - push hl - ld h, d - ld l, e - pop de -.gotStatsOrModsToCopy - ld bc, $8 - jp CopyData - -.failed - ld hl, PrintButItFailedText_ - jp BankswitchEtoF - -TransformedText: - TX_FAR _TransformedText - db "@" diff --git a/engine/battle/move_effects/conversion.asm b/engine/battle/move_effects/conversion.asm new file mode 100644 index 00000000..f23c3d70 --- /dev/null +++ b/engine/battle/move_effects/conversion.asm @@ -0,0 +1,35 @@ +ConversionEffect_: + ld hl, wEnemyMonType1 + ld de, wBattleMonType1 + ld a, [H_WHOSETURN] + and a + ld a, [wEnemyBattleStatus1] + jr z, .conversionEffect + push hl + ld h, d + ld l, e + pop de + ld a, [wPlayerBattleStatus1] +.conversionEffect + bit INVULNERABLE, a ; is mon immune to typical attacks (dig/fly) + jr nz, PrintButItFailedText +; copy target's types to user + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + ld hl, PlayCurrentMoveAnimation + call CallBankF + ld hl, ConvertedTypeText + jp PrintText + +ConvertedTypeText: + TX_FAR _ConvertedTypeText + db "@" + +PrintButItFailedText: + ld hl, PrintButItFailedText_ +CallBankF: + ld b, BANK(PrintButItFailedText_) + jp Bankswitch diff --git a/engine/battle/move_effects/drain_hp.asm b/engine/battle/move_effects/drain_hp.asm new file mode 100644 index 00000000..e5f4681a --- /dev/null +++ b/engine/battle/move_effects/drain_hp.asm @@ -0,0 +1,104 @@ +DrainHPEffect_: + ld hl, wDamage + ld a, [hl] + srl a ; divide damage by 2 + ld [hli], a + ld a, [hl] + rr a + ld [hld], a + or [hl] ; is damage 0? + jr nz, .getAttackerHP +; if damage is 0, increase to 1 so that the attacker gains at least 1 HP + inc hl + inc [hl] +.getAttackerHP + ld hl, wBattleMonHP + ld de, wBattleMonMaxHP + ld a, [H_WHOSETURN] + and a + jp z, .addDamageToAttackerHP + ld hl, wEnemyMonHP + ld de, wEnemyMonMaxHP +.addDamageToAttackerHP + ld bc, wHPBarOldHP+1 +; copy current HP to wHPBarOldHP + ld a, [hli] + ld [bc], a + ld a, [hl] + dec bc + ld [bc], a +; copy max HP to wHPBarMaxHP + ld a, [de] + dec bc + ld [bc], a + inc de + ld a, [de] + dec bc + ld [bc], a +; add damage to attacker's HP and copy new HP to wHPBarNewHP + ld a, [wDamage + 1] + ld b, [hl] + add b + ld [hld], a + ld [wHPBarNewHP], a + ld a, [wDamage] + ld b, [hl] + adc b + ld [hli], a + ld [wHPBarNewHP+1], a + jr c, .capToMaxHP ; if HP > 65,535, cap to max HP +; compare HP with max HP + ld a, [hld] + ld b, a + ld a, [de] + dec de + sub b + ld a, [hli] + ld b, a + ld a, [de] + inc de + sbc b + jr nc, .next +.capToMaxHP + ld a, [de] + ld [hld], a + ld [wHPBarNewHP], a + dec de + ld a, [de] + ld [hli], a + ld [wHPBarNewHP+1], a + inc de +.next + ld a, [H_WHOSETURN] + and a + coord hl, 10, 9 + ld a, $1 + jr z, .next2 + coord hl, 2, 2 + xor a +.next2 + ld [wHPBarType], a + predef UpdateHPBar2 + predef DrawPlayerHUDAndHPBar + predef DrawEnemyHUDAndHPBar + callab ReadPlayerMonCurHPAndStatus + ld hl, SuckedHealthText + ld a, [H_WHOSETURN] + and a + ld a, [wPlayerMoveEffect] + jr z, .next3 + ld a, [wEnemyMoveEffect] +.next3 + cp DREAM_EATER_EFFECT + jr nz, .printText + ld hl, DreamWasEatenText +.printText + jp PrintText + +SuckedHealthText: + TX_FAR _SuckedHealthText + db "@" + +DreamWasEatenText: + TX_FAR _DreamWasEatenText + db "@" diff --git a/engine/battle/move_effects/focus_energy.asm b/engine/battle/move_effects/focus_energy.asm new file mode 100644 index 00000000..16dad7bb --- /dev/null +++ b/engine/battle/move_effects/focus_energy.asm @@ -0,0 +1,22 @@ +FocusEnergyEffect_: + ld hl, wPlayerBattleStatus2 + ld a, [H_WHOSETURN] + and a + jr z, .notEnemy + ld hl, wEnemyBattleStatus2 +.notEnemy + bit GETTING_PUMPED, [hl] ; is mon already using focus energy? + jr nz, .alreadyUsing + set GETTING_PUMPED, [hl] ; mon is now using focus energy + callab PlayCurrentMoveAnimation + ld hl, GettingPumpedText + jp PrintText +.alreadyUsing + ld c, 50 + call DelayFrames + jpab PrintButItFailedText_ + +GettingPumpedText: + TX_DELAY + TX_FAR _GettingPumpedText + db "@" diff --git a/engine/battle/move_effects/haze.asm b/engine/battle/move_effects/haze.asm new file mode 100644 index 00000000..47723ba2 --- /dev/null +++ b/engine/battle/move_effects/haze.asm @@ -0,0 +1,81 @@ +HazeEffect_: + ld a, $7 +; store 7 on every stat mod + ld hl, wPlayerMonAttackMod + call ResetStatMods + ld hl, wEnemyMonAttackMod + call ResetStatMods +; copy unmodified stats to battle stats + ld hl, wPlayerMonUnmodifiedAttack + ld de, wBattleMonAttack + call ResetStats + ld hl, wEnemyMonUnmodifiedAttack + ld de, wEnemyMonAttack + call ResetStats +; cure non-volatile status, but only for the target + ld hl, wEnemyMonStatus + ld de, wEnemySelectedMove + ld a, [H_WHOSETURN] + and a + jr z, .cureStatuses + ld hl, wBattleMonStatus + dec de ; wPlayerSelectedMove + +.cureStatuses + ld a, [hl] + ld [hl], $0 + and SLP | (1 << FRZ) + jr z, .cureVolatileStatuses +; prevent the Pokemon from executing a move if it was asleep or frozen + ld a, $ff + ld [de], a + +.cureVolatileStatuses + xor a + ld [wPlayerDisabledMove], a + ld [wEnemyDisabledMove], a + ld hl, wPlayerDisabledMoveNumber + ld [hli], a + ld [hl], a + ld hl, wPlayerBattleStatus1 + call CureVolatileStatuses + ld hl, wEnemyBattleStatus1 + call CureVolatileStatuses + ld hl, PlayCurrentMoveAnimation + call CallBankF + ld hl, StatusChangesEliminatedText + jp PrintText + +CureVolatileStatuses: + res CONFUSED, [hl] + inc hl ; BATTSTATUS2 + ld a, [hl] + ; clear USING_X_ACCURACY, PROTECTED_BY_MIST, GETTING_PUMPED, and SEEDED statuses + and $ff ^((1 << USING_X_ACCURACY) | (1 << PROTECTED_BY_MIST) | (1 << GETTING_PUMPED) | (1 << SEEDED)) + ld [hli], a ; BATTSTATUS3 + ld a, [hl] + and %11110000 | (1 << TRANSFORMED) ; clear Bad Poison, Reflect and Light Screen statuses + ld [hl], a + ret + +ResetStatMods: + ld b, $8 +.loop + ld [hli], a + dec b + jr nz, .loop + ret + +ResetStats: + ld b, $8 +.loop + ld a, [hli] + ld [de], a + inc de + dec b + jr nz, .loop + ret + +StatusChangesEliminatedText: + TX_FAR _StatusChangesEliminatedText + db "@" diff --git a/engine/battle/move_effects/heal.asm b/engine/battle/move_effects/heal.asm new file mode 100644 index 00000000..2e68acc0 --- /dev/null +++ b/engine/battle/move_effects/heal.asm @@ -0,0 +1,120 @@ +HealEffect_: + ld a, [H_WHOSETURN] + and a + ld de, wBattleMonHP + ld hl, wBattleMonMaxHP + ld a, [wPlayerMoveNum] + jr z, .healEffect + ld de, wEnemyMonHP + ld hl, wEnemyMonMaxHP + ld a, [wEnemyMoveNum] +.healEffect + ld b, a + ld a, [de] + cp [hl] ; most significant bytes comparison is ignored + ; causes the move to miss if max HP is 255 or 511 points higher than the current HP + inc de + inc hl + ld a, [de] + sbc [hl] + jp z, .failed ; no effect if user's HP is already at its maximum + ld a, b + cp REST + jr nz, .healHP + push hl + push de + push af + ld c, 50 + call DelayFrames + ld hl, wBattleMonStatus + ld a, [H_WHOSETURN] + and a + jr z, .restEffect + ld hl, wEnemyMonStatus +.restEffect + ld a, [hl] + and a + ld [hl], 2 ; clear status and set number of turns asleep to 2 + ld hl, StartedSleepingEffect ; if mon didn't have an status + jr z, .printRestText + ld hl, FellAsleepBecameHealthyText ; if mon had an status +.printRestText + call PrintText + pop af + pop de + pop hl +.healHP + ld a, [hld] + ld [wHPBarMaxHP], a + ld c, a + ld a, [hl] + ld [wHPBarMaxHP+1], a + ld b, a + jr z, .gotHPAmountToHeal +; Recover and Softboiled only heal for half the mon's max HP + srl b + rr c +.gotHPAmountToHeal +; update HP + ld a, [de] + ld [wHPBarOldHP], a + add c + ld [de], a + ld [wHPBarNewHP], a + dec de + ld a, [de] + ld [wHPBarOldHP+1], a + adc b + ld [de], a + ld [wHPBarNewHP+1], a + inc hl + inc de + ld a, [de] + dec de + sub [hl] + dec hl + ld a, [de] + sbc [hl] + jr c, .playAnim +; copy max HP to current HP if an overflow occurred + ld a, [hli] + ld [de], a + ld [wHPBarNewHP+1], a + inc de + ld a, [hl] + ld [de], a + ld [wHPBarNewHP], a +.playAnim + ld hl, PlayCurrentMoveAnimation + call BankswitchEtoF + ld a, [H_WHOSETURN] + and a + coord hl, 10, 9 + ld a, $1 + jr z, .updateHPBar + coord hl, 2, 2 + xor a +.updateHPBar + ld [wHPBarType], a + predef UpdateHPBar2 + ld hl, DrawHUDsAndHPBars + call BankswitchEtoF + ld hl, RegainedHealthText + jp PrintText +.failed + ld c, 50 + call DelayFrames + ld hl, PrintButItFailedText_ + jp BankswitchEtoF + +StartedSleepingEffect: + TX_FAR _StartedSleepingEffect + db "@" + +FellAsleepBecameHealthyText: + TX_FAR _FellAsleepBecameHealthyText + db "@" + +RegainedHealthText: + TX_FAR _RegainedHealthText + db "@" diff --git a/engine/battle/move_effects/leech_seed.asm b/engine/battle/move_effects/leech_seed.asm new file mode 100644 index 00000000..f4d3ee9c --- /dev/null +++ b/engine/battle/move_effects/leech_seed.asm @@ -0,0 +1,40 @@ +LeechSeedEffect_: + callab MoveHitTest + ld a, [wMoveMissed] + and a + jr nz, .moveMissed + ld hl, wEnemyBattleStatus2 + ld de, wEnemyMonType1 + ld a, [H_WHOSETURN] + and a + jr z, .leechSeedEffect + ld hl, wPlayerBattleStatus2 + ld de, wBattleMonType1 +.leechSeedEffect +; miss if the target is grass-type or already seeded + ld a, [de] + cp GRASS + jr z, .moveMissed + inc de + ld a, [de] + cp GRASS + jr z, .moveMissed + bit SEEDED, [hl] + jr nz, .moveMissed + set SEEDED, [hl] + callab PlayCurrentMoveAnimation + ld hl, WasSeededText + jp PrintText +.moveMissed + ld c, 50 + call DelayFrames + ld hl, EvadedAttackText + jp PrintText + +WasSeededText: + TX_FAR _WasSeededText + db "@" + +EvadedAttackText: + TX_FAR _EvadedAttackText + db "@" diff --git a/engine/battle/move_effects/mist.asm b/engine/battle/move_effects/mist.asm new file mode 100644 index 00000000..65070a3e --- /dev/null +++ b/engine/battle/move_effects/mist.asm @@ -0,0 +1,19 @@ +MistEffect_: + ld hl, wPlayerBattleStatus2 + ld a, [H_WHOSETURN] + and a + jr z, .mistEffect + ld hl, wEnemyBattleStatus2 +.mistEffect + bit PROTECTED_BY_MIST, [hl] ; is mon protected by mist? + jr nz, .mistAlreadyInUse + set PROTECTED_BY_MIST, [hl] ; mon is now protected by mist + callab PlayCurrentMoveAnimation + ld hl, ShroudedInMistText + jp PrintText +.mistAlreadyInUse + jpab PrintButItFailedText_ + +ShroudedInMistText: + TX_FAR _ShroudedInMistText + db "@" diff --git a/engine/battle/move_effects/one_hit_ko.asm b/engine/battle/move_effects/one_hit_ko.asm new file mode 100644 index 00000000..827e2197 --- /dev/null +++ b/engine/battle/move_effects/one_hit_ko.asm @@ -0,0 +1,38 @@ +OneHitKOEffect_: + ld hl, wDamage + xor a + ld [hli], a + ld [hl], a ; set the damage output to zero + dec a + ld [wCriticalHitOrOHKO], a + ld hl, wBattleMonSpeed + 1 + ld de, wEnemyMonSpeed + 1 + ld a, [H_WHOSETURN] + and a + jr z, .compareSpeed + ld hl, wEnemyMonSpeed + 1 + ld de, wBattleMonSpeed + 1 +.compareSpeed +; set damage to 65535 and OHKO flag is the user's current speed is higher than the target's + ld a, [de] + dec de + ld b, a + ld a, [hld] + sub b + ld a, [de] + ld b, a + ld a, [hl] + sbc b + jr c, .userIsSlower + ld hl, wDamage + ld a, $ff + ld [hli], a + ld [hl], a + ld a, $2 + ld [wCriticalHitOrOHKO], a + ret +.userIsSlower +; keep damage at 0 and set move missed flag if target's current speed is higher instead + ld a, $1 + ld [wMoveMissed], a + ret diff --git a/engine/battle/move_effects/paralyze.asm b/engine/battle/move_effects/paralyze.asm new file mode 100644 index 00000000..95979ae6 --- /dev/null +++ b/engine/battle/move_effects/paralyze.asm @@ -0,0 +1,47 @@ +ParalyzeEffect_: + ld hl, wEnemyMonStatus + ld de, wPlayerMoveType + ld a, [H_WHOSETURN] + and a + jp z, .next + ld hl, wBattleMonStatus + ld de, wEnemyMoveType +.next + ld a, [hl] + and a ; does the target already have a status ailment? + jr nz, .didntAffect +; check if the target is immune due to types + ld a, [de] + cp ELECTRIC + jr nz, .hitTest + ld b, h + ld c, l + inc bc + ld a, [bc] + cp GROUND + jr z, .doesntAffect + inc bc + ld a, [bc] + cp GROUND + jr z, .doesntAffect +.hitTest + push hl + callab MoveHitTest + pop hl + ld a, [wMoveMissed] + and a + jr nz, .didntAffect + set PAR, [hl] + callab QuarterSpeedDueToParalysis + ld c, 30 + call DelayFrames + callab PlayCurrentMoveAnimation + jpab PrintMayNotAttackText +.didntAffect + ld c, 50 + call DelayFrames + jpab PrintDidntAffectText +.doesntAffect + ld c, 50 + call DelayFrames + jpab PrintDoesntAffectText diff --git a/engine/battle/move_effects/pay_day.asm b/engine/battle/move_effects/pay_day.asm new file mode 100644 index 00000000..e5daf014 --- /dev/null +++ b/engine/battle/move_effects/pay_day.asm @@ -0,0 +1,45 @@ +PayDayEffect_: + xor a + ld hl, wcd6d + ld [hli], a + ld a, [H_WHOSETURN] + and a + ld a, [wBattleMonLevel] + jr z, .payDayEffect + ld a, [wEnemyMonLevel] +.payDayEffect +; level * 2 + add a + ld [H_DIVIDEND + 3], a + xor a + ld [H_DIVIDEND], a + ld [H_DIVIDEND + 1], a + ld [H_DIVIDEND + 2], a +; convert to BCD + ld a, 100 + ld [H_DIVISOR], a + ld b, $4 + call Divide + ld a, [H_QUOTIENT + 3] + ld [hli], a + ld a, [H_REMAINDER] + ld [H_DIVIDEND + 3], a + ld a, 10 + ld [H_DIVISOR], a + ld b, $4 + call Divide + ld a, [H_QUOTIENT + 3] + swap a + ld b, a + ld a, [H_REMAINDER] + add b + ld [hl], a + ld de, wTotalPayDayMoney + 2 + ld c, $3 + predef AddBCDPredef + ld hl, CoinsScatteredText + jp PrintText + +CoinsScatteredText: + TX_FAR _CoinsScatteredText + db "@" diff --git a/engine/battle/move_effects/recoil.asm b/engine/battle/move_effects/recoil.asm new file mode 100644 index 00000000..0f2f087b --- /dev/null +++ b/engine/battle/move_effects/recoil.asm @@ -0,0 +1,70 @@ +RecoilEffect_: + ld a, [H_WHOSETURN] + and a + ld a, [wPlayerMoveNum] + ld hl, wBattleMonMaxHP + jr z, .recoilEffect + ld a, [wEnemyMoveNum] + ld hl, wEnemyMonMaxHP +.recoilEffect + ld d, a + ld a, [wDamage] + ld b, a + ld a, [wDamage + 1] + ld c, a + srl b + rr c + ld a, d + cp STRUGGLE ; struggle deals 50% recoil damage + jr z, .gotRecoilDamage + srl b + rr c +.gotRecoilDamage + ld a, b + or c + jr nz, .updateHP + inc c ; minimum recoil damage is 1 +.updateHP +; subtract HP from user due to the recoil damage + ld a, [hli] + ld [wHPBarMaxHP+1], a + ld a, [hl] + ld [wHPBarMaxHP], a + push bc + ld bc, wBattleMonHP - wBattleMonMaxHP + add hl, bc + pop bc + ld a, [hl] + ld [wHPBarOldHP], a + sub c + ld [hld], a + ld [wHPBarNewHP], a + ld a, [hl] + ld [wHPBarOldHP+1], a + sbc b + ld [hl], a + ld [wHPBarNewHP+1], a + jr nc, .getHPBarCoords +; if recoil damage is higher than the Pokemon's HP, set its HP to 0 + xor a + ld [hli], a + ld [hl], a + ld hl, wHPBarNewHP + ld [hli], a + ld [hl], a +.getHPBarCoords + coord hl, 10, 9 + ld a, [H_WHOSETURN] + and a + ld a, $1 + jr z, .updateHPBar + coord hl, 2, 2 + xor a +.updateHPBar + ld [wHPBarType], a + predef UpdateHPBar2 + ld hl, HitWithRecoilText + jp PrintText +HitWithRecoilText: + TX_FAR _HitWithRecoilText + db "@" diff --git a/engine/battle/move_effects/reflect_light_screen.asm b/engine/battle/move_effects/reflect_light_screen.asm new file mode 100644 index 00000000..2805a969 --- /dev/null +++ b/engine/battle/move_effects/reflect_light_screen.asm @@ -0,0 +1,45 @@ +ReflectLightScreenEffect_: + ld hl, wPlayerBattleStatus3 + ld de, wPlayerMoveEffect + ld a, [H_WHOSETURN] + and a + jr z, .reflectLightScreenEffect + ld hl, wEnemyBattleStatus3 + ld de, wEnemyMoveEffect +.reflectLightScreenEffect + ld a, [de] + cp LIGHT_SCREEN_EFFECT + jr nz, .reflect + bit HAS_LIGHT_SCREEN_UP, [hl] ; is mon already protected by light screen? + jr nz, .moveFailed + set HAS_LIGHT_SCREEN_UP, [hl] ; mon is now protected by light screen + ld hl, LightScreenProtectedText + jr .playAnim +.reflect + bit HAS_REFLECT_UP, [hl] ; is mon already protected by reflect? + jr nz, .moveFailed + set HAS_REFLECT_UP, [hl] ; mon is now protected by reflect + ld hl, ReflectGainedArmorText +.playAnim + push hl + ld hl, PlayCurrentMoveAnimation + call BankswitchEtoF + pop hl + jp PrintText +.moveFailed + ld c, 50 + call DelayFrames + ld hl, PrintButItFailedText_ + jp BankswitchEtoF + +LightScreenProtectedText: + TX_FAR _LightScreenProtectedText + db "@" + +ReflectGainedArmorText: + TX_FAR _ReflectGainedArmorText + db "@" + +BankswitchEtoF: + ld b, BANK(BattleCore) + jp Bankswitch diff --git a/engine/battle/move_effects/substitute.asm b/engine/battle/move_effects/substitute.asm new file mode 100644 index 00000000..1bb6c887 --- /dev/null +++ b/engine/battle/move_effects/substitute.asm @@ -0,0 +1,77 @@ +SubstituteEffect_: + ld c, 50 + call DelayFrames + ld hl, wBattleMonMaxHP + ld de, wPlayerSubstituteHP + ld bc, wPlayerBattleStatus2 + ld a, [H_WHOSETURN] + and a + jr z, .notEnemy + ld hl, wEnemyMonMaxHP + ld de, wEnemySubstituteHP + ld bc, wEnemyBattleStatus2 +.notEnemy + ld a, [bc] + bit HAS_SUBSTITUTE_UP, a ; user already has substitute? + jr nz, .alreadyHasSubstitute +; quarter health to remove from user +; assumes max HP is 1023 or lower + push bc + ld a, [hli] + ld b, [hl] + srl a + rr b + srl a + rr b ; max hp / 4 + push de + ld de, wBattleMonHP - wBattleMonMaxHP + add hl, de ; point hl to current HP low byte + pop de + ld a, b + ld [de], a ; save copy of HP to subtract in wPlayerSubstituteHP/wEnemySubstituteHP + ld a, [hld] +; subtract [max hp / 4] to current HP + sub b + ld d, a + ld a, [hl] + sbc 0 + pop bc + jr c, .notEnoughHP ; underflow means user would be left with negative health + ; bug: since it only branches on carry, it will possibly leave user with 0 HP +.userHasZeroOrMoreHP + ldi [hl], a ; save resulting HP after subtraction into current HP + ld [hl], d + ld h, b + ld l, c + set HAS_SUBSTITUTE_UP, [hl] + ld a, [wOptions] + bit 7, a ; battle animation is enabled? + ld hl, PlayCurrentMoveAnimation + ld b, BANK(PlayCurrentMoveAnimation) + jr z, .animationEnabled + ld hl, AnimationSubstitute + ld b, BANK(AnimationSubstitute) +.animationEnabled + call Bankswitch ; jump to routine depending on animation setting + ld hl, SubstituteText + call PrintText + jpab DrawHUDsAndHPBars +.alreadyHasSubstitute + ld hl, HasSubstituteText + jr .printText +.notEnoughHP + ld hl, TooWeakSubstituteText +.printText + jp PrintText + +SubstituteText: + TX_FAR _SubstituteText + db "@" + +HasSubstituteText: + TX_FAR _HasSubstituteText + db "@" + +TooWeakSubstituteText: + TX_FAR _TooWeakSubstituteText + db "@" diff --git a/engine/battle/move_effects/transform.asm b/engine/battle/move_effects/transform.asm new file mode 100644 index 00000000..9a5de9cc --- /dev/null +++ b/engine/battle/move_effects/transform.asm @@ -0,0 +1,148 @@ +TransformEffect_: + ld hl, wBattleMonSpecies + ld de, wEnemyMonSpecies + ld bc, wEnemyBattleStatus3 + ld a, [wEnemyBattleStatus1] + ld a, [H_WHOSETURN] + and a + jr nz, .hitTest + ld hl, wEnemyMonSpecies + ld de, wBattleMonSpecies + ld bc, wPlayerBattleStatus3 + ld [wPlayerMoveListIndex], a + ld a, [wPlayerBattleStatus1] +.hitTest + bit INVULNERABLE, a ; is mon invulnerable to typical attacks? (fly/dig) + jp nz, .failed + push hl + push de + push bc + ld hl, wPlayerBattleStatus2 + ld a, [H_WHOSETURN] + and a + jr z, .transformEffect + ld hl, wEnemyBattleStatus2 +.transformEffect +; animation(s) played are different if target has Substitute up + bit HAS_SUBSTITUTE_UP, [hl] + push af + ld hl, HideSubstituteShowMonAnim + ld b, BANK(HideSubstituteShowMonAnim) + call nz, Bankswitch + ld a, [wOptions] + add a + ld hl, PlayCurrentMoveAnimation + ld b, BANK(PlayCurrentMoveAnimation) + jr nc, .gotAnimToPlay + ld hl, AnimationTransformMon + ld b, BANK(AnimationTransformMon) +.gotAnimToPlay + call Bankswitch + ld hl, ReshowSubstituteAnim + ld b, BANK(ReshowSubstituteAnim) + pop af + call nz, Bankswitch + pop bc + ld a, [bc] + set TRANSFORMED, a ; mon is now transformed + ld [bc], a + pop de + pop hl + push hl +; transform user into opposing Pokemon +; species + ld a, [hl] + ld [de], a +; type 1, type 2, catch rate, and moves + ld bc, $5 + add hl, bc + inc de + inc de + inc de + inc de + inc de + inc bc + inc bc + call CopyData + ld a, [H_WHOSETURN] + and a + jr z, .next +; save enemy mon DVs at wTransformedEnemyMonOriginalDVs + ld a, [de] + ld [wTransformedEnemyMonOriginalDVs], a + inc de + ld a, [de] + ld [wTransformedEnemyMonOriginalDVs + 1], a + dec de +.next +; DVs + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + inc de +; Attack, Defense, Speed, and Special stats + inc hl + inc hl + inc hl + inc de + inc de + inc de + ld bc, $8 + call CopyData + ld bc, wBattleMonMoves - wBattleMonPP + add hl, bc ; ld hl, wBattleMonMoves + ld b, NUM_MOVES +.copyPPLoop +; 5 PP for all moves + ld a, [hli] + 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 +.copyStats +; original (unmodified) stats and stat mods + pop hl + ld a, [hl] + ld [wd11e], a + call GetMonName + ld hl, wEnemyMonUnmodifiedAttack + ld de, wPlayerMonUnmodifiedAttack + call .copyBasedOnTurn ; original (unmodified) stats + ld hl, wEnemyMonStatMods + ld de, wPlayerMonStatMods + call .copyBasedOnTurn ; stat mods + ld hl, TransformedText + jp PrintText + +.copyBasedOnTurn + ld a, [H_WHOSETURN] + and a + jr z, .gotStatsOrModsToCopy + push hl + ld h, d + ld l, e + pop de +.gotStatsOrModsToCopy + ld bc, $8 + jp CopyData + +.failed + ld hl, PrintButItFailedText_ + jp BankswitchEtoF + +TransformedText: + TX_FAR _TransformedText + db "@" diff --git a/engine/battle/trainer_ai.asm b/engine/battle/trainer_ai.asm index 7755b50f..2850b9c2 100644 --- a/engine/battle/trainer_ai.asm +++ b/engine/battle/trainer_ai.asm @@ -279,7 +279,7 @@ INCLUDE "data/trainer_pic_money_pointers.asm" INCLUDE "text/trainer_names.asm" -INCLUDE "engine/battle/bank_e_misc.asm" +INCLUDE "engine/battle/misc.asm" INCLUDE "engine/battle/read_trainer_party.asm" diff --git a/engine/bcd.asm b/engine/bcd.asm deleted file mode 100644 index 2d0b43df..00000000 --- a/engine/bcd.asm +++ /dev/null @@ -1,214 +0,0 @@ -DivideBCDPredef:: -DivideBCDPredef2:: -DivideBCDPredef3:: -DivideBCDPredef4:: - call GetPredefRegisters - -DivideBCD:: - xor a - ld [hDivideBCDBuffer], a - ld [hDivideBCDBuffer+1], a - ld [hDivideBCDBuffer+2], a - ld d, $1 -.mulBy10Loop -; multiply the divisor by 10 until the leading digit is nonzero -; to set up the standard long division algorithm - ld a, [hDivideBCDDivisor] - and $f0 - jr nz, .next - inc d - ld a, [hDivideBCDDivisor] - swap a - and $f0 - ld b, a - ld a, [hDivideBCDDivisor+1] - swap a - ld [hDivideBCDDivisor+1], a - and $f - or b - ld [hDivideBCDDivisor], a - ld a, [hDivideBCDDivisor+1] - and $f0 - ld b, a - ld a, [hDivideBCDDivisor+2] - swap a - ld [hDivideBCDDivisor+2], a - and $f - or b - ld [hDivideBCDDivisor+1], a - ld a, [hDivideBCDDivisor+2] - and $f0 - ld [hDivideBCDDivisor+2], a - jr .mulBy10Loop -.next - push de - push de - call DivideBCD_getNextDigit - pop de - ld a, b - swap a - and $f0 - ld [hDivideBCDBuffer], a - dec d - jr z, .next2 - push de - call DivideBCD_divDivisorBy10 - call DivideBCD_getNextDigit - pop de - ld a, [hDivideBCDBuffer] - or b - ld [hDivideBCDBuffer], a - dec d - jr z, .next2 - push de - call DivideBCD_divDivisorBy10 - call DivideBCD_getNextDigit - pop de - ld a, b - swap a - and $f0 - ld [hDivideBCDBuffer+1], a - dec d - jr z, .next2 - push de - call DivideBCD_divDivisorBy10 - call DivideBCD_getNextDigit - pop de - ld a, [hDivideBCDBuffer+1] - or b - ld [hDivideBCDBuffer+1], a - dec d - jr z, .next2 - push de - call DivideBCD_divDivisorBy10 - call DivideBCD_getNextDigit - pop de - ld a, b - swap a - and $f0 - ld [hDivideBCDBuffer+2], a - dec d - jr z, .next2 - push de - call DivideBCD_divDivisorBy10 - call DivideBCD_getNextDigit - pop de - ld a, [hDivideBCDBuffer+2] - or b - ld [hDivideBCDBuffer+2], a -.next2 - ld a, [hDivideBCDBuffer] - ld [hDivideBCDQuotient], a ; the same memory location as hDivideBCDDivisor - ld a, [hDivideBCDBuffer+1] - ld [hDivideBCDQuotient+1], a - ld a, [hDivideBCDBuffer+2] - ld [hDivideBCDQuotient+2], a - pop de - ld a, $6 - sub d - and a - ret z -.divResultBy10loop - push af - call DivideBCD_divDivisorBy10 - pop af - dec a - jr nz, .divResultBy10loop - ret - -DivideBCD_divDivisorBy10: - ld a, [hDivideBCDDivisor+2] - swap a - and $f - ld b, a - ld a, [hDivideBCDDivisor+1] - swap a - ld [hDivideBCDDivisor+1], a - and $f0 - or b - ld [hDivideBCDDivisor+2], a - ld a, [hDivideBCDDivisor+1] - and $f - ld b, a - ld a, [hDivideBCDDivisor] - swap a - ld [hDivideBCDDivisor], a - and $f0 - or b - ld [hDivideBCDDivisor+1], a - ld a, [hDivideBCDDivisor] - and $f - ld [hDivideBCDDivisor], a - ret - -DivideBCD_getNextDigit: - ld bc, $3 -.loop - ld de, hMoney ; the dividend - ld hl, hDivideBCDDivisor - push bc - call StringCmp - pop bc - ret c - inc b - ld de, hMoney+2 ; since SubBCD works starting from the least significant digit - ld hl, hDivideBCDDivisor+2 - push bc - call SubBCD - pop bc - jr .loop - - -AddBCDPredef:: - call GetPredefRegisters - -AddBCD:: - and a - ld b, c -.add - ld a, [de] - adc [hl] - daa - ld [de], a - dec de - dec hl - dec c - jr nz, .add - jr nc, .done - ld a, $99 - inc de -.fill - ld [de], a - inc de - dec b - jr nz, .fill -.done - ret - - -SubBCDPredef:: - call GetPredefRegisters - -SubBCD:: - and a - ld b, c -.sub - ld a, [de] - sbc [hl] - daa - ld [de], a - dec de - dec hl - dec c - jr nz, .sub - jr nc, .done - ld a, $00 - inc de -.fill - ld [de], a - inc de - dec b - jr nz, .fill - scf -.done - ret diff --git a/engine/black_out.asm b/engine/black_out.asm deleted file mode 100644 index 6c358ce3..00000000 --- a/engine/black_out.asm +++ /dev/null @@ -1,46 +0,0 @@ -ResetStatusAndHalveMoneyOnBlackout:: -; Reset player status on blackout. - xor a - ld [wBattleResult], a - ld [wWalkBikeSurfState], a - ld [wIsInBattle], a - ld [wMapPalOffset], a - ld [wNPCMovementScriptFunctionNum], a - ld [hJoyHeld], a - ld [wNPCMovementScriptPointerTableNum], a - ld [wFlags_0xcd60], a - - ld [hMoney], a - ld [hMoney + 1], a - ld [hMoney + 2], a - call HasEnoughMoney - jr c, .lostmoney ; never happens - - ; Halve the player's money. - ld a, [wPlayerMoney] - ld [hMoney], a - ld a, [wPlayerMoney + 1] - ld [hMoney + 1], a - ld a, [wPlayerMoney + 2] - ld [hMoney + 2], a - xor a - ld [hDivideBCDDivisor], a - ld [hDivideBCDDivisor + 1], a - ld a, 2 - ld [hDivideBCDDivisor + 2], a - predef DivideBCDPredef3 - ld a, [hDivideBCDQuotient] - ld [wPlayerMoney], a - ld a, [hDivideBCDQuotient + 1] - ld [wPlayerMoney + 1], a - ld a, [hDivideBCDQuotient + 2] - ld [wPlayerMoney + 2], a - -.lostmoney - ld hl, wd732 - set 2, [hl] - res 3, [hl] - set 6, [hl] - ld a, %11111111 - ld [wJoyIgnore], a - predef_jump HealParty diff --git a/engine/cable_club.asm b/engine/cable_club.asm deleted file mode 100755 index 141ed396..00000000 --- a/engine/cable_club.asm +++ /dev/null @@ -1,977 +0,0 @@ -; performs the appropriate action when the player uses the gameboy on the table in the Colosseum or Trade Center -; In the Colosseum, it starts a battle. In the Trade Center, it displays the trade selection screen. -; Before doing either action, it swaps random numbers, trainer names and party data with the other gameboy. -CableClub_DoBattleOrTrade: - ld c, 80 - call DelayFrames - call ClearScreen - call UpdateSprites - call LoadFontTilePatterns - call LoadHpBarAndStatusTilePatterns - call LoadTrainerInfoTextBoxTiles - coord hl, 3, 8 - ld b, 2 - ld c, 12 - call CableClub_TextBoxBorder - coord hl, 4, 10 - ld de, PleaseWaitString - call PlaceString - ld hl, wPlayerNumHits - xor a - ld [hli], a - ld [hl], $50 - ; fall through - -; This is called after completing a trade. -CableClub_DoBattleOrTradeAgain: - ld hl, wSerialPlayerDataBlock - ld a, SERIAL_PREAMBLE_BYTE - ld b, 6 -.writePlayerDataBlockPreambleLoop - ld [hli], a - dec b - jr nz, .writePlayerDataBlockPreambleLoop - ld hl, wSerialRandomNumberListBlock - ld a, SERIAL_PREAMBLE_BYTE - ld b, 7 -.writeRandomNumberListPreambleLoop - ld [hli], a - dec b - jr nz, .writeRandomNumberListPreambleLoop - ld b, 10 -.generateRandomNumberListLoop - call Random - cp SERIAL_PREAMBLE_BYTE ; all the random numbers have to be less than the preamble byte - jr nc, .generateRandomNumberListLoop - ld [hli], a - dec b - jr nz, .generateRandomNumberListLoop - ld hl, wSerialPartyMonsPatchList - ld a, SERIAL_PREAMBLE_BYTE - ld [hli], a - ld [hli], a - ld [hli], a - ld b, $c8 - xor a -.zeroPlayerDataPatchListLoop - ld [hli], a - dec b - jr nz, .zeroPlayerDataPatchListLoop - ld hl, wGrassRate - ld bc, wTrainerHeaderPtr - wGrassRate -.zeroEnemyPartyLoop - xor a - ld [hli], a - dec bc - ld a, b - or c - jr nz, .zeroEnemyPartyLoop - ld hl, wPartyMons - 1 - ld de, wSerialPartyMonsPatchList + 10 - ld bc, 0 -.patchPartyMonsLoop - inc c - ld a, c - cp SERIAL_PREAMBLE_BYTE - jr z, .startPatchListPart2 - ld a, b - dec a ; are we in part 2 of the patch list? - jr nz, .checkPlayerDataByte ; jump if in part 1 -; if we're in part 2 - ld a, c - cp (wPartyMonOT - (wPartyMons - 1)) - (SERIAL_PREAMBLE_BYTE - 1) - jr z, .finishedPatchingPlayerData -.checkPlayerDataByte - inc hl - ld a, [hl] - cp SERIAL_NO_DATA_BYTE - jr nz, .patchPartyMonsLoop -; if the player data byte matches SERIAL_NO_DATA_BYTE, patch it with $FF and record the offset in the patch list - ld a, c - ld [de], a - inc de - ld [hl], $ff - jr .patchPartyMonsLoop -.startPatchListPart2 - ld a, SERIAL_PATCH_LIST_PART_TERMINATOR - ld [de], a ; end of part 1 - inc de - lb bc, 1, 0 - jr .patchPartyMonsLoop -.finishedPatchingPlayerData - ld a, SERIAL_PATCH_LIST_PART_TERMINATOR - ld [de], a ; end of part 2 - call Serial_SyncAndExchangeNybble - ld a, [hSerialConnectionStatus] - cp USING_INTERNAL_CLOCK - jr nz, .skipSendingTwoZeroBytes -; if using internal clock -; send two zero bytes for syncing purposes? - call Delay3 - xor a - ld [hSerialSendData], a - ld a, START_TRANSFER_INTERNAL_CLOCK - ld [rSC], a - call DelayFrame - xor a - ld [hSerialSendData], a - ld a, START_TRANSFER_INTERNAL_CLOCK - ld [rSC], a -.skipSendingTwoZeroBytes - call Delay3 - ld a, (1 << SERIAL) - ld [rIE], a - ld hl, wSerialRandomNumberListBlock - ld de, wSerialOtherGameboyRandomNumberListBlock - ld bc, $11 - call Serial_ExchangeBytes - ld a, SERIAL_NO_DATA_BYTE - ld [de], a - ld hl, wSerialPlayerDataBlock - ld de, wSerialEnemyDataBlock - ld bc, $1a8 - call Serial_ExchangeBytes - ld a, SERIAL_NO_DATA_BYTE - ld [de], a - ld hl, wSerialPartyMonsPatchList - ld de, wSerialEnemyMonsPatchList - ld bc, $c8 - call Serial_ExchangeBytes - ld a, (1 << SERIAL) | (1 << TIMER) | (1 << VBLANK) - ld [rIE], a - ld a, $ff - call PlaySound - ld a, [hSerialConnectionStatus] - cp USING_INTERNAL_CLOCK - jr z, .skipCopyingRandomNumberList ; the list generated by the gameboy clocking the connection is used by both gameboys - ld hl, wSerialOtherGameboyRandomNumberListBlock -.findStartOfRandomNumberListLoop - ld a, [hli] - and a - jr z, .findStartOfRandomNumberListLoop - cp SERIAL_PREAMBLE_BYTE - jr z, .findStartOfRandomNumberListLoop - cp SERIAL_NO_DATA_BYTE - jr z, .findStartOfRandomNumberListLoop - dec hl - ld de, wLinkBattleRandomNumberList - ld c, 10 -.copyRandomNumberListLoop - ld a, [hli] - cp SERIAL_NO_DATA_BYTE - jr z, .copyRandomNumberListLoop - ld [de], a - inc de - dec c - jr nz, .copyRandomNumberListLoop -.skipCopyingRandomNumberList - ld hl, wSerialEnemyDataBlock + 3 -.findStartOfEnemyNameLoop - ld a, [hli] - and a - jr z, .findStartOfEnemyNameLoop - cp SERIAL_PREAMBLE_BYTE - jr z, .findStartOfEnemyNameLoop - cp SERIAL_NO_DATA_BYTE - jr z, .findStartOfEnemyNameLoop - dec hl - ld de, wLinkEnemyTrainerName - ld c, NAME_LENGTH -.copyEnemyNameLoop - ld a, [hli] - cp SERIAL_NO_DATA_BYTE - jr z, .copyEnemyNameLoop - ld [de], a - inc de - dec c - jr nz, .copyEnemyNameLoop - ld de, wEnemyPartyCount - ld bc, wTrainerHeaderPtr - wEnemyPartyCount -.copyEnemyPartyLoop - ld a, [hli] - cp SERIAL_NO_DATA_BYTE - jr z, .copyEnemyPartyLoop - ld [de], a - inc de - dec bc - ld a, b - or c - jr nz, .copyEnemyPartyLoop - ld de, wSerialPartyMonsPatchList - ld hl, wPartyMons - ld c, 2 ; patch list has 2 parts -.unpatchPartyMonsLoop - ld a, [de] - inc de - and a - jr z, .unpatchPartyMonsLoop - cp SERIAL_PREAMBLE_BYTE - jr z, .unpatchPartyMonsLoop - cp SERIAL_NO_DATA_BYTE - jr z, .unpatchPartyMonsLoop - cp SERIAL_PATCH_LIST_PART_TERMINATOR - jr z, .finishedPartyMonsPatchListPart - push hl - push bc - ld b, 0 - dec a - ld c, a - add hl, bc - ld a, SERIAL_NO_DATA_BYTE - ld [hl], a - pop bc - pop hl - jr .unpatchPartyMonsLoop -.finishedPartyMonsPatchListPart - ld hl, wPartyMons + (SERIAL_PREAMBLE_BYTE - 1) - dec c ; is there another part? - jr nz, .unpatchPartyMonsLoop - ld de, wSerialEnemyMonsPatchList - ld hl, wEnemyMons - ld c, 2 ; patch list has 2 parts -.unpatchEnemyMonsLoop - ld a, [de] - inc de - and a - jr z, .unpatchEnemyMonsLoop - cp SERIAL_PREAMBLE_BYTE - jr z, .unpatchEnemyMonsLoop - cp SERIAL_NO_DATA_BYTE - jr z, .unpatchEnemyMonsLoop - cp SERIAL_PATCH_LIST_PART_TERMINATOR - jr z, .finishedEnemyMonsPatchListPart - push hl - push bc - ld b, 0 - dec a - ld c, a - add hl, bc - ld a, SERIAL_NO_DATA_BYTE - ld [hl], a - pop bc - pop hl - jr .unpatchEnemyMonsLoop -.finishedEnemyMonsPatchListPart - ld hl, wEnemyMons + (SERIAL_PREAMBLE_BYTE - 1) - dec c - jr nz, .unpatchEnemyMonsLoop - ld a, wEnemyMonOT % $100 - ld [wUnusedCF8D], a - ld a, wEnemyMonOT / $100 - ld [wUnusedCF8D + 1], a - xor a - ld [wTradeCenterPointerTableIndex], a - ld a, $ff - call PlaySound - ld a, [hSerialConnectionStatus] - cp USING_INTERNAL_CLOCK - ld c, 66 - call z, DelayFrames ; delay if using internal clock - ld a, [wLinkState] - cp LINK_STATE_START_BATTLE - ld a, LINK_STATE_TRADING - ld [wLinkState], a - jr nz, .trading - ld a, LINK_STATE_BATTLING - ld [wLinkState], a - ld a, OPP_SONY1 - ld [wCurOpponent], a - call ClearScreen - call Delay3 - ld hl, wOptions - res 7, [hl] - predef InitOpponent - predef HealParty - jp ReturnToCableClubRoom -.trading - ld c, BANK(Music_GameCorner) - ld a, MUSIC_GAME_CORNER - call PlayMusic - jr CallCurrentTradeCenterFunction - -PleaseWaitString: - db "PLEASE WAIT!@" - -CallCurrentTradeCenterFunction: - ld hl, TradeCenterPointerTable - ld b, 0 - ld a, [wTradeCenterPointerTableIndex] - cp $ff - jp z, DisplayTitleScreen - add a - ld c, a - add hl, bc - ld a, [hli] - ld h, [hl] - ld l, a - jp hl - -TradeCenter_SelectMon: - call ClearScreen - call LoadTrainerInfoTextBoxTiles - call TradeCenter_DrawPartyLists - call TradeCenter_DrawCancelBox - xor a - ld hl, wSerialSyncAndExchangeNybbleReceiveData - ld [hli], a - ld [hli], a - ld [hli], a - ld [hl], a - ld [wMenuWatchMovingOutOfBounds], a - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - ld [wMenuJoypadPollCount], a - inc a - ld [wSerialExchangeNybbleSendData], a - jp .playerMonMenu -.enemyMonMenu - xor a - ld [wMenuWatchMovingOutOfBounds], a - inc a - ld [wWhichTradeMonSelectionMenu], a - ld a, D_DOWN | D_LEFT | A_BUTTON - ld [wMenuWatchedKeys], a - ld a, [wEnemyPartyCount] - ld [wMaxMenuItem], a - ld a, 9 - ld [wTopMenuItemY], a - ld a, 1 - ld [wTopMenuItemX], a -.enemyMonMenu_HandleInput - ld hl, hFlags_0xFFF6 - set 1, [hl] - call HandleMenuInput - ld hl, hFlags_0xFFF6 - res 1, [hl] - and a - jp z, .getNewInput - bit 0, a ; A button pressed? - jr z, .enemyMonMenu_ANotPressed -; if A button pressed - ld a, [wMaxMenuItem] - ld c, a - ld a, [wCurrentMenuItem] - cp c - jr c, .displayEnemyMonStats - ld a, [wMaxMenuItem] - dec a - ld [wCurrentMenuItem], a -.displayEnemyMonStats - ld a, INIT_ENEMYOT_LIST - ld [wInitListType], a - callab InitList ; the list isn't used - ld hl, wEnemyMons - call TradeCenter_DisplayStats - jp .getNewInput -.enemyMonMenu_ANotPressed - bit 5, a ; Left pressed? - jr z, .enemyMonMenu_LeftNotPressed -; if Left pressed, switch back to the player mon menu - xor a ; player mon menu - ld [wWhichTradeMonSelectionMenu], a - ld a, [wMenuCursorLocation] - ld l, a - ld a, [wMenuCursorLocation + 1] - ld h, a - ld a, [wTileBehindCursor] - ld [hl], a - ld a, [wCurrentMenuItem] - ld b, a - ld a, [wPartyCount] - dec a - cp b - jr nc, .playerMonMenu - ld [wCurrentMenuItem], a - jr .playerMonMenu -.enemyMonMenu_LeftNotPressed - bit 7, a ; Down pressed? - jp z, .getNewInput - jp .selectedCancelMenuItem ; jump if Down pressed -.playerMonMenu - xor a ; player mon menu - ld [wWhichTradeMonSelectionMenu], a - ld [wMenuWatchMovingOutOfBounds], a - ld a, D_DOWN | D_RIGHT | A_BUTTON - ld [wMenuWatchedKeys], a - ld a, [wPartyCount] - ld [wMaxMenuItem], a - ld a, 1 - ld [wTopMenuItemY], a - ld a, 1 - ld [wTopMenuItemX], a - coord hl, 1, 1 - lb bc, 6, 1 - call ClearScreenArea -.playerMonMenu_HandleInput - ld hl, hFlags_0xFFF6 - set 1, [hl] - call HandleMenuInput - ld hl, hFlags_0xFFF6 - res 1, [hl] - and a ; was anything pressed? - jr nz, .playerMonMenu_SomethingPressed - jp .getNewInput -.playerMonMenu_SomethingPressed - bit 0, a ; A button pressed? - jr z, .playerMonMenu_ANotPressed - jp .chosePlayerMon ; jump if A button pressed -; unreachable code - ld a, INIT_PLAYEROT_LIST - ld [wInitListType], a - callab InitList ; the list isn't used - call TradeCenter_DisplayStats - jp .getNewInput -.playerMonMenu_ANotPressed - bit 4, a ; Right pressed? - jr z, .playerMonMenu_RightNotPressed -; if Right pressed, switch to the enemy mon menu - ld a, $1 ; enemy mon menu - ld [wWhichTradeMonSelectionMenu], a - ld a, [wMenuCursorLocation] - ld l, a - ld a, [wMenuCursorLocation + 1] - ld h, a - ld a, [wTileBehindCursor] - ld [hl], a - ld a, [wCurrentMenuItem] - ld b, a - ld a, [wEnemyPartyCount] - dec a - cp b - jr nc, .notPastLastEnemyMon -; when switching to the enemy mon menu, if the menu selection would be past the last enemy mon, select the last enemy mon - ld [wCurrentMenuItem], a -.notPastLastEnemyMon - jp .enemyMonMenu -.playerMonMenu_RightNotPressed - bit 7, a ; Down pressed? - jr z, .getNewInput - jp .selectedCancelMenuItem ; jump if Down pressed -.getNewInput - ld a, [wWhichTradeMonSelectionMenu] - and a - jp z, .playerMonMenu_HandleInput - jp .enemyMonMenu_HandleInput -.chosePlayerMon - call SaveScreenTilesToBuffer1 - call PlaceUnfilledArrowMenuCursor - ld a, [wMaxMenuItem] - ld c, a - ld a, [wCurrentMenuItem] - cp c - jr c, .displayStatsTradeMenu - ld a, [wMaxMenuItem] - dec a -.displayStatsTradeMenu - push af - coord hl, 0, 14 - ld b, 2 - ld c, 18 - call CableClub_TextBoxBorder - coord hl, 2, 16 - ld de, .statsTrade - call PlaceString - xor a - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - ld [wMenuJoypadPollCount], a - ld [wMaxMenuItem], a - ld a, 16 - ld [wTopMenuItemY], a -.selectStatsMenuItem - ld a, " " - Coorda 11, 16 - ld a, D_RIGHT | B_BUTTON | A_BUTTON - ld [wMenuWatchedKeys], a - ld a, 1 - ld [wTopMenuItemX], a - call HandleMenuInput - bit 4, a ; Right pressed? - jr nz, .selectTradeMenuItem - bit 1, a ; B button pressed? - jr z, .displayPlayerMonStats -.cancelPlayerMonChoice - pop af - ld [wCurrentMenuItem], a - call LoadScreenTilesFromBuffer1 - jp .playerMonMenu -.selectTradeMenuItem - ld a, " " - Coorda 1, 16 - ld a, D_LEFT | B_BUTTON | A_BUTTON - ld [wMenuWatchedKeys], a - ld a, 11 - ld [wTopMenuItemX], a - call HandleMenuInput - bit 5, a ; Left pressed? - jr nz, .selectStatsMenuItem - bit 1, a ; B button pressed? - jr nz, .cancelPlayerMonChoice - jr .choseTrade -.displayPlayerMonStats - pop af - ld [wCurrentMenuItem], a - ld a, INIT_PLAYEROT_LIST - ld [wInitListType], a - callab InitList ; the list isn't used - call TradeCenter_DisplayStats - call LoadScreenTilesFromBuffer1 - jp .playerMonMenu -.choseTrade - call PlaceUnfilledArrowMenuCursor - pop af - ld [wCurrentMenuItem], a - ld [wTradingWhichPlayerMon], a - ld [wSerialExchangeNybbleSendData], a - call Serial_PrintWaitingTextAndSyncAndExchangeNybble - ld a, [wSerialSyncAndExchangeNybbleReceiveData] - cp $f - jp z, CallCurrentTradeCenterFunction ; go back to the beginning of the trade selection menu if the other person cancelled - ld [wTradingWhichEnemyMon], a - call TradeCenter_PlaceSelectedEnemyMonMenuCursor - ld a, $1 ; TradeCenter_Trade - ld [wTradeCenterPointerTableIndex], a - jp CallCurrentTradeCenterFunction -.statsTrade - db "STATS TRADE@" -.selectedCancelMenuItem - ld a, [wCurrentMenuItem] - ld b, a - ld a, [wMaxMenuItem] - cp b - jp nz, .getNewInput - ld a, [wMenuCursorLocation] - ld l, a - ld a, [wMenuCursorLocation + 1] - ld h, a - ld a, " " - ld [hl], a -.cancelMenuItem_Loop - ld a, "▶" ; filled arrow cursor - Coorda 1, 16 -.cancelMenuItem_JoypadLoop - call JoypadLowSensitivity - ld a, [hJoy5] - and a ; pressed anything? - jr z, .cancelMenuItem_JoypadLoop - bit 0, a ; A button pressed? - jr nz, .cancelMenuItem_APressed - bit 6, a ; Up pressed? - jr z, .cancelMenuItem_JoypadLoop -; if Up pressed - ld a, " " - Coorda 1, 16 - ld a, [wPartyCount] - dec a - ld [wCurrentMenuItem], a - jp .playerMonMenu -.cancelMenuItem_APressed - ld a, "▷" ; unfilled arrow cursor - Coorda 1, 16 - ld a, $f - ld [wSerialExchangeNybbleSendData], a - call Serial_PrintWaitingTextAndSyncAndExchangeNybble - ld a, [wSerialSyncAndExchangeNybbleReceiveData] - cp $f ; did the other person choose Cancel too? - jr nz, .cancelMenuItem_Loop - ; fall through - -ReturnToCableClubRoom: - call GBPalWhiteOutWithDelay3 - ld hl, wFontLoaded - ld a, [hl] - push af - push hl - res 0, [hl] - xor a - ld [wd72d], a - dec a - ld [wDestinationWarpID], a - call LoadMapData - callba ClearVariablesOnEnterMap - pop hl - pop af - ld [hl], a - call GBFadeInFromWhite - ret - -TradeCenter_DrawCancelBox: - coord hl, 11, 15 - ld a, $7e - ld bc, 2 * SCREEN_WIDTH + 9 - call FillMemory - coord hl, 0, 15 - ld b, 1 - ld c, 9 - call CableClub_TextBoxBorder - coord hl, 2, 16 - ld de, CancelTextString - jp PlaceString - -CancelTextString: - db "CANCEL@" - -TradeCenter_PlaceSelectedEnemyMonMenuCursor: - ld a, [wSerialSyncAndExchangeNybbleReceiveData] - coord hl, 1, 9 - ld bc, SCREEN_WIDTH - call AddNTimes - ld [hl], "▷" ; cursor - ret - -TradeCenter_DisplayStats: - ld a, [wCurrentMenuItem] - ld [wWhichPokemon], a - predef StatusScreen - predef StatusScreen2 - call GBPalNormal - call LoadTrainerInfoTextBoxTiles - call TradeCenter_DrawPartyLists - jp TradeCenter_DrawCancelBox - -TradeCenter_DrawPartyLists: - coord hl, 0, 0 - ld b, 6 - ld c, 18 - call CableClub_TextBoxBorder - coord hl, 0, 8 - ld b, 6 - ld c, 18 - call CableClub_TextBoxBorder - coord hl, 5, 0 - ld de, wPlayerName - call PlaceString - coord hl, 5, 8 - ld de, wLinkEnemyTrainerName - call PlaceString - coord hl, 2, 1 - ld de, wPartySpecies - call TradeCenter_PrintPartyListNames - coord hl, 2, 9 - ld de, wEnemyPartyMons - ; fall through - -TradeCenter_PrintPartyListNames: - ld c, $0 -.loop - ld a, [de] - cp $ff - ret z - ld [wd11e], a - push bc - push hl - push de - push hl - ld a, c - ld [$ff95], a - call GetMonName - pop hl - call PlaceString - pop de - inc de - pop hl - ld bc, 20 - add hl, bc - pop bc - inc c - jr .loop - -TradeCenter_Trade: - ld c, 100 - call DelayFrames - xor a - ld [wSerialExchangeNybbleSendData + 1], a ; unnecessary - ld [wSerialExchangeNybbleReceiveData], a - ld [wMenuWatchMovingOutOfBounds], a - ld [wMenuJoypadPollCount], a - coord hl, 0, 12 - ld b, 4 - ld c, 18 - call CableClub_TextBoxBorder - ld a, [wTradingWhichPlayerMon] - ld hl, wPartySpecies - ld c, a - ld b, 0 - add hl, bc - ld a, [hl] - ld [wd11e], a - call GetMonName - ld hl, wcd6d - ld de, wNameOfPlayerMonToBeTraded - ld bc, NAME_LENGTH - call CopyData - ld a, [wTradingWhichEnemyMon] - ld hl, wEnemyPartyMons - ld c, a - ld b, 0 - add hl, bc - ld a, [hl] - ld [wd11e], a - call GetMonName - ld hl, WillBeTradedText - coord bc, 1, 14 - call TextCommandProcessor - call SaveScreenTilesToBuffer1 - coord hl, 10, 7 - lb bc, 8, 11 - ld a, TRADE_CANCEL_MENU - ld [wTwoOptionMenuID], a - ld a, TWO_OPTION_MENU - ld [wTextBoxID], a - call DisplayTextBoxID - call LoadScreenTilesFromBuffer1 - ld a, [wCurrentMenuItem] - and a - jr z, .tradeConfirmed -; if trade cancelled - ld a, $1 - ld [wSerialExchangeNybbleSendData], a - coord hl, 0, 12 - ld b, 4 - ld c, 18 - call CableClub_TextBoxBorder - coord hl, 1, 14 - ld de, TradeCanceled - call PlaceString - call Serial_PrintWaitingTextAndSyncAndExchangeNybble - jp .tradeCancelled -.tradeConfirmed - ld a, $2 - ld [wSerialExchangeNybbleSendData], a - call Serial_PrintWaitingTextAndSyncAndExchangeNybble - ld a, [wSerialSyncAndExchangeNybbleReceiveData] - dec a ; did the other person cancel? - jr nz, .doTrade -; if the other person cancelled - coord hl, 0, 12 - ld b, 4 - ld c, 18 - call CableClub_TextBoxBorder - coord hl, 1, 14 - ld de, TradeCanceled - call PlaceString - jp .tradeCancelled -.doTrade - ld a, [wTradingWhichPlayerMon] - ld hl, wPartyMonOT - call SkipFixedLengthTextEntries - ld de, wTradedPlayerMonOT - ld bc, NAME_LENGTH - call CopyData - ld hl, wPartyMon1Species - ld a, [wTradingWhichPlayerMon] - ld bc, wPartyMon2 - wPartyMon1 - call AddNTimes - ld bc, wPartyMon1OTID - wPartyMon1 - add hl, bc - ld a, [hli] - ld [wTradedPlayerMonOTID], a - ld a, [hl] - ld [wTradedPlayerMonOTID + 1], a - ld a, [wTradingWhichEnemyMon] - ld hl, wEnemyMonOT - call SkipFixedLengthTextEntries - ld de, wTradedEnemyMonOT - ld bc, NAME_LENGTH - call CopyData - ld hl, wEnemyMons - ld a, [wTradingWhichEnemyMon] - ld bc, wEnemyMon2 - wEnemyMon1 - call AddNTimes - ld bc, wEnemyMon1OTID - wEnemyMon1 - add hl, bc - ld a, [hli] - ld [wTradedEnemyMonOTID], a - ld a, [hl] - ld [wTradedEnemyMonOTID + 1], a - ld a, [wTradingWhichPlayerMon] - ld [wWhichPokemon], a - ld hl, wPartySpecies - ld b, 0 - ld c, a - add hl, bc - ld a, [hl] - ld [wTradedPlayerMonSpecies], a - xor a - ld [wRemoveMonFromBox], a - call RemovePokemon - ld a, [wTradingWhichEnemyMon] - ld c, a - ld [wWhichPokemon], a - ld hl, wEnemyPartyMons - ld d, 0 - ld e, a - add hl, de - ld a, [hl] - ld [wcf91], a - ld hl, wEnemyMons - ld a, c - ld bc, wEnemyMon2 - wEnemyMon1 - call AddNTimes - ld de, wLoadedMon - ld bc, wEnemyMon2 - wEnemyMon1 - call CopyData - call AddEnemyMonToPlayerParty - ld a, [wPartyCount] - dec a - ld [wWhichPokemon], a - ld a, $1 - ld [wForceEvolution], a - ld a, [wTradingWhichEnemyMon] - ld hl, wEnemyPartyMons - ld b, 0 - ld c, a - add hl, bc - ld a, [hl] - ld [wTradedEnemyMonSpecies], a - ld a, 10 - ld [wAudioFadeOutControl], a - ld a, BANK(Music_SafariZone) - ld [wAudioSavedROMBank], a - ld a, MUSIC_SAFARI_ZONE - ld [wNewSoundID], a - call PlaySound - ld c, 100 - call DelayFrames - call ClearScreen - call LoadHpBarAndStatusTilePatterns - xor a - ld [wUnusedCC5B], a - ld a, [hSerialConnectionStatus] - cp USING_EXTERNAL_CLOCK - jr z, .usingExternalClock - predef InternalClockTradeAnim - jr .tradeCompleted -.usingExternalClock - predef ExternalClockTradeAnim -.tradeCompleted - callab TryEvolvingMon - call ClearScreen - call LoadTrainerInfoTextBoxTiles - call Serial_PrintWaitingTextAndSyncAndExchangeNybble - ld c, 40 - call DelayFrames - coord hl, 0, 12 - ld b, 4 - ld c, 18 - call CableClub_TextBoxBorder - coord hl, 1, 14 - ld de, TradeCompleted - call PlaceString - predef SaveSAVtoSRAM2 - ld c, 50 - call DelayFrames - xor a - ld [wTradeCenterPointerTableIndex], a - jp CableClub_DoBattleOrTradeAgain -.tradeCancelled - ld c, 100 - call DelayFrames - xor a ; TradeCenter_SelectMon - ld [wTradeCenterPointerTableIndex], a - jp CallCurrentTradeCenterFunction - -WillBeTradedText: - TX_FAR _WillBeTradedText - db "@" - -TradeCompleted: - db "Trade completed!@" - -TradeCanceled: - db "Too bad! The trade" - next "was canceled!@" - -TradeCenterPointerTable: - dw TradeCenter_SelectMon - dw TradeCenter_Trade - -CableClub_Run: - ld a, [wLinkState] - cp LINK_STATE_START_TRADE - jr z, .doBattleOrTrade - cp LINK_STATE_START_BATTLE - jr z, .doBattleOrTrade - cp LINK_STATE_RESET ; this is never used - ret nz - predef EmptyFunc3 - jp Init -.doBattleOrTrade - call CableClub_DoBattleOrTrade - ld hl, Club_GFX - ld a, h - ld [wTilesetGfxPtr + 1], a - ld a, l - ld [wTilesetGfxPtr], a - ld a, Bank(Club_GFX) - ld [wTilesetBank], a - ld hl, Club_Coll - ld a, h - ld [wTilesetCollisionPtr + 1], a - ld a, l - ld [wTilesetCollisionPtr], a - xor a - ld [wGrassRate], a - inc a ; LINK_STATE_IN_CABLE_CLUB - ld [wLinkState], a - ld [hJoy5], a - ld a, 10 - ld [wAudioFadeOutControl], a - ld a, BANK(Music_Celadon) - ld [wAudioSavedROMBank], a - ld a, MUSIC_CELADON - ld [wNewSoundID], a - jp PlaySound - -EmptyFunc3: - ret - -Diploma_TextBoxBorder: - call GetPredefRegisters - -; b = height -; c = width -CableClub_TextBoxBorder: - push hl - ld a, $78 ; border upper left corner tile - ld [hli], a - inc a ; border top horizontal line tile - call CableClub_DrawHorizontalLine - inc a ; border upper right corner tile - ld [hl], a - pop hl - ld de, 20 - add hl, de -.loop - push hl - ld a, $7b ; border left vertical line tile - ld [hli], a - ld a, " " - call CableClub_DrawHorizontalLine - ld [hl], $77 ; border right vertical line tile - pop hl - ld de, 20 - add hl, de - dec b - jr nz, .loop - ld a, $7c ; border lower left corner tile - ld [hli], a - ld a, $76 ; border bottom horizontal line tile - call CableClub_DrawHorizontalLine - ld [hl], $7d ; border lower right corner tile - ret - -; c = width -CableClub_DrawHorizontalLine: - ld d, c -.loop - ld [hli], a - dec d - jr nz, .loop - ret - -LoadTrainerInfoTextBoxTiles: - ld de, TrainerInfoTextBoxTileGraphics - ld hl, vChars2 + $760 - lb bc, BANK(TrainerInfoTextBoxTileGraphics), (TrainerInfoTextBoxTileGraphicsEnd - TrainerInfoTextBoxTileGraphics) / $10 - jp CopyVideoData diff --git a/engine/clear_save.asm b/engine/clear_save.asm deleted file mode 100755 index b47cd6c4..00000000 --- a/engine/clear_save.asm +++ /dev/null @@ -1,23 +0,0 @@ -DoClearSaveDialogue: - call ClearScreen - call RunDefaultPaletteCommand - call LoadFontTilePatterns - call LoadTextBoxTilePatterns - ld hl, ClearSaveDataText - call PrintText - coord hl, 14, 7 - lb bc, 8, 15 - ld a, NO_YES_MENU - ld [wTwoOptionMenuID], a - ld a, TWO_OPTION_MENU - ld [wTextBoxID], a - call DisplayTextBoxID - ld a, [wCurrentMenuItem] - and a - jp z, Init - callba ClearSAV - jp Init - -ClearSaveDataText: - TX_FAR _ClearSaveDataText - db "@" diff --git a/engine/debug/debug_party.asm b/engine/debug/debug_party.asm new file mode 100644 index 00000000..a5eb7dde --- /dev/null +++ b/engine/debug/debug_party.asm @@ -0,0 +1,33 @@ +; This function appears to never be used. +; It is likely a debugging feature to give the player Tsunekazu Ishihara's +; favorite Pokemon. This is indicated by the overpowered Exeggutor, which +; Ishihara (president of Creatures Inc.) said was his favorite Pokemon in an ABC +; interview on February 8, 2000. +; "Exeggutor is my favorite. That's because I was always using this character +; while I was debugging the program." +; http://www.ign.com/articles/2000/02/09/abc-news-pokamon-chat-transcript + +SetIshiharaTeam: + ld de, IshiharaTeam +.loop + ld a, [de] + cp $ff + ret z + ld [wcf91], a + inc de + ld a, [de] + ld [wCurEnemyLVL], a + inc de + call AddPartyMon + jr .loop + +IshiharaTeam: + db EXEGGUTOR,90 + db MEW,20 + db JOLTEON,56 + db DUGTRIO,56 + db ARTICUNO,57 + db $FF + +EmptyFunc: + ret diff --git a/engine/debug/test_battle.asm b/engine/debug/test_battle.asm new file mode 100644 index 00000000..d9dcf1fa --- /dev/null +++ b/engine/debug/test_battle.asm @@ -0,0 +1,45 @@ +TestBattle: + ret + +.loop + call GBPalNormal + + ; Don't mess around + ; with obedience. + ld a, %10000000 ; EARTHBADGE + ld [wObtainedBadges], a + + ld hl, wFlags_D733 + set BIT_TEST_BATTLE, [hl] + + ; Reset the party. + ld hl, wPartyCount + xor a + ld [hli], a + dec a + ld [hl], a + + ; Give the player a + ; level 20 Rhydon. + ld a, RHYDON + ld [wcf91], a + ld a, 20 + ld [wCurEnemyLVL], a + xor a + ld [wMonDataLocation], a + ld [wCurMap], a + call AddPartyMon + + ; Fight against a + ; level 20 Rhydon. + ld a, RHYDON + ld [wCurOpponent], a + + predef InitOpponent + + ; When the battle ends, + ; do it all again. + ld a, 1 + ld [wUpdateSpritesEnabled], a + ld [H_AUTOBGTRANSFERENABLED], a + jr .loop diff --git a/engine/debug1.asm b/engine/debug1.asm deleted file mode 100644 index a5eb7dde..00000000 --- a/engine/debug1.asm +++ /dev/null @@ -1,33 +0,0 @@ -; This function appears to never be used. -; It is likely a debugging feature to give the player Tsunekazu Ishihara's -; favorite Pokemon. This is indicated by the overpowered Exeggutor, which -; Ishihara (president of Creatures Inc.) said was his favorite Pokemon in an ABC -; interview on February 8, 2000. -; "Exeggutor is my favorite. That's because I was always using this character -; while I was debugging the program." -; http://www.ign.com/articles/2000/02/09/abc-news-pokamon-chat-transcript - -SetIshiharaTeam: - ld de, IshiharaTeam -.loop - ld a, [de] - cp $ff - ret z - ld [wcf91], a - inc de - ld a, [de] - ld [wCurEnemyLVL], a - inc de - call AddPartyMon - jr .loop - -IshiharaTeam: - db EXEGGUTOR,90 - db MEW,20 - db JOLTEON,56 - db DUGTRIO,56 - db ARTICUNO,57 - db $FF - -EmptyFunc: - ret diff --git a/engine/display_pokedex.asm b/engine/display_pokedex.asm deleted file mode 100644 index d657ea85..00000000 --- a/engine/display_pokedex.asm +++ /dev/null @@ -1,19 +0,0 @@ -_DisplayPokedex:: - ld hl, wd730 - set 6, [hl] - predef ShowPokedexData - ld hl, wd730 - res 6, [hl] - call ReloadMapData - ld c, 10 - call DelayFrames - predef IndexToPokedex - ld a, [wd11e] - dec a - ld c, a - ld b, FLAG_SET - ld hl, wPokedexSeen - predef FlagActionPredef - ld a, $1 - ld [wDoNotWaitForButtonPressAfterDisplayingText], a - ret diff --git a/engine/display_text_id_init.asm b/engine/display_text_id_init.asm deleted file mode 100644 index 5043ad22..00000000 --- a/engine/display_text_id_init.asm +++ /dev/null @@ -1,78 +0,0 @@ -; function that performs initialization for DisplayTextID -DisplayTextIDInit:: - xor a - ld [wListMenuID], a - ld a, [wAutoTextBoxDrawingControl] - bit 0, a - jr nz, .skipDrawingTextBoxBorder - ld a, [hSpriteIndexOrTextID] ; text ID (or sprite ID) - and a - jr nz, .notStartMenu -; if text ID is 0 (i.e. the start menu) -; Note that the start menu text border is also drawn in the function directly -; below this, so this seems unnecessary. - CheckEvent EVENT_GOT_POKEDEX -; start menu with pokedex - coord hl, 10, 0 - ld b, $0e - ld c, $08 - jr nz, .drawTextBoxBorder -; start menu without pokedex - coord hl, 10, 0 - ld b, $0c - ld c, $08 - jr .drawTextBoxBorder -; if text ID is not 0 (i.e. not the start menu) then do a standard dialogue text box -.notStartMenu - coord hl, 0, 12 - ld b, $04 - ld c, $12 -.drawTextBoxBorder - call TextBoxBorder -.skipDrawingTextBoxBorder - ld hl, wFontLoaded - set 0, [hl] - ld hl, wFlags_0xcd60 - bit 4, [hl] - res 4, [hl] - jr nz, .skipMovingSprites - call UpdateSprites -.skipMovingSprites -; loop to copy C1X9 (direction the sprite is facing) to C2X9 for each sprite -; this is done because when you talk to an NPC, they turn to look your way -; the original direction they were facing must be restored after the dialogue is over - ld hl, wSpriteStateData1 + $19 - ld c, $0f - ld de, $0010 -.spriteFacingDirectionCopyLoop - ld a, [hl] - inc h - ld [hl], a - dec h - add hl, de - dec c - jr nz, .spriteFacingDirectionCopyLoop -; loop to force all the sprites in the middle of animation to stand still -; (so that they don't like they're frozen mid-step during the dialogue) - ld hl, wSpriteStateData1 + 2 - ld de, $0010 - ld c, e -.spriteStandStillLoop - ld a, [hl] - cp $ff ; is the sprite visible? - jr z, .nextSprite -; if it is visible - and $fc - ld [hl], a -.nextSprite - add hl, de - dec c - jr nz, .spriteStandStillLoop - ld b, $9c ; window background address - call CopyScreenTileBufferToVRAM ; transfer background in WRAM to VRAM - xor a - ld [hWY], a ; put the window on the screen - call LoadFontTilePatterns - ld a, $01 - ld [H_AUTOBGTRANSFERENABLED], a ; enable continuous WRAM to VRAM transfer each V-blank - ret diff --git a/engine/events/black_out.asm b/engine/events/black_out.asm new file mode 100644 index 00000000..6c358ce3 --- /dev/null +++ b/engine/events/black_out.asm @@ -0,0 +1,46 @@ +ResetStatusAndHalveMoneyOnBlackout:: +; Reset player status on blackout. + xor a + ld [wBattleResult], a + ld [wWalkBikeSurfState], a + ld [wIsInBattle], a + ld [wMapPalOffset], a + ld [wNPCMovementScriptFunctionNum], a + ld [hJoyHeld], a + ld [wNPCMovementScriptPointerTableNum], a + ld [wFlags_0xcd60], a + + ld [hMoney], a + ld [hMoney + 1], a + ld [hMoney + 2], a + call HasEnoughMoney + jr c, .lostmoney ; never happens + + ; Halve the player's money. + ld a, [wPlayerMoney] + ld [hMoney], a + ld a, [wPlayerMoney + 1] + ld [hMoney + 1], a + ld a, [wPlayerMoney + 2] + ld [hMoney + 2], a + xor a + ld [hDivideBCDDivisor], a + ld [hDivideBCDDivisor + 1], a + ld a, 2 + ld [hDivideBCDDivisor + 2], a + predef DivideBCDPredef3 + ld a, [hDivideBCDQuotient] + ld [wPlayerMoney], a + ld a, [hDivideBCDQuotient + 1] + ld [wPlayerMoney + 1], a + ld a, [hDivideBCDQuotient + 2] + ld [wPlayerMoney + 2], a + +.lostmoney + ld hl, wd732 + set 2, [hl] + res 3, [hl] + set 6, [hl] + ld a, %11111111 + ld [wJoyIgnore], a + predef_jump HealParty diff --git a/engine/events/card_key.asm b/engine/events/card_key.asm new file mode 100755 index 00000000..c77d5fcd --- /dev/null +++ b/engine/events/card_key.asm @@ -0,0 +1,112 @@ +PrintCardKeyText: + ld hl, SilphCoMapList + ld a, [wCurMap] + ld b, a +.silphCoMapListLoop + ld a, [hli] + cp $ff + ret z + cp b + jr nz, .silphCoMapListLoop + predef GetTileAndCoordsInFrontOfPlayer + ld a, [wTileInFrontOfPlayer] + cp $18 + jr z, .cardKeyDoorInFrontOfPlayer + cp $24 + jr z, .cardKeyDoorInFrontOfPlayer + ld b, a + ld a, [wCurMap] + cp SILPH_CO_11F + ret nz + ld a, b + cp $5e + ret nz +.cardKeyDoorInFrontOfPlayer + ld b, CARD_KEY + call IsItemInBag + jr z, .noCardKey + call GetCoordsInFrontOfPlayer + push de + tx_pre_id CardKeySuccessText + ld [hSpriteIndexOrTextID], a + call PrintPredefTextID + pop de + srl d + ld a, d + ld b, a + ld [wCardKeyDoorY], a + srl e + ld a, e + ld c, a + ld [wCardKeyDoorX], a + ld a, [wCurMap] + cp SILPH_CO_11F + jr nz, .notSilphCo11F + ld a, $3 + jr .replaceCardKeyDoorTileBlock +.notSilphCo11F + ld a, $e +.replaceCardKeyDoorTileBlock + ld [wNewTileBlockID], a + predef ReplaceTileBlock + ld hl, wCurrentMapScriptFlags + set 5, [hl] + ld a, SFX_GO_INSIDE + jp PlaySound +.noCardKey + tx_pre_id CardKeyFailText + ld [hSpriteIndexOrTextID], a + jp PrintPredefTextID + +SilphCoMapList: + 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 $FF + +CardKeySuccessText:: + TX_FAR _CardKeySuccessText1 + TX_SFX_ITEM_1 + TX_FAR _CardKeySuccessText2 + db "@" + +CardKeyFailText:: + TX_FAR _CardKeyFailText + db "@" + +; d = Y +; e = X +GetCoordsInFrontOfPlayer: + ld a, [wYCoord] + ld d, a + ld a, [wXCoord] + ld e, a + ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction + and a + jr nz, .notFacingDown +; facing down + inc d + ret +.notFacingDown + cp SPRITE_FACING_UP + jr nz, .notFacingUp +; facing up + dec d + ret +.notFacingUp + cp SPRITE_FACING_LEFT + jr nz, .notFacingLeft +; facing left + dec e + ret +.notFacingLeft +; facing right + inc e + ret diff --git a/engine/events/cinnabar_lab.asm b/engine/events/cinnabar_lab.asm new file mode 100755 index 00000000..e642840d --- /dev/null +++ b/engine/events/cinnabar_lab.asm @@ -0,0 +1,123 @@ +GiveFossilToCinnabarLab:: + ld hl, wd730 + set 6, [hl] + xor a + ld [wCurrentMenuItem], a + ld a, A_BUTTON | B_BUTTON + ld [wMenuWatchedKeys], a + ld a, [wFilteredBagItemsCount] + dec a + ld [wMaxMenuItem], a + ld a, 2 + ld [wTopMenuItemY], a + ld a, 1 + ld [wTopMenuItemX], a + ld a, [wFilteredBagItemsCount] + dec a + ld bc, 2 + ld hl, 3 + call AddNTimes + dec l + ld b, l + ld c, $d + coord hl, 0, 0 + call TextBoxBorder + call UpdateSprites + call PrintFossilsInBag + ld hl, wd730 + res 6, [hl] + call HandleMenuInput + bit 1, a ; pressed B? + jr nz, .cancelledGivingFossil + ld hl, wFilteredBagItems + ld a, [wCurrentMenuItem] + ld d, 0 + ld e, a + add hl, de + ld a, [hl] + ld [$ffdb], a + cp DOME_FOSSIL + jr z, .choseDomeFossil + cp HELIX_FOSSIL + jr z, .choseHelixFossil + ld b, AERODACTYL + jr .fossilSelected +.choseHelixFossil + ld b, OMANYTE + jr .fossilSelected +.choseDomeFossil + ld b, KABUTO +.fossilSelected + ld [wFossilItem], a + ld a, b + ld [wFossilMon], a + call LoadFossilItemAndMonName + ld hl, LabFossil_610ae + call PrintText + call YesNoChoice + ld a, [wCurrentMenuItem] + and a + jr nz, .cancelledGivingFossil + ld hl, LabFossil_610b3 + call PrintText + ld a, [wFossilItem] + ld [hItemToRemoveID], a + callba RemoveItemByID + ld hl, LabFossil_610b8 + call PrintText + SetEvents EVENT_GAVE_FOSSIL_TO_LAB, EVENT_LAB_STILL_REVIVING_FOSSIL + ret +.cancelledGivingFossil + ld hl, LabFossil_610bd + call PrintText + ret + +LabFossil_610ae: + TX_FAR _Lab4Text_610ae + db "@" + +LabFossil_610b3: + TX_FAR _Lab4Text_610b3 + db "@" + +LabFossil_610b8: + TX_FAR _Lab4Text_610b8 + db "@" + +LabFossil_610bd: + TX_FAR _Lab4Text_610bd + db "@" + +PrintFossilsInBag: +; Prints each fossil in the player's bag on a separate line in the menu. + ld hl, wFilteredBagItems + xor a + ld [hItemCounter], a +.loop + ld a, [hli] + cp $ff + ret z + push hl + ld [wd11e], a + call GetItemName + coord hl, 2, 2 + ld a, [hItemCounter] + ld bc, SCREEN_WIDTH * 2 + call AddNTimes + ld de, wcd6d + call PlaceString + ld hl, hItemCounter + inc [hl] + pop hl + jr .loop + +; loads the names of the fossil item and the resulting mon +LoadFossilItemAndMonName:: + ld a, [wFossilMon] + ld [wd11e], a + call GetMonName + call CopyStringToCF4B + ld a, [wFossilItem] + ld [wd11e], a + call GetItemName + ret diff --git a/engine/events/diploma.asm b/engine/events/diploma.asm new file mode 100755 index 00000000..e53ef58f --- /dev/null +++ b/engine/events/diploma.asm @@ -0,0 +1,113 @@ +DisplayDiploma:: + call SaveScreenTilesToBuffer2 + call GBPalWhiteOutWithDelay3 + call ClearScreen + xor a + ld [wUpdateSpritesEnabled], a + ld hl, wd730 + set 6, [hl] + call DisableLCD + ld hl, CircleTile + ld de, vChars2 + $700 + ld bc, $0010 + ld a, BANK(CircleTile) + call FarCopyData2 + coord hl, 0, 0 + lb bc, 16, 18 + predef Diploma_TextBoxBorder + ld hl, DiplomaTextPointersAndCoords + ld c, $5 +.asm_56715 + push bc + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + ld a, [hli] + push hl + ld h, [hl] + ld l, a + call PlaceString + pop hl + inc hl + pop bc + dec c + jr nz, .asm_56715 + coord hl, 10, 4 + ld de, wPlayerName + call PlaceString + callba DrawPlayerCharacter + +; Move the player 33 pixels right and set the priority bit so he appears +; behind the background layer. + ld hl, wOAMBuffer + $01 + lb bc, $80, $28 +.adjustPlayerGfxLoop + ld a, [hl] ; X + add 33 + ld [hli], a + inc hl + ld a, b + ld [hli], a ; attributes + inc hl + dec c + jr nz, .adjustPlayerGfxLoop + + call EnableLCD + callba LoadTrainerInfoTextBoxTiles + ld b, SET_PAL_GENERIC + call RunPaletteCommand + call Delay3 + call GBPalNormal + ld a, $90 + ld [rOBP0], a + call WaitForTextScrollButtonPress + ld hl, wd730 + res 6, [hl] + call GBPalWhiteOutWithDelay3 + call RestoreScreenTilesAndReloadTilePatterns + call Delay3 + jp GBPalNormal + +UnusedPlayerNameLengthFunc: +; Unused function that does a calculation involving the length of the player's +; name. + ld hl, wPlayerName + ld bc, $ff00 +.loop + ld a, [hli] + cp "@" + ret z + dec c + jr .loop + +DiplomaTextPointersAndCoords: + dw DiplomaText + dwCoord 5, 2 + dw DiplomaPlayer + dwCoord 3, 4 + dw DiplomaEmptyText + dwCoord 15, 4 + dw DiplomaCongrats + dwCoord 2, 6 + dw DiplomaGameFreak + dwCoord 9, 16 + +DiplomaText: + db $70,"Diploma",$70,"@" + +DiplomaPlayer: + db "Player@" + +DiplomaEmptyText: + db "@" + +DiplomaCongrats: + db "Congrats! This" + next "diploma certifies" + next "that you have" + next "completed your" + next "#DEX.@" + +DiplomaGameFreak: + db "GAME FREAK@" diff --git a/engine/events/display_pokedex.asm b/engine/events/display_pokedex.asm new file mode 100644 index 00000000..d657ea85 --- /dev/null +++ b/engine/events/display_pokedex.asm @@ -0,0 +1,19 @@ +_DisplayPokedex:: + ld hl, wd730 + set 6, [hl] + predef ShowPokedexData + ld hl, wd730 + res 6, [hl] + call ReloadMapData + ld c, 10 + call DelayFrames + predef IndexToPokedex + ld a, [wd11e] + dec a + ld c, a + ld b, FLAG_SET + ld hl, wPokedexSeen + predef FlagActionPredef + ld a, $1 + ld [wDoNotWaitForButtonPressAfterDisplayingText], a + ret diff --git a/engine/events/elevator.asm b/engine/events/elevator.asm new file mode 100755 index 00000000..752bdd1a --- /dev/null +++ b/engine/events/elevator.asm @@ -0,0 +1,48 @@ +DisplayElevatorFloorMenu: + ld hl, WhichFloorText + call PrintText + ld hl, wItemList + ld a, l + ld [wListPointer], a + ld a, h + ld [wListPointer + 1], a + ld a, [wListScrollOffset] + push af + xor a + ld [wCurrentMenuItem], a + ld [wListScrollOffset], a + ld [wPrintItemPrices], a + ld a, SPECIALLISTMENU + ld [wListMenuID], a + call DisplayListMenuID + pop bc + ld a, b + ld [wListScrollOffset], a + ret c + ld hl, wCurrentMapScriptFlags + set 7, [hl] + ld hl, wElevatorWarpMaps + ld a, [wWhichPokemon] + add a + ld d, 0 + ld e, a + add hl, de + ld a, [hli] + ld b, a + ld a, [hl] + ld c, a + ld hl, wWarpEntries + call .UpdateWarp + +.UpdateWarp + inc hl + inc hl + ld a, b + ld [hli], a ; destination warp ID + ld a, c + ld [hli], a ; destination map ID + ret + +WhichFloorText: + TX_FAR _WhichFloorText + db "@" diff --git a/engine/events/evolve_trade.asm b/engine/events/evolve_trade.asm new file mode 100755 index 00000000..e17fc05c --- /dev/null +++ b/engine/events/evolve_trade.asm @@ -0,0 +1,44 @@ +EvolveTradeMon: +; Verify the TradeMon's species name before +; attempting to initiate a trade evolution. + +; The names of the trade evolutions in Blue (JP) +; are checked. In that version, TradeMons that +; can evolve are Graveler and Haunter. + +; In localization, this check was translated +; before monster names were finalized. +; Then, Haunter's name was "Spectre". +; Since its name no longer starts with +; "SP", it is prevented from evolving. + +; This may have been why Red/Green's trades +; were used instead, where none can evolve. + +; This was fixed in Yellow. + + ld a, [wInGameTradeReceiveMonName] + + ; GRAVELER + cp "G" + jr z, .ok + + ; "SPECTRE" (HAUNTER) + cp "S" + ret nz + ld a, [wInGameTradeReceiveMonName + 1] + cp "P" + ret nz + +.ok + ld a, [wPartyCount] + dec a + ld [wWhichPokemon], a + ld a, $1 + ld [wForceEvolution], a + ld a, LINK_STATE_TRADING + ld [wLinkState], a + callab TryEvolvingMon + xor a ; LINK_STATE_NONE + ld [wLinkState], a + jp PlayDefaultMusic diff --git a/engine/events/give_pokemon.asm b/engine/events/give_pokemon.asm new file mode 100755 index 00000000..03177e60 --- /dev/null +++ b/engine/events/give_pokemon.asm @@ -0,0 +1,82 @@ +_GivePokemon:: +; returns success in carry +; and whether the mon was added to the party in [wAddedToParty] + call EnableAutoTextBoxDrawing + xor a + ld [wAddedToParty], a + ld a, [wPartyCount] + cp PARTY_LENGTH + jr c, .addToParty + ld a, [wNumInBox] + cp MONS_PER_BOX + jr nc, .boxFull +; add to box + xor a + ld [wEnemyBattleStatus3], a + ld a, [wcf91] + ld [wEnemyMonSpecies2], a + callab LoadEnemyMonData + call SetPokedexOwnedFlag + callab SendNewMonToBox + ld hl, wcf4b + ld a, [wCurrentBoxNum] + and $7f + cp 9 + jr c, .singleDigitBoxNum + sub 9 + ld [hl], "1" + inc hl + add "0" + jr .next +.singleDigitBoxNum + add "1" +.next + ld [hli], a + ld [hl], "@" + ld hl, SentToBoxText + call PrintText + scf + ret +.boxFull + ld hl, BoxIsFullText + call PrintText + and a + ret +.addToParty + call SetPokedexOwnedFlag + call AddPartyMon + ld a, 1 + ld [wDoNotWaitForButtonPressAfterDisplayingText], a + ld [wAddedToParty], a + scf + ret + +SetPokedexOwnedFlag: + ld a, [wcf91] + push af + ld [wd11e], a + predef IndexToPokedex + ld a, [wd11e] + dec a + ld c, a + ld hl, wPokedexOwned + ld b, FLAG_SET + predef FlagActionPredef + pop af + ld [wd11e], a + call GetMonName + ld hl, GotMonText + jp PrintText + +GotMonText: + TX_FAR _GotMonText + TX_SFX_ITEM_1 + db "@" + +SentToBoxText: + TX_FAR _SentToBoxText + db "@" + +BoxIsFullText: + TX_FAR _BoxIsFullText + db "@" diff --git a/engine/events/heal_party.asm b/engine/events/heal_party.asm new file mode 100644 index 00000000..7aaa1bd1 --- /dev/null +++ b/engine/events/heal_party.asm @@ -0,0 +1,99 @@ +HealParty: +; Restore HP and PP. + + ld hl, wPartySpecies + ld de, wPartyMon1HP +.healmon + ld a, [hli] + cp $ff + jr z, .done + + push hl + push de + + ld hl, wPartyMon1Status - wPartyMon1HP + add hl, de + xor a + ld [hl], a + + push de + ld b, NUM_MOVES ; A Pokémon has 4 moves +.pp + ld hl, wPartyMon1Moves - wPartyMon1HP + add hl, de + + ld a, [hl] + and a + jr z, .nextmove + + dec a + ld hl, wPartyMon1PP - wPartyMon1HP + add hl, de + + push hl + push de + push bc + + ld hl, Moves + ld bc, MoveEnd - Moves + call AddNTimes + ld de, wcd6d + ld a, BANK(Moves) + call FarCopyData + ld a, [wcd6d + 5] ; PP is byte 5 of move data + + pop bc + pop de + pop hl + + inc de + push bc + ld b, a + ld a, [hl] + and $c0 + add b + ld [hl], a + pop bc + +.nextmove + dec b + jr nz, .pp + pop de + + ld hl, wPartyMon1MaxHP - wPartyMon1HP + add hl, de + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + + pop de + pop hl + + push hl + ld bc, wPartyMon2 - wPartyMon1 + ld h, d + ld l, e + add hl, bc + ld d, h + ld e, l + pop hl + jr .healmon + +.done + xor a + ld [wWhichPokemon], a + ld [wd11e], a + + ld a, [wPartyCount] + ld b, a +.ppup + push bc + call RestoreBonusPP + pop bc + ld hl, wWhichPokemon + inc [hl] + dec b + jr nz, .ppup + ret diff --git a/engine/events/hidden_items.asm b/engine/events/hidden_items.asm new file mode 100755 index 00000000..e40b0ac7 --- /dev/null +++ b/engine/events/hidden_items.asm @@ -0,0 +1,161 @@ +HiddenItems: + ld hl, HiddenItemCoords + call FindHiddenItemOrCoinsIndex + ld [wHiddenItemOrCoinsIndex], a + ld hl, wObtainedHiddenItemsFlags + ld a, [wHiddenItemOrCoinsIndex] + ld c, a + ld b, FLAG_TEST + predef FlagActionPredef + ld a, c + and a + ret nz + call EnableAutoTextBoxDrawing + ld a, 1 + ld [wDoNotWaitForButtonPressAfterDisplayingText], a + ld a, [wHiddenObjectFunctionArgument] ; item ID + ld [wd11e], a + call GetItemName + tx_pre_jump FoundHiddenItemText + +INCLUDE "data/hidden_item_coords.asm" + +FoundHiddenItemText:: + TX_FAR _FoundHiddenItemText + TX_ASM + ld a, [wHiddenObjectFunctionArgument] ; item ID + ld b, a + ld c, 1 + call GiveItem + jr nc, .bagFull + ld hl, wObtainedHiddenItemsFlags + ld a, [wHiddenItemOrCoinsIndex] + ld c, a + ld b, FLAG_SET + predef FlagActionPredef + ld a, SFX_GET_ITEM_2 + call PlaySoundWaitForCurrent + call WaitForSoundToFinish + jp TextScriptEnd +.bagFull + call WaitForTextScrollButtonPress ; wait for button press + xor a + ld [wDoNotWaitForButtonPressAfterDisplayingText], a + ld hl, HiddenItemBagFullText + call PrintText + jp TextScriptEnd + +HiddenItemBagFullText:: + TX_FAR _HiddenItemBagFullText + db "@" + +HiddenCoins: + ld b, COIN_CASE + predef GetQuantityOfItemInBag + ld a, b + and a + ret z + ld hl, HiddenCoinCoords + call FindHiddenItemOrCoinsIndex + ld [wHiddenItemOrCoinsIndex], a + ld hl, wObtainedHiddenCoinsFlags + ld a, [wHiddenItemOrCoinsIndex] + ld c, a + ld b, FLAG_TEST + predef FlagActionPredef + ld a, c + and a + ret nz + xor a + ld [hUnusedCoinsByte], a + ld [hCoins], a + ld [hCoins + 1], a + ld a, [wHiddenObjectFunctionArgument] + sub COIN + cp 10 + jr z, .bcd10 + cp 20 + jr z, .bcd20 + cp 40 + jr z, .bcd20 ; should be bcd40 + jr .bcd100 +.bcd10 + ld a, $10 + ld [hCoins + 1], a + jr .bcdDone +.bcd20 + ld a, $20 + ld [hCoins + 1], a + jr .bcdDone +.bcd40 ; due to a typo, this is never used + ld a, $40 + ld [hCoins + 1], a + jr .bcdDone +.bcd100 + ld a, $1 + ld [hCoins], a +.bcdDone + ld de, wPlayerCoins + 1 + ld hl, hCoins + 1 + ld c, $2 + predef AddBCDPredef + ld hl, wObtainedHiddenCoinsFlags + ld a, [wHiddenItemOrCoinsIndex] + ld c, a + ld b, FLAG_SET + predef FlagActionPredef + call EnableAutoTextBoxDrawing + ld a, [wPlayerCoins] + cp $99 + jr nz, .roomInCoinCase + ld a, [wPlayerCoins + 1] + cp $99 + jr nz, .roomInCoinCase + tx_pre_id DroppedHiddenCoinsText + jr .done +.roomInCoinCase + tx_pre_id FoundHiddenCoinsText +.done + jp PrintPredefTextID + +INCLUDE "data/hidden_coins.asm" + +FoundHiddenCoinsText:: + TX_FAR _FoundHiddenCoinsText + TX_SFX_ITEM_2 + db "@" + +DroppedHiddenCoinsText:: + TX_FAR _FoundHiddenCoins2Text + TX_SFX_ITEM_2 + TX_FAR _DroppedHiddenCoinsText + db "@" + +FindHiddenItemOrCoinsIndex: + ld a, [wHiddenObjectY] + ld d, a + ld a, [wHiddenObjectX] + ld e, a + ld a, [wCurMap] + ld b, a + ld c, -1 +.loop + inc c + ld a, [hli] + cp $ff ; end of the list? + ret z ; if so, we're done here + cp b + jr nz, .next1 + ld a, [hli] + cp d + jr nz, .next2 + ld a, [hli] + cp e + jr nz, .loop + ld a, c + ret +.next1 + inc hl +.next2 + inc hl + jr .loop diff --git a/engine/events/hidden_object_functions14.asm b/engine/events/hidden_object_functions14.asm new file mode 100755 index 00000000..9e14c6a7 --- /dev/null +++ b/engine/events/hidden_object_functions14.asm @@ -0,0 +1,100 @@ +PrintNotebookText: + call EnableAutoTextBoxDrawing + ld a, $1 + ld [wDoNotWaitForButtonPressAfterDisplayingText], a + ld a, [wHiddenObjectFunctionArgument] + jp PrintPredefTextID + +TMNotebook:: + TX_FAR TMNotebookText + TX_WAIT + db "@" + +ViridianSchoolNotebook:: + TX_ASM + ld hl, ViridianSchoolNotebookText1 + call PrintText + call TurnPageSchoolNotebook + jr nz, .doneReading + ld hl, ViridianSchoolNotebookText2 + call PrintText + call TurnPageSchoolNotebook + jr nz, .doneReading + ld hl, ViridianSchoolNotebookText3 + call PrintText + call TurnPageSchoolNotebook + jr nz, .doneReading + ld hl, ViridianSchoolNotebookText4 + call PrintText + ld hl, ViridianSchoolNotebookText5 + call PrintText +.doneReading + jp TextScriptEnd + +TurnPageSchoolNotebook: + ld hl, TurnPageText + call PrintText + call YesNoChoice + ld a, [wCurrentMenuItem] + and a + ret + +TurnPageText: + TX_FAR _TurnPageText + db "@" + +ViridianSchoolNotebookText5: + TX_FAR _ViridianSchoolNotebookText5 + TX_WAIT + db "@" + +ViridianSchoolNotebookText1: + TX_FAR _ViridianSchoolNotebookText1 + db "@" + +ViridianSchoolNotebookText2: + TX_FAR _ViridianSchoolNotebookText2 + db "@" + +ViridianSchoolNotebookText3: + TX_FAR _ViridianSchoolNotebookText3 + db "@" + +ViridianSchoolNotebookText4: + TX_FAR _ViridianSchoolNotebookText4 + db "@" + +PrintFightingDojoText2: + call EnableAutoTextBoxDrawing + tx_pre_jump EnemiesOnEverySideText + +EnemiesOnEverySideText:: + TX_FAR _EnemiesOnEverySideText + db "@" + +PrintFightingDojoText3: + call EnableAutoTextBoxDrawing + tx_pre_jump WhatGoesAroundComesAroundText + +WhatGoesAroundComesAroundText:: + TX_FAR _WhatGoesAroundComesAroundText + db "@" + +PrintFightingDojoText: + call EnableAutoTextBoxDrawing + tx_pre_jump FightingDojoText + +FightingDojoText:: + TX_FAR _FightingDojoText + db "@" + +PrintIndigoPlateauHQText: + ld a, [wSpriteStateData1 + 9] + cp SPRITE_FACING_UP + ret nz + call EnableAutoTextBoxDrawing + tx_pre_jump IndigoPlateauHQText + +IndigoPlateauHQText:: + TX_FAR _IndigoPlateauHQText + db "@" diff --git a/engine/events/hidden_object_functions17.asm b/engine/events/hidden_object_functions17.asm new file mode 100755 index 00000000..bb2a358c --- /dev/null +++ b/engine/events/hidden_object_functions17.asm @@ -0,0 +1,475 @@ +PrintRedSNESText: + call EnableAutoTextBoxDrawing + tx_pre_jump RedBedroomSNESText + +RedBedroomSNESText:: + TX_FAR _RedBedroomSNESText + db "@" + +OpenRedsPC: + call EnableAutoTextBoxDrawing + tx_pre_jump RedBedroomPCText + +RedBedroomPCText:: + TX_PLAYERS_PC + +Route15GateLeftBinoculars: + ld a, [wSpriteStateData1 + 9] + cp SPRITE_FACING_UP + ret nz + call EnableAutoTextBoxDrawing + tx_pre Route15UpstairsBinocularsText + ld a, ARTICUNO + ld [wcf91], a + call PlayCry + jp DisplayMonFrontSpriteInBox + +Route15UpstairsBinocularsText:: + TX_FAR _Route15UpstairsBinocularsText + db "@" + +AerodactylFossil: + ld a, FOSSIL_AERODACTYL + ld [wcf91], a + call DisplayMonFrontSpriteInBox + call EnableAutoTextBoxDrawing + tx_pre AerodactylFossilText + ret + +AerodactylFossilText:: + TX_FAR _AerodactylFossilText + db "@" + +KabutopsFossil: + ld a, FOSSIL_KABUTOPS + ld [wcf91], a + call DisplayMonFrontSpriteInBox + call EnableAutoTextBoxDrawing + tx_pre KabutopsFossilText + ret + +KabutopsFossilText:: + TX_FAR _KabutopsFossilText + db "@" + +DisplayMonFrontSpriteInBox: +; Displays a pokemon's front sprite in a pop-up window. +; [wcf91] = pokemon internal id number + ld a, 1 + ld [H_AUTOBGTRANSFERENABLED], a + call Delay3 + xor a + ld [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 + ld [hStartTileID], a + coord hl, 10, 11 + predef AnimateSendingOutMon + call WaitForTextScrollButtonPress + call LoadScreenTilesFromBuffer1 + call Delay3 + ld a, $90 + ld [hWY], a + ret + +PrintBlackboardLinkCableText: + call EnableAutoTextBoxDrawing + ld a, $1 + ld [wDoNotWaitForButtonPressAfterDisplayingText], a + ld a, [wHiddenObjectFunctionArgument] + call PrintPredefTextID + ret + +LinkCableHelp:: + TX_ASM + call SaveScreenTilesToBuffer1 + ld hl, LinkCableHelpText1 + call PrintText + xor a + ld [wMenuItemOffset], a ; not used + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + ld a, A_BUTTON | B_BUTTON + ld [wMenuWatchedKeys], a + ld a, 3 + ld [wMaxMenuItem], a + ld a, 2 + ld [wTopMenuItemY], a + ld a, 1 + ld [wTopMenuItemX], a +.linkHelpLoop + ld hl, wd730 + set 6, [hl] + coord hl, 0, 0 + ld b, 8 + ld c, 13 + call TextBoxBorder + coord hl, 2, 2 + ld de, HowToLinkText + call PlaceString + ld hl, LinkCableHelpText2 + call PrintText + call HandleMenuInput + bit 1, a ; pressed b + jr nz, .exit + ld a, [wCurrentMenuItem] + cp 3 ; pressed a on "STOP READING" + jr z, .exit + ld hl, wd730 + res 6, [hl] + ld hl, LinkCableInfoTexts + add a + ld d, 0 + ld e, a + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + call PrintText + jp .linkHelpLoop +.exit + ld hl, wd730 + res 6, [hl] + call LoadScreenTilesFromBuffer1 + jp TextScriptEnd + +LinkCableHelpText1: + TX_FAR _LinkCableHelpText1 + db "@" + +LinkCableHelpText2: + TX_FAR _LinkCableHelpText2 + db "@" + +HowToLinkText: + db "HOW TO LINK" + next "COLOSSEUM" + next "TRADE CENTER" + next "STOP READING@" + +LinkCableInfoTexts: + dw LinkCableInfoText1 + dw LinkCableInfoText2 + dw LinkCableInfoText3 + +LinkCableInfoText1: + TX_FAR _LinkCableInfoText1 + db "@" + +LinkCableInfoText2: + TX_FAR _LinkCableInfoText2 + db "@" + +LinkCableInfoText3: + TX_FAR _LinkCableInfoText3 + db "@" + +ViridianSchoolBlackboard:: + TX_ASM + call SaveScreenTilesToBuffer1 + ld hl, ViridianSchoolBlackboardText1 + call PrintText + xor a + ld [wMenuItemOffset], a + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + ld a, D_LEFT | D_RIGHT | A_BUTTON | B_BUTTON + ld [wMenuWatchedKeys], a + ld a, 2 + ld [wMaxMenuItem], a + ld a, 2 + ld [wTopMenuItemY], a + ld a, 1 + ld [wTopMenuItemX], a +.blackboardLoop + ld hl, wd730 + set 6, [hl] + coord hl, 0, 0 + lb bc, 6, 10 + call TextBoxBorder + coord hl, 1, 2 + ld de, StatusAilmentText1 + call PlaceString + coord hl, 6, 2 + ld de, StatusAilmentText2 + call PlaceString + ld hl, ViridianSchoolBlackboardText2 + call PrintText + call HandleMenuInput ; pressing up and down is handled in here + bit 1, a ; pressed b + jr nz, .exitBlackboard + bit 4, a ; pressed right + jr z, .didNotPressRight + ; move cursor to right column + ld a, 2 + ld [wMaxMenuItem], a + ld a, 2 + ld [wTopMenuItemY], a + ld a, 6 + ld [wTopMenuItemX], a + ld a, 3 ; in the the right column, use an offset to prevent overlap + ld [wMenuItemOffset], a + jr .blackboardLoop +.didNotPressRight + bit 5, a ; pressed left + jr z, .didNotPressLeftOrRight + ; move cursor to left column + ld a, 2 + ld [wMaxMenuItem], a + ld a, 2 + ld [wTopMenuItemY], a + ld a, 1 + ld [wTopMenuItemX], a + xor a + ld [wMenuItemOffset], a + jr .blackboardLoop +.didNotPressLeftOrRight + ld a, [wCurrentMenuItem] + ld b, a + ld a, [wMenuItemOffset] + add b + cp 5 ; cursor is pointing to "QUIT" + jr z, .exitBlackboard + ; we must have pressed a on a status condition + ; so print the text + ld hl, wd730 + res 6, [hl] + ld hl, ViridianBlackboardStatusPointers + add a + ld d, 0 + ld e, a + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + call PrintText + jp .blackboardLoop +.exitBlackboard + ld hl, wd730 + res 6, [hl] + call LoadScreenTilesFromBuffer1 + jp TextScriptEnd + +ViridianSchoolBlackboardText1: + TX_FAR _ViridianSchoolBlackboardText1 + db "@" + +ViridianSchoolBlackboardText2: + TX_FAR _ViridianSchoolBlackboardText2 + db "@" + +StatusAilmentText1: + db " SLP" + next " PSN" + next " PAR@" + +StatusAilmentText2: + db " BRN" + next " FRZ" + next " QUIT@@" + +ViridianBlackboardStatusPointers: + dw ViridianBlackboardSleepText + dw ViridianBlackboardPoisonText + dw ViridianBlackboardPrlzText + dw ViridianBlackboardBurnText + dw ViridianBlackboardFrozenText + +ViridianBlackboardSleepText: + TX_FAR _ViridianBlackboardSleepText + db "@" + +ViridianBlackboardPoisonText: + TX_FAR _ViridianBlackboardPoisonText + db "@" + +ViridianBlackboardPrlzText: + TX_FAR _ViridianBlackboardPrlzText + db "@" + +ViridianBlackboardBurnText: + TX_FAR _ViridianBlackboardBurnText + db "@" + +ViridianBlackboardFrozenText: + TX_FAR _ViridianBlackboardFrozenText + db "@" + +PrintTrashText: + call EnableAutoTextBoxDrawing + tx_pre_jump VermilionGymTrashText + +VermilionGymTrashText:: + TX_FAR _VermilionGymTrashText + db "@" + +GymTrashScript: + call EnableAutoTextBoxDrawing + ld a, [wHiddenObjectFunctionArgument] + ld [wGymTrashCanIndex], a + +; Don't do the trash can puzzle if it's already been done. + CheckEvent EVENT_2ND_LOCK_OPENED + jr z, .ok + + tx_pre_jump VermilionGymTrashText + +.ok + CheckEventReuseA EVENT_1ST_LOCK_OPENED + jr nz, .trySecondLock + + ld a, [wFirstLockTrashCanIndex] + ld b, a + ld a, [wGymTrashCanIndex] + cp b + jr z, .openFirstLock + + tx_pre_id VermilionGymTrashText + jr .done + +.openFirstLock +; Next can is trying for the second switch. + SetEvent EVENT_1ST_LOCK_OPENED + + ld hl, GymTrashCans + ld a, [wGymTrashCanIndex] + ; * 5 + ld b, a + add a + add a + add b + + ld d, 0 + ld e, a + add hl, de + ld a, [hli] + +; There is a bug in this code. It should calculate a value in the range [0, 3] +; but if the mask and random number don't have any 1 bits in common, then +; the result of the AND will be 0. When 1 is subtracted from that, the value +; will become $ff. This will result in 255 being added to hl, which will cause +; hl to point to one of the zero bytes that pad the end of the ROM bank. +; Trash can 0 was intended to be able to have the second lock only when the +; first lock was in trash can 1 or 3. However, due to this bug, trash can 0 can +; have the second lock regardless of which trash can had the first lock. + + ld [hGymTrashCanRandNumMask], a + push hl + call Random + swap a + ld b, a + ld a, [hGymTrashCanRandNumMask] + and b + dec a + pop hl + + ld d, 0 + ld e, a + add hl, de + ld a, [hl] + and $f + ld [wSecondLockTrashCanIndex], a + + tx_pre_id VermilionGymTrashSuccessText1 + jr .done + +.trySecondLock + ld a, [wSecondLockTrashCanIndex] + ld b, a + ld a, [wGymTrashCanIndex] + cp b + jr z, .openSecondLock + +; Reset the cans. + ResetEvent EVENT_1ST_LOCK_OPENED + call Random + + and $e + ld [wFirstLockTrashCanIndex], a + + tx_pre_id VermilionGymTrashFailText + jr .done + +.openSecondLock +; Completed the trash can puzzle. + SetEvent EVENT_2ND_LOCK_OPENED + ld hl, wCurrentMapScriptFlags + set 6, [hl] + + tx_pre_id VermilionGymTrashSuccessText3 + +.done + jp PrintPredefTextID + +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 +; 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 + db 4, 1, 3, 5, 7 ; 4 + db 3, 2, 4, 8, 0 ; 5 + db 3, 3, 7, 9, 0 ; 6 + db 4, 4, 6, 8, 10 ; 7 + db 3, 5, 7, 11, 0 ; 8 + db 3, 6, 10, 12, 0 ; 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 + +VermilionGymTrashSuccessText1:: + TX_FAR _VermilionGymTrashSuccessText1 + TX_ASM + call WaitForSoundToFinish + ld a, SFX_SWITCH + call PlaySound + call WaitForSoundToFinish + jp TextScriptEnd + +; unused +VermilionGymTrashSuccessText2:: + TX_FAR _VermilionGymTrashSuccessText2 + db "@" + +; unused +VermilionGymTrashSuccesPlaySfx: + TX_ASM + call WaitForSoundToFinish + ld a, SFX_SWITCH + call PlaySound + call WaitForSoundToFinish + jp TextScriptEnd + +VermilionGymTrashSuccessText3:: + TX_FAR _VermilionGymTrashSuccessText3 + TX_ASM + call WaitForSoundToFinish + ld a, SFX_GO_INSIDE + call PlaySound + call WaitForSoundToFinish + jp TextScriptEnd + +VermilionGymTrashFailText:: + TX_FAR _VermilionGymTrashFailText + TX_ASM + call WaitForSoundToFinish + ld a, SFX_DENIED + call PlaySound + call WaitForSoundToFinish + jp TextScriptEnd diff --git a/engine/events/hidden_object_functions18.asm b/engine/events/hidden_object_functions18.asm new file mode 100755 index 00000000..c0e5aa34 --- /dev/null +++ b/engine/events/hidden_object_functions18.asm @@ -0,0 +1,198 @@ +GymStatues: +; if in a gym and have the corresponding badge, a = GymStatueText2_id and jp PrintPredefTextID +; if in a gym and don’t have the corresponding badge, a = GymStatueText1_id and jp PrintPredefTextID +; else ret + call EnableAutoTextBoxDrawing + ld a, [wSpriteStateData1 + 9] + cp SPRITE_FACING_UP + ret nz + ld hl, .BadgeFlags + ld a, [wCurMap] + ld b, a +.loop + ld a, [hli] + cp $ff + ret z + cp b + jr z, .match + inc hl + jr .loop +.match + ld b, [hl] + ld a, [wBeatGymFlags] + and b + cp b + tx_pre_id GymStatueText2 + jr z, .haveBadge + tx_pre_id GymStatueText1 +.haveBadge + jp PrintPredefTextID + +.BadgeFlags: + db PEWTER_GYM, %00000001 + db CERULEAN_GYM, %00000010 + db VERMILION_GYM,%00000100 + db CELADON_GYM, %00001000 + db FUCHSIA_GYM, %00010000 + db SAFFRON_GYM, %00100000 + db CINNABAR_GYM, %01000000 + db VIRIDIAN_GYM, %10000000 + db $ff + +GymStatueText1:: + TX_FAR _GymStatueText1 + db "@" + +GymStatueText2:: + TX_FAR _GymStatueText2 + db "@" + +PrintBenchGuyText: + call EnableAutoTextBoxDrawing + ld hl, BenchGuyTextPointers + ld a, [wCurMap] + ld b, a +.loop + ld a, [hli] + cp $ff + ret z + cp b + jr z, .match + inc hl + inc hl + jr .loop +.match + ld a, [hli] + ld b, a + ld a, [wSpriteStateData1 + 9] + cp b + jr nz, .loop ; player isn't facing left at the bench guy + ld a, [hl] + jp PrintPredefTextID + +; format: db map id, player sprite facing direction, text id of PredefTextIDPointerTable +BenchGuyTextPointers: + db VIRIDIAN_POKECENTER, SPRITE_FACING_LEFT + db_tx_pre ViridianCityPokecenterBenchGuyText + db PEWTER_POKECENTER, SPRITE_FACING_LEFT + db_tx_pre PewterCityPokecenterBenchGuyText + db CERULEAN_POKECENTER, SPRITE_FACING_LEFT + db_tx_pre CeruleanCityPokecenterBenchGuyText + db LAVENDER_POKECENTER, SPRITE_FACING_LEFT + db_tx_pre LavenderCityPokecenterBenchGuyText + db VERMILION_POKECENTER, SPRITE_FACING_LEFT + db_tx_pre VermilionCityPokecenterBenchGuyText + db CELADON_POKECENTER, SPRITE_FACING_LEFT + db_tx_pre CeladonCityPokecenterBenchGuyText + db CELADON_HOTEL, SPRITE_FACING_LEFT + db_tx_pre CeladonCityHotelText + db FUCHSIA_POKECENTER, SPRITE_FACING_LEFT + db_tx_pre FuchsiaCityPokecenterBenchGuyText + db CINNABAR_POKECENTER, SPRITE_FACING_LEFT + db_tx_pre CinnabarIslandPokecenterBenchGuyText + db SAFFRON_POKECENTER, SPRITE_FACING_LEFT + db_tx_pre SaffronCityPokecenterBenchGuyText + db MT_MOON_POKECENTER, SPRITE_FACING_LEFT + db_tx_pre MtMoonPokecenterBenchGuyText + db ROCK_TUNNEL_POKECENTER,SPRITE_FACING_LEFT + db_tx_pre RockTunnelPokecenterBenchGuyText + db $FF + +ViridianCityPokecenterBenchGuyText:: + TX_FAR _ViridianCityPokecenterGuyText + db "@" + +PewterCityPokecenterBenchGuyText:: + TX_FAR _PewterCityPokecenterGuyText + db "@" + +CeruleanCityPokecenterBenchGuyText:: + TX_FAR _CeruleanPokecenterGuyText + db "@" + +LavenderCityPokecenterBenchGuyText:: + TX_FAR _LavenderPokecenterGuyText + db "@" + +MtMoonPokecenterBenchGuyText:: + TX_FAR _MtMoonPokecenterBenchGuyText + db "@" + +RockTunnelPokecenterBenchGuyText:: + TX_FAR _RockTunnelPokecenterGuyText + db "@" + +UnusedBenchGuyText1:: + TX_FAR _UnusedBenchGuyText1 + db "@" + +UnusedBenchGuyText2:: + TX_FAR _UnusedBenchGuyText2 + db "@" + +UnusedBenchGuyText3:: + TX_FAR _UnusedBenchGuyText3 + db "@" + +VermilionCityPokecenterBenchGuyText:: + TX_FAR _VermilionPokecenterGuyText + db "@" + +CeladonCityPokecenterBenchGuyText:: + TX_FAR _CeladonCityPokecenterGuyText + db "@" + +FuchsiaCityPokecenterBenchGuyText:: + TX_FAR _FuchsiaCityPokecenterGuyText + db "@" + +CinnabarIslandPokecenterBenchGuyText:: + TX_FAR _CinnabarPokecenterGuyText + db "@" + +SaffronCityPokecenterBenchGuyText:: + TX_ASM + CheckEvent EVENT_BEAT_SILPH_CO_GIOVANNI + ld hl, SaffronCityPokecenterBenchGuyText2 + jr nz, .asm_624f2 + ld hl, SaffronCityPokecenterBenchGuyText1 +.asm_624f2 + call PrintText + jp TextScriptEnd + +SaffronCityPokecenterBenchGuyText1: + TX_FAR _SaffronCityPokecenterGuyText1 + db "@" + +SaffronCityPokecenterBenchGuyText2: + TX_FAR _SaffronCityPokecenterGuyText2 + db "@" + +CeladonCityHotelText:: + TX_FAR _CeladonCityHotelText + db "@" + + ret + +UnusedPredefText:: + db "@" + +PrintBookcaseText: + call EnableAutoTextBoxDrawing + tx_pre_jump BookcaseText + +BookcaseText:: + TX_FAR _BookcaseText + db "@" + +OpenPokemonCenterPC: + ld a, [wSpriteStateData1 + 9] + cp SPRITE_FACING_UP ; check to see if player is facing up + ret nz + call EnableAutoTextBoxDrawing + ld a, $1 + ld [wAutoTextBoxDrawingControl], a + tx_pre_jump PokemonCenterPCText + +PokemonCenterPCText:: + TX_POKECENTER_PC diff --git a/engine/events/hidden_object_functions3.asm b/engine/events/hidden_object_functions3.asm new file mode 100755 index 00000000..1237e960 --- /dev/null +++ b/engine/events/hidden_object_functions3.asm @@ -0,0 +1,117 @@ +; prints text for bookshelves in buildings without sign events +PrintBookshelfText:: + ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction + cp SPRITE_FACING_UP + jr nz, .noMatch +; facing up + ld a, [wCurMapTileset] + ld b, a + aCoord 8, 7 + ld c, a + ld hl, BookshelfTileIDs +.loop + ld a, [hli] + cp $ff + jr z, .noMatch + cp b + jr nz, .nextBookshelfEntry1 + ld a, [hli] + cp c + jr nz, .nextBookshelfEntry2 + ld a, [hl] + push af + call EnableAutoTextBoxDrawing + pop af + call PrintPredefTextID + xor a + ld [$ffdb], a + ret +.nextBookshelfEntry1 + inc hl +.nextBookshelfEntry2 + inc hl + jr .loop +.noMatch + ld a, $ff + ld [$ffdb], a + jpba PrintCardKeyText + +INCLUDE "data/bookshelf_tile_ids.asm" + +IndigoPlateauStatues:: + TX_ASM + ld hl, IndigoPlateauStatuesText1 + call PrintText + ld a, [wXCoord] + bit 0, a + ld hl, IndigoPlateauStatuesText2 + jr nz, .ok + ld hl, IndigoPlateauStatuesText3 +.ok + call PrintText + jp TextScriptEnd + +IndigoPlateauStatuesText1: + TX_FAR _IndigoPlateauStatuesText1 + db "@" + +IndigoPlateauStatuesText2: + TX_FAR _IndigoPlateauStatuesText2 + db "@" + +IndigoPlateauStatuesText3: + TX_FAR _IndigoPlateauStatuesText3 + db "@" + +BookOrSculptureText:: + TX_ASM + ld hl, PokemonBooksText + ld a, [wCurMapTileset] + cp MANSION ; Celadon Mansion tileset + jr nz, .ok + aCoord 8, 6 + cp $38 + jr nz, .ok + ld hl, DiglettSculptureText +.ok + call PrintText + jp TextScriptEnd + +PokemonBooksText: + TX_FAR _PokemonBooksText + db "@" + +DiglettSculptureText: + TX_FAR _DiglettSculptureText + db "@" + +ElevatorText:: + TX_FAR _ElevatorText + db "@" + +TownMapText:: + TX_FAR _TownMapText + TX_BLINK + TX_ASM + ld a, $1 + ld [wDoNotWaitForButtonPressAfterDisplayingText], a + ld hl, wd730 + set 6, [hl] + call GBPalWhiteOutWithDelay3 + xor a + ld [hWY], a + inc a + ld [H_AUTOBGTRANSFERENABLED], a + call LoadFontTilePatterns + callba DisplayTownMap + ld hl, wd730 + res 6, [hl] + ld de, TextScriptEnd + push de + ld a, [H_LOADEDROMBANK] + push af + jp CloseTextDisplay + +PokemonStuffText:: + TX_FAR _PokemonStuffText + db "@" diff --git a/engine/events/hidden_object_functions7.asm b/engine/events/hidden_object_functions7.asm new file mode 100755 index 00000000..e18b9570 --- /dev/null +++ b/engine/events/hidden_object_functions7.asm @@ -0,0 +1,467 @@ +PrintNewBikeText: + call EnableAutoTextBoxDrawing + tx_pre_jump NewBicycleText + +NewBicycleText:: + TX_FAR _NewBicycleText + db "@" + +DisplayOakLabLeftPoster: + call EnableAutoTextBoxDrawing + tx_pre_jump PushStartText + +PushStartText:: + TX_FAR _PushStartText + db "@" + +DisplayOakLabRightPoster: + call EnableAutoTextBoxDrawing + ld hl, wPokedexOwned + ld b, wPokedexOwnedEnd - wPokedexOwned + call CountSetBits + ld a, [wNumSetBits] + cp 2 + tx_pre_id SaveOptionText + jr c, .ownLessThanTwo + ; own two or more mon + tx_pre_id StrengthsAndWeaknessesText +.ownLessThanTwo + jp PrintPredefTextID + +SaveOptionText:: + TX_FAR _SaveOptionText + db "@" + +StrengthsAndWeaknessesText:: + TX_FAR _StrengthsAndWeaknessesText + db "@" + +SafariZoneCheck:: + CheckEventHL EVENT_IN_SAFARI_ZONE ; if we are not in the Safari Zone, + jr z, SafariZoneGameStillGoing ; don't bother printing game over text + ld a, [wNumSafariBalls] + and a + jr z, SafariZoneGameOver + jr SafariZoneGameStillGoing + +SafariZoneCheckSteps:: + ld a, [wSafariSteps] + ld b, a + ld a, [wSafariSteps + 1] + ld c, a + or b + jr z, SafariZoneGameOver + dec bc + ld a, b + ld [wSafariSteps], a + ld a, c + ld [wSafariSteps + 1], a +SafariZoneGameStillGoing: + xor a + ld [wSafariZoneGameOver], a + ret + +SafariZoneGameOver: + call EnableAutoTextBoxDrawing + xor a + ld [wAudioFadeOutControl], a + dec a + call PlaySound + ld c, BANK(SFX_Safari_Zone_PA) + ld a, SFX_SAFARI_ZONE_PA + call PlayMusic +.waitForMusicToPlay + ld a, [wChannelSoundIDs + Ch5] + cp SFX_SAFARI_ZONE_PA + jr nz, .waitForMusicToPlay + ld a, TEXT_SAFARI_GAME_OVER + ld [hSpriteIndexOrTextID], a + call DisplayTextID + xor a + ld [wPlayerMovingDirection], a + ld a, SAFARI_ZONE_GATE + ld [hWarpDestinationMap], a + ld a, $3 + ld [wDestinationWarpID], a + ld a, $5 + ld [wSafariZoneGateCurScript], a + SetEvent EVENT_SAFARI_GAME_OVER + ld a, 1 + ld [wSafariZoneGameOver], a + ret + +PrintSafariGameOverText:: + xor a + ld [wJoyIgnore], a + ld hl, SafariGameOverText + jp PrintText + +SafariGameOverText: + TX_ASM + ld a, [wNumSafariBalls] + and a + jr z, .noMoreSafariBalls + ld hl, TimesUpText + call PrintText +.noMoreSafariBalls + ld hl, GameOverText + call PrintText + jp TextScriptEnd + +TimesUpText: + TX_FAR _TimesUpText + db "@" + +GameOverText: + TX_FAR _GameOverText + db "@" + +PrintCinnabarQuiz: + ld a, [wSpriteStateData1 + 9] + cp SPRITE_FACING_UP + ret nz + call EnableAutoTextBoxDrawing + tx_pre_jump CinnabarGymQuiz + +CinnabarGymQuiz:: + TX_ASM + xor a + ld [wOpponentAfterWrongAnswer], a + ld a, [wHiddenObjectFunctionArgument] + push af + and $f + ld [hGymGateIndex], a + pop af + and $f0 + swap a + ld [$ffdc], a + ld hl, CinnabarGymQuizIntroText + call PrintText + ld a, [hGymGateIndex] + dec a + add a + ld d, 0 + ld e, a + ld hl, CinnabarQuizQuestions + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + call PrintText + ld a, 1 + ld [wDoNotWaitForButtonPressAfterDisplayingText], a + call CinnabarGymQuiz_1ea92 + jp TextScriptEnd + +CinnabarGymQuizIntroText: + TX_FAR _CinnabarGymQuizIntroText + db "@" + +CinnabarQuizQuestions: + dw CinnabarQuizQuestionsText1 + dw CinnabarQuizQuestionsText2 + dw CinnabarQuizQuestionsText3 + dw CinnabarQuizQuestionsText4 + dw CinnabarQuizQuestionsText5 + dw CinnabarQuizQuestionsText6 + +CinnabarQuizQuestionsText1: + TX_FAR _CinnabarQuizQuestionsText1 + db "@" + +CinnabarQuizQuestionsText2: + TX_FAR _CinnabarQuizQuestionsText2 + db "@" + +CinnabarQuizQuestionsText3: + TX_FAR _CinnabarQuizQuestionsText3 + db "@" + +CinnabarQuizQuestionsText4: + TX_FAR _CinnabarQuizQuestionsText4 + db "@" + +CinnabarQuizQuestionsText5: + TX_FAR _CinnabarQuizQuestionsText5 + db "@" + +CinnabarQuizQuestionsText6: + TX_FAR _CinnabarQuizQuestionsText6 + db "@" + +CinnabarGymGateFlagAction: + EventFlagAddress hl, EVENT_CINNABAR_GYM_GATE0_UNLOCKED + predef_jump FlagActionPredef + +CinnabarGymQuiz_1ea92: + call YesNoChoice + ld a, [$ffdc] + ld c, a + ld a, [wCurrentMenuItem] + cp c + jr nz, .wrongAnswer + ld hl, wCurrentMapScriptFlags + set 5, [hl] + ld a, [hGymGateIndex] + ld [$ffe0], a + ld hl, CinnabarGymQuizCorrectText + call PrintText + ld a, [$ffe0] + AdjustEventBit EVENT_CINNABAR_GYM_GATE0_UNLOCKED, 0 + ld c, a + ld b, FLAG_SET + call CinnabarGymGateFlagAction + jp UpdateCinnabarGymGateTileBlocks_ +.wrongAnswer + call WaitForSoundToFinish + ld a, SFX_DENIED + call PlaySound + call WaitForSoundToFinish + ld hl, CinnabarGymQuizIncorrectText + call PrintText + ld a, [hGymGateIndex] + add $2 + AdjustEventBit EVENT_BEAT_CINNABAR_GYM_TRAINER_0, 2 + ld c, a + ld b, FLAG_TEST + EventFlagAddress hl, EVENT_BEAT_CINNABAR_GYM_TRAINER_0 + predef FlagActionPredef + ld a, c + and a + ret nz + ld a, [hGymGateIndex] + add $2 + ld [wOpponentAfterWrongAnswer], a + ret + +CinnabarGymQuizCorrectText: + TX_SFX_ITEM_1 + TX_FAR _CinnabarGymQuizCorrectText + TX_BLINK + TX_ASM + + ld a, [$ffe0] + AdjustEventBit EVENT_CINNABAR_GYM_GATE0_UNLOCKED, 0 + ld c, a + ld b, FLAG_TEST + call CinnabarGymGateFlagAction + ld a, c + and a + jp nz, TextScriptEnd + call WaitForSoundToFinish + ld a, SFX_GO_INSIDE + call PlaySound + call WaitForSoundToFinish + jp TextScriptEnd + +CinnabarGymQuizIncorrectText: + TX_FAR _CinnabarGymQuizIncorrectText + db "@" + +UpdateCinnabarGymGateTileBlocks_:: +; Update the overworld map with open floor blocks or locked gate blocks +; depending on event flags. + ld a, 6 + ld [hGymGateIndex], a +.loop + ld a, [hGymGateIndex] + dec a + add a + add a + ld d, 0 + ld e, a + ld hl, CinnabarGymGateCoords + add hl, de + ld a, [hli] + ld b, [hl] + ld c, a + inc hl + ld a, [hl] + ld [wGymGateTileBlock], a + push bc + ld a, [hGymGateIndex] + ld [$ffe0], a + AdjustEventBit EVENT_CINNABAR_GYM_GATE0_UNLOCKED, 0 + ld c, a + ld b, FLAG_TEST + call CinnabarGymGateFlagAction + ld a, c + and a + jr nz, .unlocked + ld a, [wGymGateTileBlock] + jr .next +.unlocked + ld a, $e +.next + pop bc + ld [wNewTileBlockID], a + predef ReplaceTileBlock + ld hl, hGymGateIndex + dec [hl] + jr nz, .loop + ret + +CinnabarGymGateCoords: + ; format: x-coord, y-coord, direction, padding + ; direction: $54 = horizontal gate, $5f = vertical gate + db $09,$03,$54,$00 + db $06,$03,$54,$00 + db $06,$06,$54,$00 + db $03,$08,$5f,$00 + db $02,$06,$54,$00 + db $02,$03,$54,$00 + +PrintMagazinesText: + call EnableAutoTextBoxDrawing + tx_pre MagazinesText + ret + +MagazinesText:: + TX_FAR _MagazinesText + db "@" + +BillsHousePC: + call EnableAutoTextBoxDrawing + ld a, [wSpriteStateData1 + 9] + cp SPRITE_FACING_UP + ret nz + CheckEvent EVENT_LEFT_BILLS_HOUSE_AFTER_HELPING + jr nz, .displayBillsHousePokemonList + CheckEventReuseA EVENT_USED_CELL_SEPARATOR_ON_BILL + jr nz, .displayBillsHouseMonitorText + CheckEventReuseA EVENT_BILL_SAID_USE_CELL_SEPARATOR + jr nz, .doCellSeparator +.displayBillsHouseMonitorText + tx_pre_jump BillsHouseMonitorText +.doCellSeparator + ld a, $1 + ld [wDoNotWaitForButtonPressAfterDisplayingText], a + tx_pre BillsHouseInitiatedText + ld c, 32 + call DelayFrames + ld a, SFX_TINK + call PlaySound + call WaitForSoundToFinish + ld c, 80 + call DelayFrames + ld a, SFX_SHRINK + call PlaySound + call WaitForSoundToFinish + ld c, 48 + call DelayFrames + ld a, SFX_TINK + call PlaySound + call WaitForSoundToFinish + ld c, 32 + call DelayFrames + ld a, SFX_GET_ITEM_1 + call PlaySound + call WaitForSoundToFinish + call PlayDefaultMusic + SetEvent EVENT_USED_CELL_SEPARATOR_ON_BILL + ret +.displayBillsHousePokemonList + ld a, $1 + ld [wDoNotWaitForButtonPressAfterDisplayingText], a + tx_pre BillsHousePokemonList + ret + +BillsHouseMonitorText:: + TX_FAR _BillsHouseMonitorText + db "@" + +BillsHouseInitiatedText:: + TX_FAR _BillsHouseInitiatedText + TX_BLINK + TX_ASM + ld a, $ff + ld [wNewSoundID], a + call PlaySound + ld c, 16 + call DelayFrames + ld a, SFX_SWITCH + call PlaySound + call WaitForSoundToFinish + ld c, 60 + call DelayFrames + jp TextScriptEnd + +BillsHousePokemonList:: + TX_ASM + call SaveScreenTilesToBuffer1 + ld hl, BillsHousePokemonListText1 + call PrintText + xor a + ld [wMenuItemOffset], a ; not used + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + ld a, A_BUTTON | B_BUTTON + ld [wMenuWatchedKeys], a + ld a, 4 + ld [wMaxMenuItem], a + ld a, 2 + ld [wTopMenuItemY], a + ld a, 1 + ld [wTopMenuItemX], a +.billsPokemonLoop + ld hl, wd730 + set 6, [hl] + coord hl, 0, 0 + ld b, 10 + ld c, 9 + call TextBoxBorder + coord hl, 2, 2 + ld de, BillsMonListText + call PlaceString + ld hl, BillsHousePokemonListText2 + call PrintText + call SaveScreenTilesToBuffer2 + call HandleMenuInput + bit 1, a ; pressed b + jr nz, .cancel + ld a, [wCurrentMenuItem] + add EEVEE + cp EEVEE + jr z, .displayPokedex + cp FLAREON + jr z, .displayPokedex + cp JOLTEON + jr z, .displayPokedex + cp VAPOREON + jr z, .displayPokedex + jr .cancel +.displayPokedex + call DisplayPokedex + call LoadScreenTilesFromBuffer2 + jr .billsPokemonLoop +.cancel + ld hl, wd730 + res 6, [hl] + call LoadScreenTilesFromBuffer2 + jp TextScriptEnd + +BillsHousePokemonListText1: + TX_FAR _BillsHousePokemonListText1 + db "@" + +BillsMonListText: + db "EEVEE" + next "FLAREON" + next "JOLTEON" + next "VAPOREON" + next "CANCEL@" + +BillsHousePokemonListText2: + TX_FAR _BillsHousePokemonListText2 + db "@" + +DisplayOakLabEmailText: + ld a, [wSpriteStateData1 + 9] + cp SPRITE_FACING_UP + ret nz + call EnableAutoTextBoxDrawing + tx_pre_jump OakLabEmailText + +OakLabEmailText:: + TX_FAR _OakLabEmailText + db "@" diff --git a/engine/events/in_game_trades.asm b/engine/events/in_game_trades.asm new file mode 100755 index 00000000..c01bc3c3 --- /dev/null +++ b/engine/events/in_game_trades.asm @@ -0,0 +1,330 @@ +DoInGameTradeDialogue: +; trigger the trade offer/action specified by wWhichTrade + 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 a, [hli] + ld [wInGameTradeGiveMonSpecies], a + ld a, [hli] + ld [wInGameTradeReceiveMonSpecies], a + ld a, [hli] + push af + ld de, wInGameTradeMonNick + ld bc, NAME_LENGTH + call CopyData + pop af + ld l, a + ld h, 0 + ld de, InGameTradeTextPointers + add hl, hl + add hl, de + ld a, [hli] + ld [wInGameTradeTextPointerTablePointer], a + ld a, [hl] + ld [wInGameTradeTextPointerTablePointer + 1], a + ld a, [wInGameTradeGiveMonSpecies] + ld de, wInGameTradeGiveMonName + call InGameTrade_GetMonName + ld a, [wInGameTradeReceiveMonSpecies] + ld de, wInGameTradeReceiveMonName + call InGameTrade_GetMonName + ld hl, wCompletedInGameTradeFlags + ld a, [wWhichTrade] + ld c, a + ld b, FLAG_TEST + predef 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 [wInGameTradeTextPointerTableIndex], a + call .printText + ld a, $1 + ld [wInGameTradeTextPointerTableIndex], a + call YesNoChoice + ld a, [wCurrentMenuItem] + and a + jr nz, .printText + call InGameTrade_DoTrade + jr c, .printText + ld hl, TradedForText + call PrintText +.printText + ld hl, wInGameTradeTextPointerTableIndex + ld a, [hld] ; wInGameTradeTextPointerTableIndex + ld e, a + ld d, 0 + ld a, [hld] ; wInGameTradeTextPointerTablePointer + 1 + ld l, [hl] ; wInGameTradeTextPointerTablePointer + ld h, a + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + jp PrintText + +; copies name of species a to hl +InGameTrade_GetMonName: + push de + ld [wd11e], a + call GetMonName + ld hl, wcd6d + pop de + ld bc, NAME_LENGTH + jp CopyData + +INCLUDE "data/trades.asm" + +InGameTrade_DoTrade: + xor a ; NORMAL_PARTY_MENU + ld [wPartyMenuTypeOrMessageID], a + dec a + ld [wUpdateSpritesEnabled], a + call DisplayPartyMenu + push af + call InGameTrade_RestoreScreen + pop af + ld a, $1 + jp c, .tradeFailed ; jump if the player didn't select a pokemon + ld a, [wInGameTradeGiveMonSpecies] + ld b, a + ld a, [wcf91] + cp b + ld a, $2 + jr nz, .tradeFailed ; jump if the selected mon's species is not the required one + ld a, [wWhichPokemon] + ld hl, wPartyMon1Level + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld a, [hl] + ld [wCurEnemyLVL], a + ld hl, wCompletedInGameTradeFlags + ld a, [wWhichTrade] + ld c, a + ld b, FLAG_SET + predef FlagActionPredef + ld hl, ConnectCableText + call PrintText + ld a, [wWhichPokemon] + push af + ld a, [wCurEnemyLVL] + push af + call LoadHpBarAndStatusTilePatterns + call InGameTrade_PrepareTradeData + predef InternalClockTradeAnim + pop af + ld [wCurEnemyLVL], a + pop af + ld [wWhichPokemon], a + ld a, [wInGameTradeReceiveMonSpecies] + ld [wcf91], a + xor a + ld [wMonDataLocation], a ; not used + ld [wRemoveMonFromBox], a + call RemovePokemon + ld a, $80 ; prevent the player from naming the mon + ld [wMonDataLocation], a + call AddPartyMon + call InGameTrade_CopyDataToReceivedMon + callab EvolveTradeMon + call ClearScreen + call InGameTrade_RestoreScreen + callba RedrawMapView + and a + ld a, $3 + jr .tradeSucceeded +.tradeFailed + scf +.tradeSucceeded + ld [wInGameTradeTextPointerTableIndex], a + ret + +InGameTrade_RestoreScreen: + call GBPalWhiteOutWithDelay3 + call RestoreScreenTilesAndReloadTilePatterns + call ReloadTilesetTilePatterns + call LoadScreenTilesFromBuffer2 + call Delay3 + call LoadGBPal + ld c, 10 + call DelayFrames + jpba LoadWildData + +InGameTrade_PrepareTradeData: + ld hl, wTradedPlayerMonSpecies + ld a, [wInGameTradeGiveMonSpecies] + ld [hli], a ; wTradedPlayerMonSpecies + ld a, [wInGameTradeReceiveMonSpecies] + ld [hl], a ; wTradedEnemyMonSpecies + ld hl, wPartyMonOT + ld bc, NAME_LENGTH + ld a, [wWhichPokemon] + call AddNTimes + ld de, wTradedPlayerMonOT + ld bc, NAME_LENGTH + call InGameTrade_CopyData + ld hl, InGameTrade_TrainerString + ld de, wTradedEnemyMonOT + call InGameTrade_CopyData + ld de, wLinkEnemyTrainerName + call InGameTrade_CopyData + ld hl, wPartyMon1OTID + ld bc, wPartyMon2 - wPartyMon1 + ld a, [wWhichPokemon] + call AddNTimes + ld de, wTradedPlayerMonOTID + ld bc, $2 + call InGameTrade_CopyData + call Random + ld hl, hRandomAdd + ld de, wTradedEnemyMonOTID + jp CopyData + +InGameTrade_CopyData: + push hl + push bc + call CopyData + pop bc + pop hl + ret + +InGameTrade_CopyDataToReceivedMon: + ld hl, wPartyMonNicks + ld bc, NAME_LENGTH + call InGameTrade_GetReceivedMonPointer + ld hl, wInGameTradeMonNick + ld bc, NAME_LENGTH + call CopyData + ld hl, wPartyMonOT + ld bc, NAME_LENGTH + call InGameTrade_GetReceivedMonPointer + ld hl, InGameTrade_TrainerString + ld bc, NAME_LENGTH + call CopyData + ld hl, wPartyMon1OTID + ld bc, wPartyMon2 - wPartyMon1 + call InGameTrade_GetReceivedMonPointer + ld hl, wTradedEnemyMonOTID + ld bc, $2 + jp CopyData + +; the received mon's index is (partyCount - 1), +; so this adds bc to hl (partyCount - 1) times and moves the result to de +InGameTrade_GetReceivedMonPointer: + ld a, [wPartyCount] + dec a + call AddNTimes + ld e, l + ld d, h + ret + +InGameTrade_TrainerString: + ; "TRAINER@@@@@@@@@@" + db $5d, "@@@@@@@@@@" + +InGameTradeTextPointers: + dw TradeTextPointers1 + dw TradeTextPointers2 + dw TradeTextPointers3 + +TradeTextPointers1: + dw WannaTrade1Text + dw NoTrade1Text + dw WrongMon1Text + dw Thanks1Text + dw AfterTrade1Text + +TradeTextPointers2: + dw WannaTrade2Text + dw NoTrade2Text + dw WrongMon2Text + dw Thanks2Text + dw AfterTrade2Text + +TradeTextPointers3: + dw WannaTrade3Text + dw NoTrade3Text + dw WrongMon3Text + dw Thanks3Text + dw AfterTrade3Text + +ConnectCableText: + TX_FAR _ConnectCableText + db "@" + +TradedForText: + TX_FAR _TradedForText + TX_SFX_KEY_ITEM + TX_DELAY + db "@" + +WannaTrade1Text: + TX_FAR _WannaTrade1Text + db "@" + +NoTrade1Text: + TX_FAR _NoTrade1Text + db "@" + +WrongMon1Text: + TX_FAR _WrongMon1Text + db "@" + +Thanks1Text: + TX_FAR _Thanks1Text + db "@" + +AfterTrade1Text: + TX_FAR _AfterTrade1Text + db "@" + +WannaTrade2Text: + TX_FAR _WannaTrade2Text + db "@" + +NoTrade2Text: + TX_FAR _NoTrade2Text + db "@" + +WrongMon2Text: + TX_FAR _WrongMon2Text + db "@" + +Thanks2Text: + TX_FAR _Thanks2Text + db "@" + +AfterTrade2Text: + TX_FAR _AfterTrade2Text + db "@" + +WannaTrade3Text: + TX_FAR _WannaTrade3Text + db "@" + +NoTrade3Text: + TX_FAR _NoTrade3Text + db "@" + +WrongMon3Text: + TX_FAR _WrongMon3Text + db "@" + +Thanks3Text: + TX_FAR _Thanks3Text + db "@" + +AfterTrade3Text: + TX_FAR _AfterTrade3Text + db "@" diff --git a/engine/events/oaks_aide.asm b/engine/events/oaks_aide.asm new file mode 100755 index 00000000..f5068fda --- /dev/null +++ b/engine/events/oaks_aide.asm @@ -0,0 +1,71 @@ +OaksAideScript: + ld hl, OaksAideHiText + call PrintText + call YesNoChoice + ld a, [wCurrentMenuItem] + and a + jr nz, .choseNo + ld hl, wPokedexOwned + ld b, wPokedexOwnedEnd - wPokedexOwned + call CountSetBits + ld a, [wNumSetBits] + ld [hOaksAideNumMonsOwned], a + ld b, a + ld a, [hOaksAideRequirement] + cp b + jr z, .giveItem + jr nc, .notEnoughOwnedMons +.giveItem + ld hl, OaksAideHereYouGoText + call PrintText + ld a, [hOaksAideRewardItem] + ld b, a + ld c, 1 + call GiveItem + jr nc, .bagFull + ld hl, OaksAideGotItemText + call PrintText + ld a, $1 + jr .done +.bagFull + ld hl, OaksAideNoRoomText + call PrintText + xor a + jr .done +.notEnoughOwnedMons + ld hl, OaksAideUhOhText + call PrintText + ld a, $80 + jr .done +.choseNo + ld hl, OaksAideComeBackText + call PrintText + ld a, $ff +.done + ld [hOaksAideResult], a + ret + +OaksAideHiText: + TX_FAR _OaksAideHiText + db "@" + +OaksAideUhOhText: + TX_FAR _OaksAideUhOhText + db "@" + +OaksAideComeBackText: + TX_FAR _OaksAideComeBackText + db "@" + +OaksAideHereYouGoText: + TX_FAR _OaksAideHereYouGoText + db "@" + +OaksAideGotItemText: + TX_FAR _OaksAideGotItemText + TX_SFX_ITEM_1 + db "@" + +OaksAideNoRoomText: + TX_FAR _OaksAideNoRoomText + db "@" diff --git a/engine/events/pewter_guys.asm b/engine/events/pewter_guys.asm new file mode 100755 index 00000000..532fa4bf --- /dev/null +++ b/engine/events/pewter_guys.asm @@ -0,0 +1,102 @@ +PewterGuys: + ld hl, wSimulatedJoypadStatesEnd + ld a, [wSimulatedJoypadStatesIndex] + dec a ; this decrement causes it to overwrite the last byte before $FF in the list + ld [wSimulatedJoypadStatesIndex], a + ld d, 0 + ld e, a + add hl, de + ld d, h + ld e, l + ld hl, PointerTable_37ce6 + ld a, [wWhichPewterGuy] + add a + ld b, 0 + ld c, a + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wYCoord] + ld b, a + ld a, [wXCoord] + ld c, a +.findMatchingCoordsLoop + ld a, [hli] + cp b + jr nz, .nextEntry1 + ld a, [hli] + cp c + jr nz, .nextEntry2 + ld a, [hli] + ld h, [hl] + ld l, a +.copyMovementDataLoop + ld a, [hli] + cp $ff + ret z + ld [de], a + inc de + ld a, [wSimulatedJoypadStatesIndex] + inc a + ld [wSimulatedJoypadStatesIndex], a + jr .copyMovementDataLoop +.nextEntry1 + inc hl +.nextEntry2 + inc hl + inc hl + jr .findMatchingCoordsLoop + +PointerTable_37ce6: + dw PewterMuseumGuyCoords + dw PewterGymGuyCoords + +; these are the four coordinates of the spaces below, above, to the left and +; to the right of the museum guy, and pointers to different movements for +; the player to make to get positioned before the main movement. +PewterMuseumGuyCoords: + db 18, 27 + dw .down + db 16, 27 + dw .up + db 17, 26 + dw .left + db 17, 28 + dw .right + +.down + db D_UP, D_UP, $ff +.up + db D_RIGHT, D_LEFT, $ff +.left + db D_UP, D_RIGHT, $ff +.right + db D_UP, D_LEFT, $ff + +; these are the five coordinates which trigger the gym guy and pointers to +; different movements for the player to make to get positioned before the +; main movement +; $00 is a pause +PewterGymGuyCoords: + db 16, 34 + dw .one + db 17, 35 + dw .two + db 18, 37 + dw .three + db 19, 37 + dw .four + db 17, 36 + dw .five + +.one + db D_LEFT, D_DOWN, D_DOWN, D_RIGHT, $ff +.two + db D_LEFT, D_DOWN, D_RIGHT, D_LEFT, $ff +.three + db D_LEFT, D_LEFT, D_LEFT, $00, $00, $00, $00, $00, $00, $00, $00, $ff +.four + db D_LEFT, D_LEFT, D_UP, D_LEFT, $ff +.five + db D_LEFT, D_DOWN, D_LEFT, $00, $00, $00, $00, $00, $00, $00, $00, $ff diff --git a/engine/events/pick_up_item.asm b/engine/events/pick_up_item.asm new file mode 100644 index 00000000..9f19100a --- /dev/null +++ b/engine/events/pick_up_item.asm @@ -0,0 +1,54 @@ +PickUpItem: + call EnableAutoTextBoxDrawing + + ld a, [hSpriteIndexOrTextID] + ld b, a + ld hl, wMissableObjectList +.missableObjectsListLoop + ld a, [hli] + cp $ff + ret z + cp b + jr z, .isMissable + inc hl + jr .missableObjectsListLoop + +.isMissable + ld a, [hl] + ld [$ffdb], a + + ld hl, wMapSpriteExtraData + ld a, [hSpriteIndexOrTextID] + dec a + add a + ld d, 0 + ld e, a + add hl, de + ld a, [hl] + ld b, a ; item + ld c, 1 ; quantity + call GiveItem + jr nc, .BagFull + + ld a, [$ffdb] + ld [wMissableObjectIndex], a + predef HideObject + ld a, 1 + ld [wDoNotWaitForButtonPressAfterDisplayingText], a + ld hl, FoundItemText + jr .print + +.BagFull + ld hl, NoMoreRoomForItemText +.print + call PrintText + ret + +FoundItemText: + TX_FAR _FoundItemText + TX_SFX_ITEM_1 + db "@" + +NoMoreRoomForItemText: + TX_FAR _NoMoreRoomForItemText + db "@" diff --git a/engine/events/poison.asm b/engine/events/poison.asm new file mode 100644 index 00000000..5d8eb9fd --- /dev/null +++ b/engine/events/poison.asm @@ -0,0 +1,112 @@ +ApplyOutOfBattlePoisonDamage: + ld a, [wd730] + add a + jp c, .noBlackOut ; no black out if joypad states are being simulated + ld a, [wPartyCount] + and a + jp z, .noBlackOut + call IncrementDayCareMonExp + ld a, [wStepCounter] + and $3 ; is the counter a multiple of 4? + jp nz, .noBlackOut ; only apply poison damage every fourth step + ld [wWhichPokemon], a + ld hl, wPartyMon1Status + ld de, wPartySpecies +.applyDamageLoop + ld a, [hl] + and (1 << PSN) + jr z, .nextMon2 ; not poisoned + dec hl + dec hl + ld a, [hld] + ld b, a + ld a, [hli] + or b + jr z, .nextMon ; already fainted +; subtract 1 from HP + ld a, [hl] + dec a + ld [hld], a + inc a + jr nz, .noBorrow +; borrow 1 from upper byte of HP + dec [hl] + inc hl + jr .nextMon +.noBorrow + ld a, [hli] + or [hl] + jr nz, .nextMon ; didn't faint from damage +; the mon fainted from the damage + push hl + inc hl + inc hl + ld [hl], a + ld a, [de] + ld [wd11e], a + push de + ld a, [wWhichPokemon] + ld hl, wPartyMonNicks + call GetPartyMonName + xor a + ld [wJoyIgnore], a + call EnableAutoTextBoxDrawing + ld a, TEXT_MON_FAINTED + ld [hSpriteIndexOrTextID], a + call DisplayTextID + pop de + pop hl +.nextMon + inc hl + inc hl +.nextMon2 + inc de + ld a, [de] + inc a + jr z, .applyDamageLoopDone + ld bc, wPartyMon2 - wPartyMon1 + add hl, bc + push hl + ld hl, wWhichPokemon + inc [hl] + pop hl + jr .applyDamageLoop +.applyDamageLoopDone + ld hl, wPartyMon1Status + ld a, [wPartyCount] + ld d, a + ld e, 0 +.countPoisonedLoop + ld a, [hl] + and (1 << PSN) + or e + ld e, a + ld bc, wPartyMon2 - wPartyMon1 + add hl, bc + dec d + jr nz, .countPoisonedLoop + ld a, e + and a ; are any party members poisoned? + jr z, .skipPoisonEffectAndSound + ld b, $2 + predef ChangeBGPalColor0_4Frames ; change BG white to dark grey for 4 frames + ld a, SFX_POISONED + call PlaySound +.skipPoisonEffectAndSound + predef AnyPartyAlive + ld a, d + and a + jr nz, .noBlackOut + call EnableAutoTextBoxDrawing + ld a, TEXT_BLACKED_OUT + ld [hSpriteIndexOrTextID], a + call DisplayTextID + ld hl, wd72e + set 5, [hl] + ld a, $ff + jr .done +.noBlackOut + xor a +.done + ld [wOutOfBattleBlackout], a + ret diff --git a/engine/events/pokecenter.asm b/engine/events/pokecenter.asm new file mode 100755 index 00000000..f340e06d --- /dev/null +++ b/engine/events/pokecenter.asm @@ -0,0 +1,68 @@ +DisplayPokemonCenterDialogue_:: + call SaveScreenTilesToBuffer1 ; save screen + ld hl, PokemonCenterWelcomeText + call PrintText + ld hl, wd72e + bit 2, [hl] + set 1, [hl] + set 2, [hl] + jr nz, .skipShallWeHealYourPokemon + ld hl, ShallWeHealYourPokemonText + call PrintText +.skipShallWeHealYourPokemon + call YesNoChoicePokeCenter ; yes/no menu + ld a, [wCurrentMenuItem] + and a + jr nz, .declinedHealing ; if the player chose No + call SetLastBlackoutMap + call LoadScreenTilesFromBuffer1 ; restore screen + ld hl, NeedYourPokemonText + call PrintText + ld a, $18 + ld [wSpriteStateData1 + $12], a ; make the nurse turn to face the machine + call Delay3 + predef HealParty + callba AnimateHealingMachine ; do the healing machine animation + xor a + ld [wAudioFadeOutControl], a + ld a, [wAudioSavedROMBank] + ld [wAudioROMBank], a + ld a, [wMapMusicSoundID] + ld [wLastMusicSoundID], a + ld [wNewSoundID], a + call PlaySound + ld hl, PokemonFightingFitText + call PrintText + ld a, $14 + ld [wSpriteStateData1 + $12], a ; make the nurse bow + ld c, a + call DelayFrames + jr .done +.declinedHealing + call LoadScreenTilesFromBuffer1 ; restore screen +.done + ld hl, PokemonCenterFarewellText + call PrintText + jp UpdateSprites + +PokemonCenterWelcomeText: + TX_FAR _PokemonCenterWelcomeText + db "@" + +ShallWeHealYourPokemonText: + TX_DELAY + TX_FAR _ShallWeHealYourPokemonText + db "@" + +NeedYourPokemonText: + TX_FAR _NeedYourPokemonText + db "@" + +PokemonFightingFitText: + TX_FAR _PokemonFightingFitText + db "@" + +PokemonCenterFarewellText: + TX_DELAY + TX_FAR _PokemonCenterFarewellText + db "@" diff --git a/engine/events/pokedex_rating.asm b/engine/events/pokedex_rating.asm new file mode 100755 index 00000000..f1aaf618 --- /dev/null +++ b/engine/events/pokedex_rating.asm @@ -0,0 +1,154 @@ +DisplayDexRating: + ld hl, wPokedexSeen + ld b, wPokedexSeenEnd - wPokedexSeen + call CountSetBits + ld a, [wNumSetBits] + ld [hDexRatingNumMonsSeen], a + ld hl, wPokedexOwned + ld b, wPokedexOwnedEnd - wPokedexOwned + call CountSetBits + ld a, [wNumSetBits] + ld [hDexRatingNumMonsOwned], a + ld hl, DexRatingsTable +.findRating + ld a, [hli] + ld b, a + ld a, [hDexRatingNumMonsOwned] + cp b + jr c, .foundRating + inc hl + inc hl + jr .findRating +.foundRating + ld a, [hli] + ld h, [hl] + ld l, a ; load text pointer into hl + CheckAndResetEventA EVENT_HALL_OF_FAME_DEX_RATING + jr nz, .hallOfFame + push hl + ld hl, PokedexRatingText_441cc + call PrintText + pop hl + call PrintText + callba PlayPokedexRatingSfx + jp WaitForTextScrollButtonPress +.hallOfFame + ld de, wDexRatingNumMonsSeen + ld a, [hDexRatingNumMonsSeen] + ld [de], a + inc de + ld a, [hDexRatingNumMonsOwned] + ld [de], a + inc de +.copyRatingTextLoop + ld a, [hli] + cp "@" + jr z, .doneCopying + ld [de], a + inc de + jr .copyRatingTextLoop +.doneCopying + ld [de], a + ret + +PokedexRatingText_441cc: + TX_FAR _OaksLabText_441cc + db "@" + +DexRatingsTable: + db 10 + dw PokedexRatingText_44201 + db 20 + dw PokedexRatingText_44206 + db 30 + dw PokedexRatingText_4420b + db 40 + dw PokedexRatingText_44210 + db 50 + dw PokedexRatingText_44215 + db 60 + dw PokedexRatingText_4421a + db 70 + dw PokedexRatingText_4421f + db 80 + dw PokedexRatingText_44224 + db 90 + dw PokedexRatingText_44229 + db 100 + dw PokedexRatingText_4422e + db 110 + dw PokedexRatingText_44233 + db 120 + dw PokedexRatingText_44238 + db 130 + dw PokedexRatingText_4423d + db 140 + dw PokedexRatingText_44242 + db 150 + dw PokedexRatingText_44247 + db NUM_POKEMON + 1 + dw PokedexRatingText_4424c + +PokedexRatingText_44201: + TX_FAR _OaksLabText_44201 + db "@" + +PokedexRatingText_44206: + TX_FAR _OaksLabText_44206 + db "@" + +PokedexRatingText_4420b: + TX_FAR _OaksLabText_4420b + db "@" + +PokedexRatingText_44210: + TX_FAR _OaksLabText_44210 + db "@" + +PokedexRatingText_44215: + TX_FAR _OaksLabText_44215 + db "@" + +PokedexRatingText_4421a: + TX_FAR _OaksLabText_4421a + db "@" + +PokedexRatingText_4421f: + TX_FAR _OaksLabText_4421f + db "@" + +PokedexRatingText_44224: + TX_FAR _OaksLabText_44224 + db "@" + +PokedexRatingText_44229: + TX_FAR _OaksLabText_44229 + db "@" + +PokedexRatingText_4422e: + TX_FAR _OaksLabText_4422e + db "@" + +PokedexRatingText_44233: + TX_FAR _OaksLabText_44233 + db "@" + +PokedexRatingText_44238: + TX_FAR _OaksLabText_44238 + db "@" + +PokedexRatingText_4423d: + TX_FAR _OaksLabText_4423d + db "@" + +PokedexRatingText_44242: + TX_FAR _OaksLabText_44242 + db "@" + +PokedexRatingText_44247: + TX_FAR _OaksLabText_44247 + db "@" + +PokedexRatingText_4424c: + TX_FAR _OaksLabText_4424c + db "@" diff --git a/engine/events/pokemart.asm b/engine/events/pokemart.asm new file mode 100755 index 00000000..177e8a09 --- /dev/null +++ b/engine/events/pokemart.asm @@ -0,0 +1,272 @@ +DisplayPokemartDialogue_:: + ld a, [wListScrollOffset] + ld [wSavedListScrollOffset], a + call UpdateSprites + xor a + ld [wBoughtOrSoldItemInMart], a +.loop + xor a + ld [wListScrollOffset], a + ld [wCurrentMenuItem], a + ld [wPlayerMonNumber], a + inc a + ld [wPrintItemPrices], a + ld a, MONEY_BOX + ld [wTextBoxID], a + call DisplayTextBoxID + ld a, BUY_SELL_QUIT_MENU + ld [wTextBoxID], a + call DisplayTextBoxID + +; This code is useless. It copies the address of the pokemart's inventory to hl, +; but the address is never used. + ld hl, wItemListPointer + ld a, [hli] + ld l, [hl] + ld h, a + + ld a, [wMenuExitMethod] + cp CANCELLED_MENU + jp z, .done + ld a, [wChosenMenuItem] + and a ; buying? + jp z, .buyMenu + dec a ; selling? + jp z, .sellMenu + dec a ; quitting? + jp z, .done +.sellMenu + +; the same variables are set again below, so this code has no effect + xor a + ld [wPrintItemPrices], a + ld a, INIT_BAG_ITEM_LIST + ld [wInitListType], a + callab InitList + + ld a, [wNumBagItems] + and a + jp z, .bagEmpty + ld hl, PokemonSellingGreetingText + call PrintText + call SaveScreenTilesToBuffer1 ; save screen +.sellMenuLoop + call LoadScreenTilesFromBuffer1 ; restore saved screen + ld a, MONEY_BOX + ld [wTextBoxID], a + call DisplayTextBoxID ; draw money text box + ld hl, wNumBagItems + ld a, l + ld [wListPointer], a + ld a, h + ld [wListPointer + 1], a + xor a + ld [wPrintItemPrices], a + ld [wCurrentMenuItem], a + ld a, ITEMLISTMENU + ld [wListMenuID], a + call DisplayListMenuID + jp c, .returnToMainPokemartMenu ; if the player closed the menu +.confirmItemSale ; if the player is trying to sell a specific item + call IsKeyItem + ld a, [wIsKeyItem] + and a + jr nz, .unsellableItem + ld a, [wcf91] + call IsItemHM + jr c, .unsellableItem + ld a, PRICEDITEMLISTMENU + ld [wListMenuID], a + ld [hHalveItemPrices], a ; halve prices when selling + call DisplayChooseQuantityMenu + inc a + jr z, .sellMenuLoop ; if the player closed the choose quantity menu with the B button + ld hl, PokemartTellSellPriceText + lb bc, 14, 1 ; location that PrintText always prints to, this is useless + call PrintText + coord hl, 14, 7 + lb bc, 8, 15 + ld a, TWO_OPTION_MENU + ld [wTextBoxID], a + call DisplayTextBoxID ; yes/no menu + ld a, [wMenuExitMethod] + cp CHOSE_SECOND_ITEM + jr z, .sellMenuLoop ; if the player chose No or pressed the B button + +; The following code is supposed to check if the player chose No, but the above +; check already catches it. + ld a, [wChosenMenuItem] + dec a + jr z, .sellMenuLoop + +.sellItem + ld a, [wBoughtOrSoldItemInMart] + and a + jr nz, .skipSettingFlag1 + inc a + ld [wBoughtOrSoldItemInMart], a +.skipSettingFlag1 + call AddAmountSoldToMoney + ld hl, wNumBagItems + call RemoveItemFromInventory + jp .sellMenuLoop +.unsellableItem + ld hl, PokemartUnsellableItemText + call PrintText + jp .returnToMainPokemartMenu +.bagEmpty + ld hl, PokemartItemBagEmptyText + call PrintText + call SaveScreenTilesToBuffer1 + jp .returnToMainPokemartMenu +.buyMenu + +; the same variables are set again below, so this code has no effect + ld a, 1 + ld [wPrintItemPrices], a + ld a, INIT_OTHER_ITEM_LIST + ld [wInitListType], a + callab InitList + + ld hl, PokemartBuyingGreetingText + call PrintText + call SaveScreenTilesToBuffer1 +.buyMenuLoop + call LoadScreenTilesFromBuffer1 + ld a, MONEY_BOX + ld [wTextBoxID], a + call DisplayTextBoxID + ld hl, wItemList + ld a, l + ld [wListPointer], a + ld a, h + ld [wListPointer + 1], a + xor a + ld [wCurrentMenuItem], a + inc a + ld [wPrintItemPrices], a + inc a ; a = 2 (PRICEDITEMLISTMENU) + ld [wListMenuID], a + call DisplayListMenuID + jr c, .returnToMainPokemartMenu ; if the player closed the menu + ld a, 99 + ld [wMaxItemQuantity], a + xor a + ld [hHalveItemPrices], a ; don't halve item prices when buying + call DisplayChooseQuantityMenu + inc a + jr z, .buyMenuLoop ; if the player closed the choose quantity menu with the B button + ld a, [wcf91] ; item ID + ld [wd11e], a ; store item ID for GetItemName + call GetItemName + call CopyStringToCF4B ; copy name to wcf4b + ld hl, PokemartTellBuyPriceText + call PrintText + coord hl, 14, 7 + lb bc, 8, 15 + ld a, TWO_OPTION_MENU + ld [wTextBoxID], a + call DisplayTextBoxID ; yes/no menu + ld a, [wMenuExitMethod] + cp CHOSE_SECOND_ITEM + jp z, .buyMenuLoop ; if the player chose No or pressed the B button + +; The following code is supposed to check if the player chose No, but the above +; check already catches it. + ld a, [wChosenMenuItem] + dec a + jr z, .buyMenuLoop + +.buyItem + call .isThereEnoughMoney + jr c, .notEnoughMoney + ld hl, wNumBagItems + call AddItemToInventory + jr nc, .bagFull + call SubtractAmountPaidFromMoney + ld a, [wBoughtOrSoldItemInMart] + and a + jr nz, .skipSettingFlag2 + ld a, 1 + ld [wBoughtOrSoldItemInMart], a +.skipSettingFlag2 + ld a, SFX_PURCHASE + call PlaySoundWaitForCurrent + call WaitForSoundToFinish + ld hl, PokemartBoughtItemText + call PrintText + jp .buyMenuLoop +.returnToMainPokemartMenu + call LoadScreenTilesFromBuffer1 + ld a, MONEY_BOX + ld [wTextBoxID], a + call DisplayTextBoxID + ld hl, PokemartAnythingElseText + call PrintText + jp .loop +.isThereEnoughMoney + ld de, wPlayerMoney + ld hl, hMoney + ld c, 3 ; length of money in bytes + jp StringCmp +.notEnoughMoney + ld hl, PokemartNotEnoughMoneyText + call PrintText + jr .returnToMainPokemartMenu +.bagFull + ld hl, PokemartItemBagFullText + call PrintText + jr .returnToMainPokemartMenu +.done + ld hl, PokemartThankYouText + call PrintText + ld a, 1 + ld [wUpdateSpritesEnabled], a + call UpdateSprites + ld a, [wSavedListScrollOffset] + ld [wListScrollOffset], a + ret + +PokemartBuyingGreetingText: + TX_FAR _PokemartBuyingGreetingText + db "@" + +PokemartTellBuyPriceText: + TX_FAR _PokemartTellBuyPriceText + db "@" + +PokemartBoughtItemText: + TX_FAR _PokemartBoughtItemText + db "@" + +PokemartNotEnoughMoneyText: + TX_FAR _PokemartNotEnoughMoneyText + db "@" + +PokemartItemBagFullText: + TX_FAR _PokemartItemBagFullText + db "@" + +PokemonSellingGreetingText: + TX_FAR _PokemonSellingGreetingText + db "@" + +PokemartTellSellPriceText: + TX_FAR _PokemartTellSellPriceText + db "@" + +PokemartItemBagEmptyText: + TX_FAR _PokemartItemBagEmptyText + db "@" + +PokemartUnsellableItemText: + TX_FAR _PokemartUnsellableItemText + db "@" + +PokemartThankYouText: + TX_FAR _PokemartThankYouText + db "@" + +PokemartAnythingElseText: + TX_FAR _PokemartAnythingElseText + db "@" diff --git a/engine/events/prize_menu.asm b/engine/events/prize_menu.asm new file mode 100755 index 00000000..5e08bb8f --- /dev/null +++ b/engine/events/prize_menu.asm @@ -0,0 +1,306 @@ +CeladonPrizeMenu:: + ld b, COIN_CASE + call IsItemInBag + jr nz, .havingCoinCase + ld hl, RequireCoinCaseTextPtr + jp PrintText +.havingCoinCase + ld hl, wd730 + set 6, [hl] ; disable letter-printing delay + ld hl, ExchangeCoinsForPrizesTextPtr + call PrintText +; the following are the menu settings + xor a + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + ld a, A_BUTTON | B_BUTTON + ld [wMenuWatchedKeys], a + ld a, $03 + ld [wMaxMenuItem], a + ld a, $04 + ld [wTopMenuItemY], a + ld a, $01 + ld [wTopMenuItemX], a + call PrintPrizePrice + coord hl, 0, 2 + ld b, 8 + ld c, 16 + call TextBoxBorder + call GetPrizeMenuId + call UpdateSprites + ld hl, WhichPrizeTextPtr + call PrintText + call HandleMenuInput ; menu choice handler + bit 1, a ; keypress = B (Cancel) + jr nz, .noChoice + ld a, [wCurrentMenuItem] + cp 3 ; "NO,THANKS" choice + jr z, .noChoice + call HandlePrizeChoice +.noChoice + ld hl, wd730 + res 6, [hl] + ret + +RequireCoinCaseTextPtr: + TX_FAR _RequireCoinCaseText + TX_WAIT + db "@" + +ExchangeCoinsForPrizesTextPtr: + TX_FAR _ExchangeCoinsForPrizesText + db "@" + +WhichPrizeTextPtr: + TX_FAR _WhichPrizeText + db "@" + +GetPrizeMenuId: +; determine which one among the three +; prize-texts has been selected +; using the text ID (stored in [hSpriteIndexOrTextID]) +; load the three prizes at wd13d-wd13f +; load the three prices at wd141-wd146 +; display the three prizes' names +; (distinguishing between Pokemon names +; and Items (specifically TMs) names) + ld a, [hSpriteIndexOrTextID] + sub 3 ; prize-texts' id are 3, 4 and 5 + ld [wWhichPrizeWindow], a ; prize-texts' id (relative, i.e. 0, 1 or 2) + add a + add a + ld d, 0 + ld e, a + ld hl, PrizeDifferentMenuPtrs + add hl, de + ld a, [hli] + ld d, [hl] + ld e, a + inc hl + push hl + ld hl, wPrize1 + call CopyString + pop hl + ld a, [hli] + ld h, [hl] + ld l, a + ld de, wPrize1Price + ld bc, 6 + call CopyData + ld a, [wWhichPrizeWindow] + cp 2 ;is TM_menu? + jr nz, .putMonName + ld a, [wPrize1] + ld [wd11e], a + call GetItemName + coord hl, 2, 4 + call PlaceString + ld a, [wPrize2] + ld [wd11e], a + call GetItemName + coord hl, 2, 6 + call PlaceString + ld a, [wPrize3] + ld [wd11e], a + call GetItemName + coord hl, 2, 8 + call PlaceString + jr .putNoThanksText +.putMonName + ld a, [wPrize1] + ld [wd11e], a + call GetMonName + coord hl, 2, 4 + call PlaceString + ld a, [wPrize2] + ld [wd11e], a + call GetMonName + coord hl, 2, 6 + call PlaceString + ld a, [wPrize3] + ld [wd11e], a + call GetMonName + coord hl, 2, 8 + call PlaceString +.putNoThanksText + coord hl, 2, 10 + ld de, NoThanksText + call PlaceString +; put prices on the right side of the textbox + ld de, wPrize1Price + coord hl, 13, 5 +; reg. c: +; [low nybble] number of bytes +; [bit 765 = %100] space-padding (not zero-padding) + ld c, (1 << 7 | 2) +; Function $15CD displays BCD value (same routine +; used by text-command $02) + call PrintBCDNumber + ld de, wPrize2Price + coord hl, 13, 7 + ld c, (1 << 7 | 2) + call PrintBCDNumber + ld de, wPrize3Price + coord hl, 13, 9 + ld c, (1 << 7 | 2) + jp PrintBCDNumber + +INCLUDE "data/prizes.asm" + +PrintPrizePrice: + coord hl, 11, 0 + ld b, 1 + ld c, 7 + call TextBoxBorder + call UpdateSprites + coord hl, 12, 0 + ld de, .CoinString + call PlaceString + coord hl, 13, 1 + ld de, .SixSpacesString + call PlaceString + coord hl, 13, 1 + ld de, wPlayerCoins + ld c, %10000010 + call PrintBCDNumber + ret + +.CoinString: + db "COIN@" + +.SixSpacesString: + db " @" + +LoadCoinsToSubtract: + ld a, [wWhichPrize] + add a + ld d, 0 + ld e, a + ld hl, wPrize1Price + add hl, de ; get selected prize's price + xor a + ld [hUnusedCoinsByte], a + ld a, [hli] + ld [hCoins], a + ld a, [hl] + ld [hCoins + 1], a + ret + +HandlePrizeChoice: + ld a, [wCurrentMenuItem] + ld [wWhichPrize], a + ld d, 0 + ld e, a + ld hl, wPrize1 + add hl, de + ld a, [hl] + ld [wd11e], a + ld a, [wWhichPrizeWindow] + cp 2 ; is prize a TM? + jr nz, .getMonName + call GetItemName + jr .givePrize +.getMonName + call GetMonName +.givePrize + ld hl, SoYouWantPrizeTextPtr + call PrintText + call YesNoChoice + ld a, [wCurrentMenuItem] ; yes/no answer (Y=0, N=1) + and a + jr nz, .printOhFineThen + call LoadCoinsToSubtract + call HasEnoughCoins + jr c, .notEnoughCoins + ld a, [wWhichPrizeWindow] + cp $02 + jr nz, .giveMon + ld a, [wd11e] + ld b, a + ld a, 1 + ld c, a + call GiveItem + jr nc, .bagFull + jr .subtractCoins +.giveMon + ld a, [wd11e] + ld [wcf91], a + push af + call GetPrizeMonLevel + ld c, a + pop af + ld b, a + call GivePokemon + +; If either the party or box was full, wait after displaying message. + push af + ld a, [wAddedToParty] + and a + call z, WaitForTextScrollButtonPress + pop af + +; If the mon couldn't be given to the player (because both the party and box +; were full), return without subtracting coins. + ret nc + +.subtractCoins + call LoadCoinsToSubtract + ld hl, hCoins + 1 + ld de, wPlayerCoins + 1 + ld c, $02 ; how many bytes + predef SubBCDPredef + jp PrintPrizePrice +.bagFull + ld hl, PrizeRoomBagIsFullTextPtr + jp PrintText +.notEnoughCoins + ld hl, SorryNeedMoreCoinsText + jp PrintText +.printOhFineThen + ld hl, OhFineThenTextPtr + jp PrintText + +UnknownPrizeData: +; XXX what's this? + db $00,$01,$00,$01,$00,$01,$00,$00,$01 + +HereYouGoTextPtr: + TX_FAR _HereYouGoText + TX_WAIT + db "@" + +SoYouWantPrizeTextPtr: + TX_FAR _SoYouWantPrizeText + db "@" + +SorryNeedMoreCoinsText: + TX_FAR _SorryNeedMoreCoinsText + TX_WAIT + db "@" + +PrizeRoomBagIsFullTextPtr: + TX_FAR _OopsYouDontHaveEnoughRoomText + TX_WAIT + db "@" + +OhFineThenTextPtr: + TX_FAR _OhFineThenText + TX_WAIT + db "@" + +GetPrizeMonLevel: + ld a, [wcf91] + ld b, a + ld hl, PrizeMonLevelDictionary +.loop + ld a, [hli] + cp b + jr z, .matchFound + inc hl + jr .loop +.matchFound + ld a, [hl] + ld [wCurEnemyLVL], a + ret + +INCLUDE "data/prize_mon_levels.asm" diff --git a/engine/events/saffron_guards.asm b/engine/events/saffron_guards.asm new file mode 100755 index 00000000..091cfa1a --- /dev/null +++ b/engine/events/saffron_guards.asm @@ -0,0 +1,15 @@ +RemoveGuardDrink:: + ld hl, GuardDrinksList +.drinkLoop + ld a, [hli] + ld [$ffdb], a + and a + ret z + push hl + ld b, a + call IsItemInBag + pop hl + jr z, .drinkLoop + jpba RemoveItemByID + +INCLUDE "data/guard_drink_items.asm" diff --git a/engine/events/set_blackout_map.asm b/engine/events/set_blackout_map.asm new file mode 100644 index 00000000..14f0ba28 --- /dev/null +++ b/engine/events/set_blackout_map.asm @@ -0,0 +1,25 @@ +SetLastBlackoutMap: +; Set the map to return to when +; blacking out or using Teleport or Dig. +; Safari rest houses don't count. + + push hl + ld hl, SafariZoneRestHouses + ld a, [wCurMap] + ld b, a +.loop + ld a, [hli] + cp -1 + jr z, .notresthouse + cp b + jr nz, .loop + jr .done + +.notresthouse + ld a, [wLastMap] + ld [wLastBlackoutMap], a +.done + pop hl + ret + +INCLUDE "data/rest_house_maps.asm" diff --git a/engine/events/starter_dex.asm b/engine/events/starter_dex.asm new file mode 100755 index 00000000..21289c6a --- /dev/null +++ b/engine/events/starter_dex.asm @@ -0,0 +1,9 @@ +; this function temporarily makes the starters (and Ivysaur) seen +; so that the full Pokedex information gets displayed in Oak's lab +StarterDex: + ld a, %01001011 ; set starter flags + ld [wPokedexOwned], a + predef ShowPokedexData + xor a ; unset starter flags + ld [wPokedexOwned], a + ret diff --git a/engine/events/vending_machine.asm b/engine/events/vending_machine.asm new file mode 100755 index 00000000..554c5d4f --- /dev/null +++ b/engine/events/vending_machine.asm @@ -0,0 +1,133 @@ +VendingMachineMenu:: + ld hl, VendingMachineText1 + call PrintText + ld a, MONEY_BOX + ld [wTextBoxID], a + call DisplayTextBoxID + xor a + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + ld a, A_BUTTON | B_BUTTON + ld [wMenuWatchedKeys], a + ld a, 3 + ld [wMaxMenuItem], a + ld a, 5 + ld [wTopMenuItemY], a + ld a, 1 + ld [wTopMenuItemX], a + ld hl, wd730 + set 6, [hl] + coord hl, 0, 3 + ld b, 8 + ld c, 12 + call TextBoxBorder + call UpdateSprites + coord hl, 2, 5 + ld de, DrinkText + call PlaceString + coord hl, 9, 6 + ld de, DrinkPriceText + call PlaceString + ld hl, wd730 + res 6, [hl] + call HandleMenuInput + bit 1, a ; pressed B? + jr nz, .notThirsty + ld a, [wCurrentMenuItem] + cp 3 ; chose Cancel? + jr z, .notThirsty + xor a + ld [hMoney], a + ld [hMoney + 2], a + ld a, $2 + ld [hMoney + 1], a + call HasEnoughMoney + jr nc, .enoughMoney + ld hl, VendingMachineText4 + jp PrintText +.enoughMoney + call LoadVendingMachineItem + ld a, [hVendingMachineItem] + ld b, a + ld c, 1 + call GiveItem + jr nc, .BagFull + + ld b, 60 ; number of times to play the "brrrrr" sound +.playDeliverySound + ld c, 2 + call DelayFrames + push bc + ld a, SFX_PUSH_BOULDER + call PlaySound + pop bc + dec b + jr nz, .playDeliverySound + + ld hl, VendingMachineText5 + call PrintText + ld hl, hVendingMachinePrice + 2 + ld de, wPlayerMoney + 2 + ld c, $3 + predef SubBCDPredef + ld a, MONEY_BOX + ld [wTextBoxID], a + jp DisplayTextBoxID +.BagFull + ld hl, VendingMachineText6 + jp PrintText +.notThirsty + ld hl, VendingMachineText7 + jp PrintText + +VendingMachineText1: + TX_FAR _VendingMachineText1 + db "@" + +DrinkText: + db "FRESH WATER" + next "SODA POP" + next "LEMONADE" + next "CANCEL@" + +DrinkPriceText: + db "¥200" + next "¥300" + next "¥350" + next "@" + +VendingMachineText4: + TX_FAR _VendingMachineText4 + db "@" + +VendingMachineText5: + TX_FAR _VendingMachineText5 + db "@" + +VendingMachineText6: + TX_FAR _VendingMachineText6 + db "@" + +VendingMachineText7: + TX_FAR _VendingMachineText7 + db "@" + +LoadVendingMachineItem: + ld hl, VendingPrices + ld a, [wCurrentMenuItem] + add a + add a + ld d, 0 + ld e, a + add hl, de + ld a, [hli] + ld [hVendingMachineItem], a + ld a, [hli] + ld [hVendingMachinePrice], a + ld a, [hli] + ld [hVendingMachinePrice + 1], a + ld a, [hl] + ld [hVendingMachinePrice + 2], a + ret + +INCLUDE "data/vending_prices.asm" diff --git a/engine/evolution.asm b/engine/evolution.asm deleted file mode 100755 index 731735c5..00000000 --- a/engine/evolution.asm +++ /dev/null @@ -1,160 +0,0 @@ -EvolveMon: - push hl - push de - push bc - ld a, [wcf91] - push af - ld a, [wd0b5] - push af - xor a - ld [wLowHealthAlarm], a - ld [wChannelSoundIDs + Ch5], a - dec a - ld [wNewSoundID], a - call PlaySound - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a - ld a, SFX_TINK - call PlaySound - call Delay3 - xor a - ld [H_AUTOBGTRANSFERENABLED], a - ld [hTilesetType], a - ld a, [wEvoOldSpecies] - ld [wWholeScreenPaletteMonSpecies], a - ld c, 0 - call EvolutionSetWholeScreenPalette - ld a, [wEvoNewSpecies] - ld [wcf91], a - ld [wd0b5], a - call Evolution_LoadPic - ld de, vFrontPic - ld hl, vBackPic - ld bc, 7 * 7 - call CopyVideoData - ld a, [wEvoOldSpecies] - ld [wcf91], a - ld [wd0b5], a - call Evolution_LoadPic - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a - ld a, [wEvoOldSpecies] - call PlayCry - call WaitForSoundToFinish - ld c, BANK(Music_SafariZone) - ld a, MUSIC_SAFARI_ZONE - call PlayMusic - ld c, 80 - call DelayFrames - ld c, 1 ; set PAL_BLACK instead of mon palette - call EvolutionSetWholeScreenPalette - lb bc, $1, $10 -.animLoop - push bc - call Evolution_CheckForCancel - jr c, .evolutionCancelled - call Evolution_BackAndForthAnim - pop bc - inc b - dec c - dec c - jr nz, .animLoop - xor a - ld [wEvoCancelled], a - ld a, $31 - ld [wEvoMonTileOffset], a - call Evolution_ChangeMonPic ; show the new species pic - ld a, [wEvoNewSpecies] -.done - ld [wWholeScreenPaletteMonSpecies], a - ld a, $ff - ld [wNewSoundID], a - call PlaySound - ld a, [wWholeScreenPaletteMonSpecies] - call PlayCry - ld c, 0 - call EvolutionSetWholeScreenPalette - pop af - ld [wd0b5], a - pop af - ld [wcf91], a - pop bc - pop de - pop hl - ld a, [wEvoCancelled] - and a - ret z - scf - ret -.evolutionCancelled - pop bc - ld a, 1 - ld [wEvoCancelled], a - ld a, [wEvoOldSpecies] - jr .done - -EvolutionSetWholeScreenPalette: - ld b, SET_PAL_POKEMON_WHOLE_SCREEN - jp RunPaletteCommand - -Evolution_LoadPic: - call GetMonHeader - coord hl, 7, 2 - jp LoadFlippedFrontSpriteByMonIndex - -Evolution_BackAndForthAnim: -; show the mon change back and forth between the new and old species b times - ld a, $31 - ld [wEvoMonTileOffset], a - call Evolution_ChangeMonPic - ld a, -$31 - ld [wEvoMonTileOffset], a - call Evolution_ChangeMonPic - dec b - jr nz, Evolution_BackAndForthAnim - ret - -Evolution_ChangeMonPic: - push bc - xor a - ld [H_AUTOBGTRANSFERENABLED], a - coord hl, 7, 2 - lb bc, 7, 7 - ld de, SCREEN_WIDTH - 7 -.loop - push bc -.innerLoop - ld a, [wEvoMonTileOffset] - add [hl] - ld [hli], a - dec c - jr nz, .innerLoop - pop bc - add hl, de - dec b - jr nz, .loop - ld a, 1 - ld [H_AUTOBGTRANSFERENABLED], a - call Delay3 - pop bc - ret - -Evolution_CheckForCancel: - call DelayFrame - push bc - call JoypadLowSensitivity - ld a, [hJoy5] - pop bc - and B_BUTTON - jr nz, .pressedB -.notAllowedToCancel - dec c - jr nz, Evolution_CheckForCancel - and a - ret -.pressedB - ld a, [wForceEvolution] - and a - jr nz, .notAllowedToCancel - scf - ret diff --git a/engine/evolve_trade.asm b/engine/evolve_trade.asm deleted file mode 100755 index e17fc05c..00000000 --- a/engine/evolve_trade.asm +++ /dev/null @@ -1,44 +0,0 @@ -EvolveTradeMon: -; Verify the TradeMon's species name before -; attempting to initiate a trade evolution. - -; The names of the trade evolutions in Blue (JP) -; are checked. In that version, TradeMons that -; can evolve are Graveler and Haunter. - -; In localization, this check was translated -; before monster names were finalized. -; Then, Haunter's name was "Spectre". -; Since its name no longer starts with -; "SP", it is prevented from evolving. - -; This may have been why Red/Green's trades -; were used instead, where none can evolve. - -; This was fixed in Yellow. - - ld a, [wInGameTradeReceiveMonName] - - ; GRAVELER - cp "G" - jr z, .ok - - ; "SPECTRE" (HAUNTER) - cp "S" - ret nz - ld a, [wInGameTradeReceiveMonName + 1] - cp "P" - ret nz - -.ok - ld a, [wPartyCount] - dec a - ld [wWhichPokemon], a - ld a, $1 - ld [wForceEvolution], a - ld a, LINK_STATE_TRADING - ld [wLinkState], a - callab TryEvolvingMon - xor a ; LINK_STATE_NONE - ld [wLinkState], a - jp PlayDefaultMusic diff --git a/engine/evos_moves.asm b/engine/evos_moves.asm deleted file mode 100755 index f50f8081..00000000 --- a/engine/evos_moves.asm +++ /dev/null @@ -1,513 +0,0 @@ -; try to evolve the mon in [wWhichPokemon] -TryEvolvingMon: - ld hl, wCanEvolveFlags - xor a - ld [hl], a - ld a, [wWhichPokemon] - ld c, a - ld b, FLAG_SET - call Evolution_FlagAction - -; this is only called after battle -; it is supposed to do level up evolutions, though there is a bug that allows item evolutions to occur -EvolutionAfterBattle: - ld a, [hTilesetType] - push af - xor a - ld [wEvolutionOccurred], a - dec a - ld [wWhichPokemon], a - push hl - push bc - push de - ld hl, wPartyCount - push hl - -Evolution_PartyMonLoop: ; loop over party mons - ld hl, wWhichPokemon - inc [hl] - pop hl - inc hl - ld a, [hl] - cp $ff ; have we reached the end of the party? - jp z, .done - ld [wEvoOldSpecies], a - push hl - ld a, [wWhichPokemon] - ld c, a - ld hl, wCanEvolveFlags - ld b, FLAG_TEST - call Evolution_FlagAction - ld a, c - and a ; is the mon's bit set? - jp z, Evolution_PartyMonLoop ; if not, go to the next mon - ld a, [wEvoOldSpecies] - dec a - ld b, 0 - ld hl, EvosMovesPointerTable - add a - rl b - ld c, a - add hl, bc - ld a, [hli] - ld h, [hl] - ld l, a - push hl - ld a, [wcf91] - push af - xor a ; PLAYER_PARTY_DATA - ld [wMonDataLocation], a - call LoadMonData - pop af - ld [wcf91], a - pop hl - -.evoEntryLoop ; loop over evolution entries - ld a, [hli] - and a ; have we reached the end of the evolution data? - jr z, Evolution_PartyMonLoop - ld b, a ; evolution type - cp EV_TRADE - jr z, .checkTradeEvo -; not trade evolution - ld a, [wLinkState] - cp LINK_STATE_TRADING - jr z, Evolution_PartyMonLoop ; if trading, go the next mon - ld a, b - cp EV_ITEM - jr z, .checkItemEvo - ld a, [wForceEvolution] - and a - jr nz, Evolution_PartyMonLoop - ld a, b - cp EV_LEVEL - jr z, .checkLevel -.checkTradeEvo - ld a, [wLinkState] - cp LINK_STATE_TRADING - jp nz, .nextEvoEntry1 ; if not trading, go to the next evolution entry - ld a, [hli] ; level requirement - ld b, a - ld a, [wLoadedMonLevel] - cp b ; is the mon's level greater than the evolution requirement? - jp c, Evolution_PartyMonLoop ; if so, go the next mon - jr .doEvolution -.checkItemEvo - ld a, [hli] - 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 - cp b ; was the evolution item in this entry used? - jp nz, .nextEvoEntry1 ; if not, go to the next evolution entry -.checkLevel - ld a, [hli] ; level requirement - ld b, a - ld a, [wLoadedMonLevel] - cp b ; is the mon's level greater than the evolution requirement? - jp c, .nextEvoEntry2 ; if so, go the next evolution entry -.doEvolution - ld [wCurEnemyLVL], a - ld a, 1 - ld [wEvolutionOccurred], a - push hl - ld a, [hl] - ld [wEvoNewSpecies], a - ld a, [wWhichPokemon] - ld hl, wPartyMonNicks - call GetPartyMonName - call CopyStringToCF4B - ld hl, IsEvolvingText - call PrintText - ld c, 50 - call DelayFrames - xor a - ld [H_AUTOBGTRANSFERENABLED], a - coord hl, 0, 0 - lb bc, 12, 20 - call ClearScreenArea - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a - ld a, $ff - ld [wUpdateSpritesEnabled], a - call ClearSprites - callab EvolveMon - jp c, CancelledEvolution - ld hl, EvolvedText - call PrintText - pop hl - ld a, [hl] - ld [wd0b5], a - ld [wLoadedMonSpecies], a - ld [wEvoNewSpecies], a - ld a, MONSTER_NAME - ld [wNameListType], a - ld a, BANK(TrainerNames) ; bank is not used for monster names - ld [wPredefBank], a - call GetName - push hl - ld hl, IntoText - call PrintText_NoCreatingTextBox - ld a, SFX_GET_ITEM_2 - call PlaySoundWaitForCurrent - call WaitForSoundToFinish - ld c, 40 - call DelayFrames - call ClearScreen - call RenameEvolvedMon - ld a, [wd11e] - push af - ld a, [wd0b5] - ld [wd11e], a - predef IndexToPokedex - ld a, [wd11e] - dec a - ld hl, BaseStats - ld bc, MonBaseStatsEnd - MonBaseStats - call AddNTimes - ld de, wMonHeader - call CopyData - ld a, [wd0b5] - ld [wMonHIndex], a - pop af - ld [wd11e], a - ld hl, wLoadedMonHPExp - 1 - ld de, wLoadedMonStats - ld b, $1 - call CalcStats - ld a, [wWhichPokemon] - ld hl, wPartyMon1 - ld bc, wPartyMon2 - wPartyMon1 - call AddNTimes - ld e, l - ld d, h - push hl - push bc - ld bc, wPartyMon1MaxHP - wPartyMon1 - add hl, bc - ld a, [hli] - ld b, a - ld c, [hl] - ld hl, wLoadedMonMaxHP + 1 - ld a, [hld] - sub c - ld c, a - ld a, [hl] - sbc b - ld b, a - ld hl, wLoadedMonHP + 1 - ld a, [hl] - add c - ld [hld], a - ld a, [hl] - adc b - ld [hl], a - dec hl - pop bc - call CopyData - ld a, [wd0b5] - ld [wd11e], a - xor a - ld [wMonDataLocation], a - call LearnMoveFromLevelUp - pop hl - predef SetPartyMonTypes - ld a, [wIsInBattle] - and a - call z, Evolution_ReloadTilesetTilePatterns - predef IndexToPokedex - ld a, [wd11e] - dec a - ld c, a - ld b, FLAG_SET - ld hl, wPokedexOwned - push bc - call Evolution_FlagAction - pop bc - ld hl, wPokedexSeen - call Evolution_FlagAction - pop de - pop hl - ld a, [wLoadedMonSpecies] - ld [hl], a - push hl - ld l, e - ld h, d - jr .nextEvoEntry2 - -.nextEvoEntry1 - inc hl - -.nextEvoEntry2 - inc hl - jp .evoEntryLoop - -.done - pop de - pop bc - pop hl - pop af - ld [hTilesetType], a - ld a, [wLinkState] - cp LINK_STATE_TRADING - ret z - ld a, [wIsInBattle] - and a - ret nz - ld a, [wEvolutionOccurred] - and a - call nz, PlayDefaultMusic - ret - -RenameEvolvedMon: -; Renames the mon to its new, evolved form's standard name unless it had a -; nickname, in which case the nickname is kept. - ld a, [wd0b5] - push af - ld a, [wMonHIndex] - ld [wd0b5], a - call GetName - pop af - ld [wd0b5], a - ld hl, wcd6d - ld de, wcf4b -.compareNamesLoop - ld a, [de] - inc de - cp [hl] - inc hl - ret nz - cp "@" - jr nz, .compareNamesLoop - ld a, [wWhichPokemon] - ld bc, NAME_LENGTH - ld hl, wPartyMonNicks - call AddNTimes - push hl - call GetName - ld hl, wcd6d - pop de - jp CopyData - -CancelledEvolution: - ld hl, StoppedEvolvingText - call PrintText - call ClearScreen - pop hl - call Evolution_ReloadTilesetTilePatterns - jp Evolution_PartyMonLoop - -EvolvedText: - TX_FAR _EvolvedText - db "@" - -IntoText: - TX_FAR _IntoText - db "@" - -StoppedEvolvingText: - TX_FAR _StoppedEvolvingText - db "@" - -IsEvolvingText: - TX_FAR _IsEvolvingText - db "@" - -Evolution_ReloadTilesetTilePatterns: - ld a, [wLinkState] - cp LINK_STATE_TRADING - ret z - 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 -.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? - jr z, .done ; if we've reached the end of the learn set, jump - ld b, a ; level the move is learnt at - ld a, [wCurEnemyLVL] - cp b ; is the move learnt at the mon's current level? - ld a, [hli] ; move ID - jr nz, .learnSetLoop - ld d, a ; ID of move to learn - ld a, [wMonDataLocation] - and a - jr nz, .next -; If [wMonDataLocation] is 0 (PLAYER_PARTY_DATA), get the address of the mon's -; current moves in party data. Every call to this function sets -; [wMonDataLocation] to 0 because other data locations are not supported. -; If it is not 0, this function will not work properly. - ld hl, wPartyMon1Moves - ld a, [wWhichPokemon] - ld bc, wPartyMon2 - wPartyMon1 - call AddNTimes -.next - ld b, NUM_MOVES -.checkCurrentMovesLoop ; check if the move to learn is already known - ld a, [hli] - cp d - jr z, .done ; if already known, jump - dec b - jr nz, .checkCurrentMovesLoop - ld a, d - ld [wMoveNum], a - ld [wd11e], a - call GetMoveName - call CopyStringToCF4B - predef LearnMove -.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 - ld hl, EvosMovesPointerTable - ld b, 0 - ld a, [wcf91] ; cur mon ID - dec a - add a - rl b - ld c, a - add hl, bc - ld a, [hli] - ld h, [hl] - ld l, a -.skipEvoEntriesLoop - ld a, [hli] - and a - jr nz, .skipEvoEntriesLoop - jr .firstMove -.nextMove - pop de -.nextMove2 - inc hl -.firstMove - ld a, [hli] ; read level of next move in learnset - and a - jp z, .done ; end of list - ld b, a - ld a, [wCurEnemyLVL] - cp b - jp c, .done ; mon level < move level (assumption: learnset is sorted by level) - ld a, [wLearningMovesFromDayCare] - and a - jr z, .skipMinLevelCheck - ld a, [wDayCareStartLevel] - cp b - jr nc, .nextMove2 ; min level >= move level - -.skipMinLevelCheck - -; check if the move is already known - push de - ld c, NUM_MOVES -.alreadyKnowsCheckLoop - ld a, [de] - inc de - cp [hl] - jr z, .nextMove - dec c - jr nz, .alreadyKnowsCheckLoop - -; try to find an empty move slot - pop de - push de - ld c, NUM_MOVES -.findEmptySlotLoop - ld a, [de] - and a - jr z, .writeMoveToSlot2 - inc de - dec c - jr nz, .findEmptySlotLoop - -; no empty move slots found - pop de - push de - push hl - ld h, d - ld l, e - call WriteMonMoves_ShiftMoveData ; shift all moves one up (deleting move 1) - ld a, [wLearningMovesFromDayCare] - and a - jr z, .writeMoveToSlot - -; shift PP as well if learning moves from day care - push de - ld bc, wPartyMon1PP - (wPartyMon1Moves + 3) - add hl, bc - ld d, h - ld e, l - call WriteMonMoves_ShiftMoveData ; shift all move PP data one up - pop de - -.writeMoveToSlot - pop hl -.writeMoveToSlot2 - ld a, [hl] - ld [de], a - ld a, [wLearningMovesFromDayCare] - and a - jr z, .nextMove - -; write move PP value if learning moves from day care - push hl - ld a, [hl] - ld hl, wPartyMon1PP - wPartyMon1Moves - add hl, de - push hl - dec a - ld hl, Moves - ld bc, MoveEnd - Moves - call AddNTimes - ld de, wBuffer - ld a, BANK(Moves) - call FarCopyData - ld a, [wBuffer + 5] - pop hl - ld [hl], a - pop hl - jr .nextMove - -.done - pop bc - pop de - pop hl - ret - -; shifts all move data one up (freeing 4th move slot) -WriteMonMoves_ShiftMoveData: - ld c, NUM_MOVES - 1 -.loop - inc de - ld a, [de] - ld [hli], a - dec c - jr nz, .loop - ret - -Evolution_FlagAction: - predef_jump FlagActionPredef - -INCLUDE "data/evos_moves.asm" diff --git a/engine/experience.asm b/engine/experience.asm deleted file mode 100755 index 3ee4b2a8..00000000 --- a/engine/experience.asm +++ /dev/null @@ -1,149 +0,0 @@ -; calculates the level a mon should be based on its current exp -CalcLevelFromExperience:: - ld a, [wLoadedMonSpecies] - ld [wd0b5], a - call GetMonHeader - ld d, $1 ; init level to 1 -.loop - inc d ; increment level - call CalcExperience - push hl - ld hl, wLoadedMonExp + 2 ; current exp -; compare exp needed for level d with current exp - ld a, [hExperience + 2] - ld c, a - ld a, [hld] - sub c - ld a, [hExperience + 1] - ld c, a - ld a, [hld] - sbc c - ld a, [hExperience] - ld c, a - ld a, [hl] - sbc c - pop hl - jr nc, .loop ; if exp needed for level d is not greater than exp, try the next level - dec d ; since the exp was too high on the last loop iteration, go back to the previous value and return - ret - -; calculates the amount of experience needed for level d -CalcExperience:: - ld a, [wMonHGrowthRate] - add a - add a - ld c, a - ld b, 0 - ld hl, GrowthRateTable - add hl, bc - call CalcDSquared - ld a, d - ld [H_MULTIPLIER], a - call Multiply - ld a, [hl] - and $f0 - swap a - ld [H_MULTIPLIER], a - call Multiply - ld a, [hli] - and $f - ld [H_DIVISOR], a - ld b, $4 - call Divide - ld a, [H_QUOTIENT + 1] - push af - ld a, [H_QUOTIENT + 2] - push af - ld a, [H_QUOTIENT + 3] - push af - call CalcDSquared - ld a, [hl] - and $7f - ld [H_MULTIPLIER], a - call Multiply - ld a, [H_PRODUCT + 1] - push af - ld a, [H_PRODUCT + 2] - push af - ld a, [H_PRODUCT + 3] - push af - ld a, [hli] - push af - xor a - ld [H_MULTIPLICAND], a - ld [H_MULTIPLICAND + 1], a - ld a, d - ld [H_MULTIPLICAND + 2], a - ld a, [hli] - ld [H_MULTIPLIER], a - call Multiply - ld b, [hl] - ld a, [H_PRODUCT + 3] - sub b - ld [H_PRODUCT + 3], a - ld b, $0 - ld a, [H_PRODUCT + 2] - sbc b - ld [H_PRODUCT + 2], a - ld a, [H_PRODUCT + 1] - sbc b - ld [H_PRODUCT + 1], a -; The difference of the linear term and the constant term consists of 3 bytes -; starting at H_PRODUCT + 1. Below, hExperience (an alias of that address) will -; be used instead for the further work of adding or subtracting the squared -; term and adding the cubed term. - pop af - and $80 - jr nz, .subtractSquaredTerm ; check sign - pop bc - ld a, [hExperience + 2] - add b - ld [hExperience + 2], a - pop bc - ld a, [hExperience + 1] - adc b - ld [hExperience + 1], a - pop bc - ld a, [hExperience] - adc b - ld [hExperience], a - jr .addCubedTerm -.subtractSquaredTerm - pop bc - ld a, [hExperience + 2] - sub b - ld [hExperience + 2], a - pop bc - ld a, [hExperience + 1] - sbc b - ld [hExperience + 1], a - pop bc - ld a, [hExperience] - sbc b - ld [hExperience], a -.addCubedTerm - pop bc - ld a, [hExperience + 2] - add b - ld [hExperience + 2], a - pop bc - ld a, [hExperience + 1] - adc b - ld [hExperience + 1], a - pop bc - ld a, [hExperience] - adc b - ld [hExperience], a - ret - -; calculates d*d -CalcDSquared: - xor a - ld [H_MULTIPLICAND], a - ld [H_MULTIPLICAND + 1], a - ld a, d - ld [H_MULTIPLICAND + 2], a - ld [H_MULTIPLIER], a - jp Multiply - -INCLUDE "data/growth_rates.asm" diff --git a/engine/game_corner_slots.asm b/engine/game_corner_slots.asm deleted file mode 100755 index 2108695f..00000000 --- a/engine/game_corner_slots.asm +++ /dev/null @@ -1,54 +0,0 @@ -StartSlotMachine: - ld a, [wHiddenObjectFunctionArgument] - cp $fd - jr z, .printOutOfOrder - cp $fe - jr z, .printOutToLunch - cp $ff - jr z, .printSomeonesKeys - callba AbleToPlaySlotsCheck - ld a, [wCanPlaySlots] - and a - ret z - ld a, [wLuckySlotHiddenObjectIndex] - ld b, a - ld a, [wHiddenObjectIndex] - inc a - cp b - jr z, .match - ld a, 253 - jr .next -.match - ld a, 250 -.next - ld [wSlotMachineSevenAndBarModeChance], a - ld a, [H_LOADEDROMBANK] - ld [wSlotMachineSavedROMBank], a - call PromptUserToPlaySlots - ret -.printOutOfOrder - tx_pre_id GameCornerOutOfOrderText - jr .printText -.printOutToLunch - tx_pre_id GameCornerOutToLunchText - jr .printText -.printSomeonesKeys - tx_pre_id GameCornerSomeonesKeysText -.printText - push af - call EnableAutoTextBoxDrawing - pop af - call PrintPredefTextID - ret - -GameCornerOutOfOrderText:: - TX_FAR _GameCornerOutOfOrderText - db "@" - -GameCornerOutToLunchText:: - TX_FAR _GameCornerOutToLunchText - db "@" - -GameCornerSomeonesKeysText:: - TX_FAR _GameCornerSomeonesKeysText - db "@" diff --git a/engine/game_corner_slots2.asm b/engine/game_corner_slots2.asm deleted file mode 100755 index 8f6e8374..00000000 --- a/engine/game_corner_slots2.asm +++ /dev/null @@ -1,31 +0,0 @@ -AbleToPlaySlotsCheck: - ld a, [wSpriteStateData1 + 2] - and $8 - jr z, .done ; not able - ld b, COIN_CASE - predef GetQuantityOfItemInBag - ld a, b - and a - ld b, (GameCornerCoinCaseText_id - TextPredefs) / 2 + 1 - jr z, .printCoinCaseRequired - ld hl, wPlayerCoins - ld a, [hli] - or [hl] - jr nz, .done ; able to play - ld b, (GameCornerNoCoinsText_id - TextPredefs) / 2 + 1 -.printCoinCaseRequired - call EnableAutoTextBoxDrawing - ld a, b - call PrintPredefTextID - xor a -.done - ld [wCanPlaySlots], a - ret - -GameCornerCoinCaseText:: - TX_FAR _GameCornerCoinCaseText - db "@" - -GameCornerNoCoinsText:: - TX_FAR _GameCornerNoCoinsText - db "@" diff --git a/engine/gamefreak.asm b/engine/gamefreak.asm deleted file mode 100755 index 78e48384..00000000 --- a/engine/gamefreak.asm +++ /dev/null @@ -1,243 +0,0 @@ -LoadShootingStarGraphics: - ld a, $f9 - ld [rOBP0], a - ld a, $a4 - ld [rOBP1], a - ld de, AnimationTileset2 + $30 ; star tile (top left quadrant) - ld hl, vChars1 + $200 - lb bc, BANK(AnimationTileset2), $01 - call CopyVideoData - ld de, AnimationTileset2 + $130 ; star tile (bottom left quadrant) - ld hl, vChars1 + $210 - lb bc, BANK(AnimationTileset2), $01 - call CopyVideoData - ld de, FallingStar - ld hl, vChars1 + $220 - lb bc, BANK(FallingStar), (FallingStarEnd - FallingStar) / $10 - call CopyVideoData - ld hl, GameFreakLogoOAMData - ld de, wOAMBuffer + $60 - ld bc, GameFreakLogoOAMDataEnd - GameFreakLogoOAMData - call CopyData - ld hl, GameFreakShootingStarOAMData - ld de, wOAMBuffer - ld bc, GameFreakShootingStarOAMDataEnd - GameFreakShootingStarOAMData - jp CopyData - -AnimateShootingStar: - call LoadShootingStarGraphics - ld a, SFX_SHOOTING_STAR - call PlaySound - -; Move the big star down and left across the screen. - ld hl, wOAMBuffer - lb bc, $a0, $4 -.bigStarLoop - push hl - push bc -.bigStarInnerLoop - ld a, [hl] ; Y - add 4 - ld [hli], a - ld a, [hl] ; X - add -4 - ld [hli], a - inc hl - inc hl - dec c - jr nz, .bigStarInnerLoop - ld c, 1 - call CheckForUserInterruption - pop bc - pop hl - ret c - ld a, [hl] - cp 80 - jr nz, .next - jr .bigStarLoop -.next - cp b - jr nz, .bigStarLoop - -; Clear big star OAM. - ld hl, wOAMBuffer - ld c, 4 - ld de, 4 -.clearOAMLoop - ld [hl], 160 - add hl, de - dec c - jr nz, .clearOAMLoop - -; Make Gamefreak logo flash. - ld b, 3 -.flashLogoLoop - ld hl, rOBP0 - rrc [hl] - rrc [hl] - ld c, 10 - call CheckForUserInterruption - ret c - dec b - jr nz, .flashLogoLoop - -; Copy 24 instances of the small stars OAM data. -; Note that their coordinates put them off-screen. - ld de, wOAMBuffer - ld a, 24 -.initSmallStarsOAMLoop - push af - ld hl, SmallStarsOAM - ld bc, SmallStarsOAMEnd - SmallStarsOAM - call CopyData - pop af - dec a - jr nz, .initSmallStarsOAMLoop - -; Animate the small stars falling from the Gamefreak logo. - xor a - ld [wMoveDownSmallStarsOAMCount], a - ld hl, SmallStarsWaveCoordsPointerTable - ld c, 6 -.smallStarsLoop - ld a, [hli] - ld e, a - ld a, [hli] - ld d, a - push bc - push hl - ld hl, wOAMBuffer + $50 - ld c, 4 -.smallStarsInnerLoop ; introduce new wave of 4 small stars OAM entries - ld a, [de] - cp $ff - jr z, .next2 - ld [hli], a ; Y - inc de - ld a, [de] - ld [hli], a ; X - inc de - inc hl - inc hl - dec c - jr nz, .smallStarsInnerLoop - ld a, [wMoveDownSmallStarsOAMCount] - cp 24 - jr z, .next2 - add 6 ; should be 4, but the extra 2 aren't visible on screen - ld [wMoveDownSmallStarsOAMCount], a -.next2 - call MoveDownSmallStars - push af - -; shift the existing OAM entries down to make room for the next wave - ld hl, wOAMBuffer + $10 - ld de, wOAMBuffer - ld bc, $50 - call CopyData - - pop af - pop hl - pop bc - ret c - dec c - jr nz, .smallStarsLoop - and a - ret - -SmallStarsOAM: - db $00,$00,$A2,$90 -SmallStarsOAMEnd: - -SmallStarsWaveCoordsPointerTable: - dw SmallStarsWave1Coords - dw SmallStarsWave2Coords - dw SmallStarsWave3Coords - dw SmallStarsWave4Coords - dw SmallStarsEmptyWave - dw SmallStarsEmptyWave - -; The stars that fall from the Gamefreak logo come in 4 waves of 4 OAM entries. -; These arrays contain the Y and X coordinates of each OAM entry. - -SmallStarsWave1Coords: - db $68,$30 - db $68,$40 - db $68,$58 - db $68,$78 - -SmallStarsWave2Coords: - db $68,$38 - db $68,$48 - db $68,$60 - db $68,$70 - -SmallStarsWave3Coords: - db $68,$34 - db $68,$4C - db $68,$54 - db $68,$64 - -SmallStarsWave4Coords: - db $68,$3C - db $68,$5C - db $68,$6C - db $68,$74 - -SmallStarsEmptyWave: - db $FF - -MoveDownSmallStars: - ld b, 8 -.loop - ld hl, wOAMBuffer + $5c - ld a, [wMoveDownSmallStarsOAMCount] - ld de, -4 - ld c, a -.innerLoop - inc [hl] ; Y - add hl, de - dec c - jr nz, .innerLoop -; Toggle the palette so that the lower star in the small stars tile blinks in -; and out. - ld a, [rOBP1] - xor %10100000 - ld [rOBP1], a - - ld c, 3 - call CheckForUserInterruption - ret c - dec b - jr nz, .loop - ret - -GameFreakLogoOAMData: - db $48,$50,$8D,$00 - db $48,$58,$8E,$00 - db $50,$50,$8F,$00 - db $50,$58,$90,$00 - db $58,$50,$91,$00 - db $58,$58,$92,$00 - db $60,$30,$80,$00 - db $60,$38,$81,$00 - db $60,$40,$82,$00 - db $60,$48,$83,$00 - db $60,$50,$93,$00 - db $60,$58,$84,$00 - db $60,$60,$85,$00 - db $60,$68,$83,$00 - db $60,$70,$81,$00 - db $60,$78,$86,$00 -GameFreakLogoOAMDataEnd: - -GameFreakShootingStarOAMData: - db $00,$A0,$A0,$10 - db $00,$A8,$A0,$30 - db $08,$A0,$A1,$10 - db $08,$A8,$A1,$30 -GameFreakShootingStarOAMDataEnd: - -FallingStar: - INCBIN "gfx/intro_credits/falling_star.2bpp" -FallingStarEnd: diff --git a/engine/get_bag_item_quantity.asm b/engine/get_bag_item_quantity.asm deleted file mode 100644 index f10df1a0..00000000 --- a/engine/get_bag_item_quantity.asm +++ /dev/null @@ -1,18 +0,0 @@ -GetQuantityOfItemInBag: -; In: b = item ID -; Out: b = how many of that item are in the bag - call GetPredefRegisters - ld hl, wNumBagItems -.loop - inc hl - ld a, [hli] - cp $ff - jr z, .notInBag - cp b - jr nz, .loop - ld a, [hl] - ld b, a - ret -.notInBag - ld b, 0 - ret diff --git a/engine/gfx/hp_bar.asm b/engine/gfx/hp_bar.asm new file mode 100755 index 00000000..221bd7a9 --- /dev/null +++ b/engine/gfx/hp_bar.asm @@ -0,0 +1,270 @@ +HPBarLength: + call GetPredefRegisters + +; calculates bc * 48 / de, the number of pixels the HP bar has +; the result is always at least 1 +GetHPBarLength: + push hl + xor a + ld hl, H_MULTIPLICAND + ld [hli], a + ld a, b + ld [hli], a + ld a, c + ld [hli], a + ld [hl], $30 + call Multiply ; 48 * bc (hp bar is 48 pixels long) + ld a, d + and a + jr z, .maxHPSmaller256 + srl d ; make HP in de fit into 1 byte by dividing by 4 + rr e + srl d + rr e + ld a, [H_MULTIPLICAND+1] + ld b, a + ld a, [H_MULTIPLICAND+2] + srl b ; divide multiplication result as well + rr a + srl b + rr a + ld [H_MULTIPLICAND+2], a + ld a, b + ld [H_MULTIPLICAND+1], a +.maxHPSmaller256 + ld a, e + ld [H_DIVISOR], a + ld b, $4 + call Divide + ld a, [H_MULTIPLICAND+2] + ld e, a ; e = bc * 48 / de (num of pixels of HP bar) + pop hl + and a + ret nz + ld e, $1 ; make result at least 1 + ret + +; predef $48 +UpdateHPBar: +UpdateHPBar2: + push hl + ld hl, wHPBarOldHP + ld a, [hli] + ld c, a ; old HP into bc + ld a, [hli] + ld b, a + ld a, [hli] + ld e, a ; new HP into de + ld d, [hl] + pop hl + push de + push bc + call UpdateHPBar_CalcHPDifference + ld a, e + ld [wHPBarHPDifference+1], a + ld a, d + ld [wHPBarHPDifference], a + pop bc + pop de + call UpdateHPBar_CompareNewHPToOldHP + ret z + ld a, $ff + jr c, .HPdecrease + ld a, $1 +.HPdecrease + ld [wHPBarDelta], a + call GetPredefRegisters + ld a, [wHPBarNewHP] + ld e, a + ld a, [wHPBarNewHP+1] + ld d, a +.animateHPBarLoop + push de + ld a, [wHPBarOldHP] + ld c, a + ld a, [wHPBarOldHP+1] + ld b, a + call UpdateHPBar_CompareNewHPToOldHP + jr z, .animateHPBarDone + jr nc, .HPIncrease +; HP decrease + dec bc ; subtract 1 HP + ld a, c + ld [wHPBarNewHP], a + ld a, b + ld [wHPBarNewHP+1], a + call UpdateHPBar_CalcOldNewHPBarPixels + ld a, e + sub d ; calc pixel difference + jr .ok +.HPIncrease + inc bc ; add 1 HP + ld a, c + ld [wHPBarNewHP], a + ld a, b + ld [wHPBarNewHP+1], a + call UpdateHPBar_CalcOldNewHPBarPixels + ld a, d + sub e ; calc pixel difference +.ok + call UpdateHPBar_PrintHPNumber + and a + jr z, .noPixelDifference + call UpdateHPBar_AnimateHPBar +.noPixelDifference + ld a, [wHPBarNewHP] + ld [wHPBarOldHP], a + ld a, [wHPBarNewHP+1] + ld [wHPBarOldHP+1], a + pop de + jr .animateHPBarLoop +.animateHPBarDone + pop de + ld a, e + ld [wHPBarOldHP], a + ld a, d + ld [wHPBarOldHP+1], a + or e + jr z, .monFainted + call UpdateHPBar_CalcOldNewHPBarPixels + ld d, e +.monFainted + call UpdateHPBar_PrintHPNumber + ld a, $1 + call UpdateHPBar_AnimateHPBar + jp Delay3 + +; animates the HP bar going up or down for (a) ticks (two waiting frames each) +; stops prematurely if bar is filled up +; e: current health (in pixels) to start with +UpdateHPBar_AnimateHPBar: + push hl +.barAnimationLoop + push af + push de + ld d, $6 + call DrawHPBar + ld c, 2 + call DelayFrames + pop de + ld a, [wHPBarDelta] ; +1 or -1 + add e + cp $31 + jr nc, .barFilledUp + ld e, a + pop af + dec a + jr nz, .barAnimationLoop + pop hl + ret +.barFilledUp + pop af + pop hl + ret + +; compares old HP and new HP and sets c and z flags accordingly +UpdateHPBar_CompareNewHPToOldHP: + ld a, d + sub b + ret nz + ld a, e + sub c + ret + +; calcs HP difference between bc and de (into de) +UpdateHPBar_CalcHPDifference: + ld a, d + sub b + jr c, .oldHPGreater + jr z, .testLowerByte +.newHPGreater + ld a, e + sub c + ld e, a + ld a, d + sbc b + ld d, a + ret +.oldHPGreater + ld a, c + sub e + ld e, a + ld a, b + sbc d + ld d, a + ret +.testLowerByte + ld a, e + sub c + jr c, .oldHPGreater + jr nz, .newHPGreater + ld de, $0 + ret + +UpdateHPBar_PrintHPNumber: + push af + push de + ld a, [wHPBarType] + and a + jr z, .done ; don't print number in enemy HUD +; convert from little-endian to big-endian for PrintNumber + ld a, [wHPBarOldHP] + ld [wHPBarTempHP + 1], a + ld a, [wHPBarOldHP + 1] + ld [wHPBarTempHP], a + push hl + ld a, [hFlags_0xFFF6] + bit 0, a + jr z, .asm_fb15 + ld de, $9 + jr .next +.asm_fb15 + ld de, $15 +.next + add hl, de + push hl + ld a, " " + ld [hli], a + ld [hli], a + ld [hli], a + pop hl + ld de, wHPBarTempHP + lb bc, 2, 3 + call PrintNumber + call DelayFrame + pop hl +.done + pop de + pop af + ret + +; calcs number of HP bar pixels for old and new HP value +; d: new pixels +; e: old pixels +UpdateHPBar_CalcOldNewHPBarPixels: + push hl + ld hl, wHPBarMaxHP + ld a, [hli] ; max HP into de + ld e, a + ld a, [hli] + ld d, a + ld a, [hli] ; old HP into bc + ld c, a + ld a, [hli] + ld b, a + ld a, [hli] ; new HP into hl + ld h, [hl] + ld l, a + push hl + push de + call GetHPBarLength ; calc num pixels for old HP + ld a, e + pop de + pop bc + push af + call GetHPBarLength ; calc num pixels for new HP + pop af + ld d, e + ld e, a + pop hl + ret diff --git a/engine/gfx/load_pokedex_tiles.asm b/engine/gfx/load_pokedex_tiles.asm new file mode 100755 index 00000000..70bcf04d --- /dev/null +++ b/engine/gfx/load_pokedex_tiles.asm @@ -0,0 +1,11 @@ +; Loads tile patterns for tiles used in the pokedex. +LoadPokedexTilePatterns: + call LoadHpBarAndStatusTilePatterns + ld de, PokedexTileGraphics + ld hl, vChars2 + $600 + lb bc, BANK(PokedexTileGraphics), (PokedexTileGraphicsEnd - PokedexTileGraphics) / $10 + call CopyVideoData + ld de, PokeballTileGraphics + ld hl, vChars2 + $720 + lb bc, BANK(PokeballTileGraphics), $01 + jp CopyVideoData ; load pokeball tile for marking caught mons diff --git a/engine/gfx/mon_icons.asm b/engine/gfx/mon_icons.asm new file mode 100755 index 00000000..d2913715 --- /dev/null +++ b/engine/gfx/mon_icons.asm @@ -0,0 +1,295 @@ +AnimatePartyMon_ForceSpeed1: + xor a + ld [wCurrentMenuItem], a + ld b, a + inc a + jr GetAnimationSpeed + +; wPartyMenuHPBarColors contains the party mon's health bar colors +; 0: green +; 1: yellow +; 2: red +AnimatePartyMon:: + ld hl, wPartyMenuHPBarColors + ld a, [wCurrentMenuItem] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + +GetAnimationSpeed: + ld c, a + ld hl, PartyMonSpeeds + add hl, bc + ld a, [wOnSGB] + xor $1 + add [hl] + ld c, a + add a + ld b, a + ld a, [wAnimCounter] + and a + jr z, .resetSprites + cp c + jr z, .animateSprite +.incTimer + inc a + cp b + jr nz, .skipResetTimer + xor a ; reset timer +.skipResetTimer + ld [wAnimCounter], a + jp DelayFrame +.resetSprites + push bc + ld hl, wMonPartySpritesSavedOAM + ld de, wOAMBuffer + ld bc, $60 + call CopyData + pop bc + xor a + jr .incTimer +.animateSprite + push bc + ld hl, wOAMBuffer + $02 ; OAM tile id + ld bc, $10 + ld a, [wCurrentMenuItem] + call AddNTimes + ld c, $40 ; amount to increase the tile id by + ld a, [hl] + cp $4 ; tile ID for ICON_BALL + jr z, .editCoords + cp $8 ; tile ID for ICON_HELIX + jr nz, .editTileIDS +; ICON_BALL and ICON_HELIX only shake up and down +.editCoords + dec hl + dec hl ; dec hl to the OAM y coord + ld c, $1 ; amount to increase the y coord by +; otherwise, load a second sprite frame +.editTileIDS + ld b, $4 + ld de, $4 +.loop + ld a, [hl] + add c + ld [hl], a + add hl, de + dec b + jr nz, .loop + pop bc + ld a, c + jr .incTimer + +; Party mon animations cycle between 2 frames. +; The members of the PartyMonSpeeds array specify the number of V-blanks +; that each frame lasts for green HP, yellow HP, and red HP in order. +; On the naming screen, the yellow HP speed is always used. +PartyMonSpeeds: + db 5, 16, 32 + +LoadMonPartySpriteGfx: +; Load mon party sprite tile patterns into VRAM during V-blank. + ld hl, MonPartySpritePointers + ld a, $1c + +LoadAnimSpriteGfx: +; Load animated sprite tile patterns into VRAM during V-blank. hl is the address +; of an array of structures that contain arguments for CopyVideoData and a is +; the number of structures in the array. + ld bc, $0 +.loop + push af + push bc + push hl + add hl, bc + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + ld a, [hli] + ld c, a + ld a, [hli] + ld b, a + ld a, [hli] + ld h, [hl] + ld l, a + call CopyVideoData + pop hl + pop bc + ld a, $6 + add c + ld c, a + pop af + dec a + jr nz, .loop + ret + +LoadMonPartySpriteGfxWithLCDDisabled: +; Load mon party sprite tile patterns into VRAM immediately by disabling the +; LCD. + call DisableLCD + ld hl, MonPartySpritePointers + ld a, $1c + ld bc, $0 +.loop + push af + push bc + push hl + add hl, bc + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + push de + ld a, [hli] + ld c, a + swap c + ld b, $0 + ld a, [hli] + ld e, [hl] + inc hl + ld d, [hl] + pop hl + call FarCopyData2 + pop hl + pop bc + ld a, $6 + add c + ld c, a + pop af + dec a + jr nz, .loop + jp EnableLCD + +INCLUDE "data/mon_party_sprite_pointers.asm" + +WriteMonPartySpriteOAMByPartyIndex: +; Write OAM blocks for the party mon in [hPartyMonIndex]. + push hl + push de + push bc + ld a, [hPartyMonIndex] + ld hl, wPartySpecies + ld e, a + ld d, 0 + add hl, de + ld a, [hl] + call GetPartyMonSpriteID + ld [wOAMBaseTile], a + call WriteMonPartySpriteOAM + pop bc + pop de + pop hl + ret + +WriteMonPartySpriteOAMBySpecies: +; Write OAM blocks for the party sprite of the species in +; [wMonPartySpriteSpecies]. + xor a + ld [hPartyMonIndex], a + ld a, [wMonPartySpriteSpecies] + call GetPartyMonSpriteID + ld [wOAMBaseTile], a + jr WriteMonPartySpriteOAM + +UnusedPartyMonSpriteFunction: +; This function is unused and doesn't appear to do anything useful. It looks +; like it may have been intended to load the tile patterns and OAM data for +; the mon party sprite associated with the species in [wcf91]. +; However, its calculations are off and it loads garbage data. + ld a, [wcf91] + call GetPartyMonSpriteID + push af + ld hl, vSprites + call .LoadTilePatterns + pop af + add $54 + ld hl, vSprites + $40 + call .LoadTilePatterns + xor a + ld [wMonPartySpriteSpecies], a + jr WriteMonPartySpriteOAMBySpecies + +.LoadTilePatterns + push hl + add a + ld c, a + ld b, 0 + ld hl, MonPartySpritePointers + add hl, bc + add hl, bc + add hl, bc + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + ld a, [hli] + ld c, a + ld a, [hli] + ld b, a + pop hl + jp CopyVideoData + +WriteMonPartySpriteOAM: +; Write the OAM blocks for the first animation frame into the OAM buffer and +; make a copy at wMonPartySpritesSavedOAM. + push af + ld c, $10 + ld h, wOAMBuffer / $100 + ld a, [hPartyMonIndex] + swap a + ld l, a + add $10 + ld b, a + pop af + cp ICON_HELIX << 2 + jr z, .helix + call WriteSymmetricMonPartySpriteOAM + jr .makeCopy +.helix + call WriteAsymmetricMonPartySpriteOAM +; Make a copy of the OAM buffer with the first animation frame written so that +; we can flip back to it from the second frame by copying it back. +.makeCopy + ld hl, wOAMBuffer + ld de, wMonPartySpritesSavedOAM + ld bc, $60 + jp CopyData + +GetPartyMonSpriteID: + ld [wd11e], a + predef IndexToPokedex + ld a, [wd11e] + ld c, a + dec a + srl a + ld hl, MonPartyData + ld e, a + ld d, 0 + add hl, de + ld a, [hl] + bit 0, c + jr nz, .skipSwap + swap a ; use lower nybble if pokedex num is even +.skipSwap + and $f0 + srl a + srl a + ret + +INCLUDE "data/mon_party_sprites.asm" + +INC_FRAME_1 EQUS "0, $20" +INC_FRAME_2 EQUS "$20, $20" + +BugIconFrame1: INCBIN "gfx/icons/bug.2bpp", INC_FRAME_1 +PlantIconFrame1: INCBIN "gfx/icons/plant.2bpp", INC_FRAME_1 +BugIconFrame2: INCBIN "gfx/icons/bug.2bpp", INC_FRAME_2 +PlantIconFrame2: INCBIN "gfx/icons/plant.2bpp", INC_FRAME_2 +SnakeIconFrame1: INCBIN "gfx/icons/snake.2bpp", INC_FRAME_1 +QuadrupedIconFrame1: INCBIN "gfx/icons/quadruped.2bpp", INC_FRAME_1 +SnakeIconFrame2: INCBIN "gfx/icons/snake.2bpp", INC_FRAME_2 +QuadrupedIconFrame2: INCBIN "gfx/icons/quadruped.2bpp", INC_FRAME_2 + +TradeBubbleIconGFX: INCBIN "gfx/trade/bubble.2bpp" diff --git a/engine/gfx/oam_dma.asm b/engine/gfx/oam_dma.asm new file mode 100644 index 00000000..b0d64675 --- /dev/null +++ b/engine/gfx/oam_dma.asm @@ -0,0 +1,26 @@ +WriteDMACodeToHRAM:: +; Since no other memory is available during OAM DMA, +; DMARoutine is copied to HRAM and executed there. + ld c, $ff80 % $100 + ld b, DMARoutineEnd - DMARoutine + ld hl, DMARoutine +.copy + ld a, [hli] + ld [$ff00+c], a + inc c + dec b + jr nz, .copy + ret + +DMARoutine: + ; initiate DMA + ld a, wOAMBuffer / $100 + ld [rDMA], a + + ; wait for DMA to finish + ld a, $28 +.wait + dec a + jr nz, .wait + ret +DMARoutineEnd: diff --git a/engine/gfx/palettes.asm b/engine/gfx/palettes.asm new file mode 100755 index 00000000..39991d48 --- /dev/null +++ b/engine/gfx/palettes.asm @@ -0,0 +1,641 @@ +_RunPaletteCommand: + call GetPredefRegisters + ld a, b + cp $ff + jr nz, .next + ld a, [wDefaultPaletteCommand] ; use default command if command ID is $ff +.next + cp UPDATE_PARTY_MENU_BLK_PACKET + jp z, UpdatePartyMenuBlkPacket + ld l, a + ld h, 0 + add hl, hl + ld de, SetPalFunctions + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ld de, SendSGBPackets + push de + jp hl + +SetPal_BattleBlack: + ld hl, PalPacket_Black + ld de, BlkPacket_Battle + ret + +; uses PalPacket_Empty to build a packet based on mon IDs and health color +SetPal_Battle: + ld hl, PalPacket_Empty + ld de, wPalPacket + ld bc, $10 + call CopyData + ld a, [wPlayerBattleStatus3] + ld hl, wBattleMonSpecies + call DeterminePaletteID + ld b, a + ld a, [wEnemyBattleStatus3] + ld hl, wEnemyMonSpecies2 + call DeterminePaletteID + ld c, a + ld hl, wPalPacket + 1 + ld a, [wPlayerHPBarColor] + add PAL_GREENBAR + ld [hli], a + inc hl + ld a, [wEnemyHPBarColor] + add PAL_GREENBAR + ld [hli], a + inc hl + ld a, b + ld [hli], a + inc hl + ld a, c + ld [hl], a + ld hl, wPalPacket + ld de, BlkPacket_Battle + ld a, SET_PAL_BATTLE + ld [wDefaultPaletteCommand], a + ret + +SetPal_TownMap: + ld hl, PalPacket_TownMap + ld de, BlkPacket_WholeScreen + ret + +; uses PalPacket_Empty to build a packet based the mon ID +SetPal_StatusScreen: + ld hl, PalPacket_Empty + ld de, wPalPacket + ld bc, $10 + call CopyData + ld a, [wcf91] + cp NUM_POKEMON_INDEXES + 1 + jr c, .pokemon + ld a, $1 ; not pokemon +.pokemon + call DeterminePaletteIDOutOfBattle + push af + ld hl, wPalPacket + 1 + ld a, [wStatusScreenHPBarColor] + add PAL_GREENBAR + ld [hli], a + inc hl + pop af + ld [hl], a + ld hl, wPalPacket + ld de, BlkPacket_StatusScreen + ret + +SetPal_PartyMenu: + ld hl, PalPacket_PartyMenu + ld de, wPartyMenuBlkPacket + ret + +SetPal_Pokedex: + ld hl, PalPacket_Pokedex + ld de, wPalPacket + ld bc, $10 + call CopyData + ld a, [wcf91] + call DeterminePaletteIDOutOfBattle + ld hl, wPalPacket + 3 + ld [hl], a + ld hl, wPalPacket + ld de, BlkPacket_Pokedex + ret + +SetPal_Slots: + ld hl, PalPacket_Slots + ld de, BlkPacket_Slots + ret + +SetPal_TitleScreen: + ld hl, PalPacket_Titlescreen + ld de, BlkPacket_Titlescreen + ret + +; used mostly for menus and the Oak intro +SetPal_Generic: + ld hl, PalPacket_Generic + ld de, BlkPacket_WholeScreen + ret + +SetPal_NidorinoIntro: + ld hl, PalPacket_NidorinoIntro + ld de, BlkPacket_NidorinoIntro + ret + +SetPal_GameFreakIntro: + ld hl, PalPacket_GameFreakIntro + ld de, BlkPacket_GameFreakIntro + ld a, SET_PAL_GENERIC + ld [wDefaultPaletteCommand], a + ret + +; uses PalPacket_Empty to build a packet based on the current map +SetPal_Overworld: + ld hl, PalPacket_Empty + ld de, wPalPacket + ld bc, $10 + call CopyData + 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 +.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 palette ID is its map ID + 1 + ld hl, wPalPacket + 1 + ld [hld], a + ld de, BlkPacket_WholeScreen + ld a, SET_PAL_OVERWORLD + ld [wDefaultPaletteCommand], a + ret +.PokemonTowerOrAgatha + ld a, PAL_GREYMON - 1 + jr .town +.caveOrBruno + ld a, PAL_CAVE - 1 + jr .town +.Lorelei + xor a + jr .town + +; used when a Pokemon is the only thing on the screen +; such as evolution, trading and the Hall of Fame +SetPal_PokemonWholeScreen: + push bc + ld hl, PalPacket_Empty + ld de, wPalPacket + ld bc, $10 + call CopyData + pop bc + ld a, c + and a + ld a, PAL_BLACK + jr nz, .next + ld a, [wWholeScreenPaletteMonSpecies] + call DeterminePaletteIDOutOfBattle +.next + ld [wPalPacket + 1], a + ld hl, wPalPacket + ld de, BlkPacket_WholeScreen + ret + +SetPal_TrainerCard: + ld hl, BlkPacket_TrainerCard + ld de, wTrainerCardBlkPacket + ld bc, $40 + call CopyData + ld de, BadgeBlkDataLengths + ld hl, wTrainerCardBlkPacket + 2 + ld a, [wObtainedBadges] + ld c, 8 +.badgeLoop + srl a + push af + jr c, .haveBadge +; The player doens't have the badge, so zero the badge's blk data. + push bc + ld a, [de] + ld c, a + xor a +.zeroBadgeDataLoop + ld [hli], a + dec c + jr nz, .zeroBadgeDataLoop + pop bc + jr .nextBadge +.haveBadge +; The player does have the badge, so skip past the badge's blk data. + ld a, [de] +.skipBadgeDataLoop + inc hl + dec a + jr nz, .skipBadgeDataLoop +.nextBadge + pop af + inc de + dec c + jr nz, .badgeLoop + ld hl, PalPacket_TrainerCard + ld de, wTrainerCardBlkPacket + ret + +SetPalFunctions: + dw SetPal_BattleBlack + dw SetPal_Battle + dw SetPal_TownMap + dw SetPal_StatusScreen + dw SetPal_Pokedex + dw SetPal_Slots + dw SetPal_TitleScreen + dw SetPal_NidorinoIntro + dw SetPal_Generic + dw SetPal_Overworld + dw SetPal_PartyMenu + dw SetPal_PokemonWholeScreen + dw SetPal_GameFreakIntro + dw SetPal_TrainerCard + +; The length of the blk data of each badge on the Trainer Card. +; The Rainbow Badge has 3 entries because of its many colors. +BadgeBlkDataLengths: + db 6 ; Boulder Badge + db 6 ; Cascade Badge + db 6 ; Thunder Badge + db 6 * 3 ; Rainbow Badge + db 6 ; Soul Badge + db 6 ; Marsh Badge + db 6 ; Volcano Badge + 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 + and a ; is the mon index 0? + jr z, .skipDexNumConversion + push bc + predef IndexToPokedex + pop bc + ld a, [wd11e] +.skipDexNumConversion + ld e, a + ld d, 0 + ld hl, MonsterPalettes ; not just for Pokemon, Trainers use it too + add hl, de + ld a, [hl] + ret + +InitPartyMenuBlkPacket: + ld hl, BlkPacket_PartyMenu + ld de, wPartyMenuBlkPacket + ld bc, $30 + jp CopyData + +UpdatePartyMenuBlkPacket: +; Update the blk packet with the palette of the HP bar that is +; specified in [wWhichPartyMenuHPBar]. + ld hl, wPartyMenuHPBarColors + ld a, [wWhichPartyMenuHPBar] + ld e, a + ld d, 0 + add hl, de + ld e, l + ld d, h + ld a, [de] + and a + ld e, (1 << 2) | 1 ; green + jr z, .next + dec a + ld e, (2 << 2) | 2 ; yellow + jr z, .next + ld e, (3 << 2) | 3 ; red +.next + push de + ld hl, wPartyMenuBlkPacket + 8 + 1 + ld bc, 6 + ld a, [wWhichPartyMenuHPBar] + call AddNTimes + pop de + ld [hl], e + ret + +SendSGBPacket: +;check number of packets + ld a, [hl] + and $07 + ret z +; store number of packets in B + ld b, a +.loop2 +; save B for later use + push bc +; disable ReadJoypad to prevent it from interfering with sending the packet + ld a, 1 + ld [hDisableJoypadPolling], a +; send RESET signal (P14=LOW, P15=LOW) + xor a + ld [rJOYP], a +; set P14=HIGH, P15=HIGH + ld a, $30 + ld [rJOYP], a +;load length of packets (16 bytes) + ld b, $10 +.nextByte +;set bit counter (8 bits per byte) + ld e, $08 +; get next byte in the packet + ld a, [hli] + ld d, a +.nextBit0 + bit 0, d +; 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) + ld a, $20 +.next0 + ld [rJOYP], a +; must set P14=HIGH,P15=HIGH between each "pulse" + ld a, $30 + ld [rJOYP], a +; rotation will put next bit in 0th position (so we can always use command +; "bit 0,d" to fetch the bit that has to be sent) + rr d +; decrease bit counter so we know when we have sent all 8 bits of current byte + dec e + jr nz, .nextBit0 + dec b + jr nz, .nextByte +; send bit 1 as a "stop bit" (end of parameter data) + ld a, $20 + ld [rJOYP], a +; set P14=HIGH,P15=HIGH + ld a, $30 + ld [rJOYP], a + xor a + ld [hDisableJoypadPolling], a +; wait for about 70000 cycles + call Wait7000 +; restore (previously pushed) number of packets + pop bc + dec b +; return if there are no more packets + ret z +; else send 16 more bytes + jr .loop2 + +LoadSGB: + xor a + ld [wOnSGB], a + call CheckSGB + ret nc + ld a, 1 + ld [wOnSGB], a + ld a, [wGBC] + and a + jr z, .notGBC + ret +.notGBC + di + call PrepareSuperNintendoVRAMTransfer + ei + ld a, 1 + ld [wCopyingSGBTileData], a + ld de, ChrTrnPacket + ld hl, SGBBorderGraphics + call CopyGfxToSuperNintendoVRAM + xor a + ld [wCopyingSGBTileData], a + ld de, PctTrnPacket + ld hl, BorderPalettes + call CopyGfxToSuperNintendoVRAM + xor a + ld [wCopyingSGBTileData], a + ld de, PalTrnPacket + ld hl, SuperPalettes + call CopyGfxToSuperNintendoVRAM + call ClearVram + ld hl, MaskEnCancelPacket + jp SendSGBPacket + +PrepareSuperNintendoVRAMTransfer: + ld hl, .packetPointers + ld c, 9 +.loop + push bc + ld a, [hli] + push hl + ld h, [hl] + ld l, a + call SendSGBPacket + pop hl + inc hl + pop bc + dec c + jr nz, .loop + ret + +.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 + +CheckSGB: +; Returns whether the game is running on an SGB in carry. + ld hl, MltReq2Packet + di + call SendSGBPacket + ld a, 1 + ld [hDisableJoypadPolling], a + ei + call Wait7000 + ld a, [rJOYP] + and $3 + cp $3 + jr nz, .isSGB + ld a, $20 + ld [rJOYP], a + ld a, [rJOYP] + ld a, [rJOYP] + call Wait7000 + call Wait7000 + ld a, $30 + ld [rJOYP], a + call Wait7000 + call Wait7000 + ld a, $10 + ld [rJOYP], a + ld a, [rJOYP] + ld a, [rJOYP] + ld a, [rJOYP] + ld a, [rJOYP] + ld a, [rJOYP] + ld a, [rJOYP] + call Wait7000 + call Wait7000 + ld a, $30 + ld [rJOYP], a + ld a, [rJOYP] + ld a, [rJOYP] + ld a, [rJOYP] + call Wait7000 + call Wait7000 + ld a, [rJOYP] + and $3 + cp $3 + jr nz, .isSGB + call SendMltReq1Packet + and a + ret +.isSGB + call SendMltReq1Packet + scf + ret + +SendMltReq1Packet: + ld hl, MltReq1Packet + call SendSGBPacket + jp Wait7000 + +CopyGfxToSuperNintendoVRAM: + di + push de + call DisableLCD + ld a, $e4 + ld [rBGP], a + ld de, vChars1 + ld a, [wCopyingSGBTileData] + and a + jr z, .notCopyingTileData + call CopySGBBorderTiles + jr .next +.notCopyingTileData + ld bc, $1000 + call CopyData +.next + ld hl, vBGMap0 + ld de, $c + ld a, $80 + ld c, $d +.loop + ld b, $14 +.innerLoop + ld [hli], a + inc a + dec b + jr nz, .innerLoop + add hl, de + dec c + jr nz, .loop + ld a, $e3 + ld [rLCDC], a + pop hl + call SendSGBPacket + xor a + ld [rBGP], a + ei + ret + +Wait7000: +; Each loop takes 9 cycles so this routine actually waits 63000 cycles. + ld de, 7000 +.loop + nop + nop + nop + dec de + ld a, d + or e + jr nz, .loop + ret + +SendSGBPackets: + ld a, [wGBC] + and a + jr z, .notGBC + push de + call InitGBCPalettes + pop hl + call EmptyFunc5 + ret +.notGBC + push de + call SendSGBPacket + pop hl + jp SendSGBPacket + +InitGBCPalettes: + ld a, $80 ; index 0 with auto-increment + ld [rBGPI], a + inc hl + ld c, $20 +.loop + ld a, [hli] + inc hl + add a + add a + add a + ld de, SuperPalettes + add e + jr nc, .noCarry + inc d +.noCarry + ld a, [de] + ld [rBGPD], a + dec c + jr nz, .loop + ret + +EmptyFunc5: + ret + +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 +; the second 16 bytes contain bit planes 3 and 4. +; 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 + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .copyLoop + +; Zero bit planes 3 and 4. + ld c, 16 + xor a +.zeroLoop + ld [de], a + inc de + dec c + jr nz, .zeroLoop + + dec b + jr nz, .tileLoop + ret + +INCLUDE "data/sgb_packets.asm" + +INCLUDE "data/mon_palettes.asm" + +INCLUDE "data/super_palettes.asm" + +INCLUDE "data/sgb_border.asm" diff --git a/engine/gfx/screen_effects.asm b/engine/gfx/screen_effects.asm new file mode 100755 index 00000000..95f0ea25 --- /dev/null +++ b/engine/gfx/screen_effects.asm @@ -0,0 +1,71 @@ +; b = new colour for BG colour 0 (usually white) for 4 frames +ChangeBGPalColor0_4Frames: + call GetPredefRegisters + ld a, [rBGP] + or b + ld [rBGP], a + ld c, 4 + call DelayFrames + ld a, [rBGP] + and %11111100 + ld [rBGP], a + ret + +PredefShakeScreenVertically: +; Moves the window down and then back in a sequence of progressively smaller +; numbers of pixels, starting at b. + call GetPredefRegisters + ld a, 1 + ld [wDisableVBlankWYUpdate], a + xor a +.loop + ld [$ff96], a + call .MutateWY + call .MutateWY + dec b + ld a, b + jr nz, .loop + xor a + ld [wDisableVBlankWYUpdate], a + ret + +.MutateWY + ld a, [$ff96] + xor b + ld [$ff96], a + ld [rWY], a + ld c, 3 + jp DelayFrames + +PredefShakeScreenHorizontally: +; Moves the window right and then back in a sequence of progressively smaller +; numbers of pixels, starting at b. + call GetPredefRegisters + xor a +.loop + ld [$ff97], a + call .MutateWX + ld c, 1 + call DelayFrames + call .MutateWX + dec b + ld a, b + jr nz, .loop + +; restore normal WX + ld a, 7 + ld [rWX], a + ret + +.MutateWX + ld a, [$ff97] + xor b + ld [$ff97], a + bit 7, a + jr z, .skipZeroing + xor a ; zero a if it's negative +.skipZeroing + add 7 + ld [rWX], a + ld c, 4 + jp DelayFrames diff --git a/engine/gfx/sprite_oam.asm b/engine/gfx/sprite_oam.asm new file mode 100644 index 00000000..68128413 --- /dev/null +++ b/engine/gfx/sprite_oam.asm @@ -0,0 +1,189 @@ +PrepareOAMData:: +; Determine OAM data for currently visible +; sprites and write it to wOAMBuffer. + + ld a, [wUpdateSpritesEnabled] + dec a + jr z, .updateEnabled + + cp -1 + ret nz + ld [wUpdateSpritesEnabled], a + jp HideSprites + +.updateEnabled + xor a + ld [hOAMBufferOffset], a + +.spriteLoop + ld [hSpriteOffset2], a + + ld d, wSpriteStateData1 / $100 + ld a, [hSpriteOffset2] + ld e, a + ld a, [de] ; c1x0 + and a + jp z, .nextSprite + + inc e + inc e + ld a, [de] ; c1x2 (facing/anim) + ld [wd5cd], a + cp $ff ; off-screen (don't draw) + jr nz, .visible + + call GetSpriteScreenXY + jr .nextSprite + +.visible + cp $a0 ; is the sprite unchanging like an item ball or boulder? + jr c, .usefacing + +; unchanging + and $f + add $10 ; skip to the second half of the table which doesn't account for facing direction + jr .next + +.usefacing + and $f + +.next + ld l, a + +; get sprite priority + push de + inc d + ld a, e + add $5 + ld e, a + ld a, [de] ; c2x7 + and $80 + ld [hSpritePriority], a ; temp store sprite priority + pop de + +; read the entry from the table + ld h, 0 + ld bc, SpriteFacingAndAnimationTable + add hl, hl + add hl, hl + add hl, bc + ld a, [hli] + ld c, a + ld a, [hli] + ld b, a + ld a, [hli] + ld h, [hl] + ld l, a + + call GetSpriteScreenXY + + ld a, [hOAMBufferOffset] + ld e, a + ld d, wOAMBuffer / $100 + +.tileLoop + ld a, [hSpriteScreenY] ; temp for sprite Y position + add $10 ; Y=16 is top of screen (Y=0 is invisible) + add [hl] ; add Y offset from table + ld [de], a ; write new sprite OAM Y position + inc hl + ld a, [hSpriteScreenX] ; temp for sprite X position + add $8 ; X=8 is left of screen (X=0 is invisible) + add [hl] ; add X offset from table + inc e + ld [de], a ; write new sprite OAM X position + inc e + ld a, [bc] ; read pattern number offset (accommodates orientation (offset 0,4 or 8) and animation (offset 0 or $80)) + inc bc + push bc + ld b, a + + ld a, [wd5cd] ; temp copy of c1x2 + swap a ; high nybble determines sprite used (0 is always player sprite, next are some npcs) + and $f + + ; Sprites $a and $b have one face (and therefore 4 tiles instead of 12). + ; As a result, sprite $b's tile offset is less than normal. + cp $b + jr nz, .notFourTileSprite + ld a, $a * 12 + 4 + jr .next2 + +.notFourTileSprite + ; a *= 12 + sla a + sla a + ld c, a + sla a + add c + +.next2 + add b ; add the tile offset from the table (based on frame and facing direction) + pop bc + ld [de], a ; tile id + inc hl + inc e + ld a, [hl] + bit 1, a ; is the tile allowed to set the sprite priority bit? + jr z, .skipPriority + ld a, [hSpritePriority] + or [hl] +.skipPriority + inc hl + ld [de], a + inc e + bit 0, a ; OAMFLAG_ENDOFDATA + jr z, .tileLoop + + ld a, e + ld [hOAMBufferOffset], a + +.nextSprite + ld a, [hSpriteOffset2] + add $10 + cp $100 % $100 + jp nz, .spriteLoop + + ; Clear unused OAM. + ld a, [hOAMBufferOffset] + ld l, a + ld h, wOAMBuffer / $100 + ld de, $4 + ld b, $a0 + ld a, [wd736] + bit 6, a ; jumping down ledge or fishing animation? + ld a, $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 + +.clear + cp l + ret z + ld [hl], b + add hl, de + jr .clear + +GetSpriteScreenXY: + inc e + inc e + ld a, [de] ; c1x4 + ld [hSpriteScreenY], a + inc e + inc e + ld a, [de] ; c1x6 + ld [hSpriteScreenX], a + ld a, 4 + add e + ld e, a + ld a, [hSpriteScreenY] + add 4 + and $f0 + ld [de], a ; c1xa (y) + inc e + ld a, [hSpriteScreenX] + and $f0 + ld [de], a ; c1xb (x) + ret diff --git a/engine/give_pokemon.asm b/engine/give_pokemon.asm deleted file mode 100755 index 03177e60..00000000 --- a/engine/give_pokemon.asm +++ /dev/null @@ -1,82 +0,0 @@ -_GivePokemon:: -; returns success in carry -; and whether the mon was added to the party in [wAddedToParty] - call EnableAutoTextBoxDrawing - xor a - ld [wAddedToParty], a - ld a, [wPartyCount] - cp PARTY_LENGTH - jr c, .addToParty - ld a, [wNumInBox] - cp MONS_PER_BOX - jr nc, .boxFull -; add to box - xor a - ld [wEnemyBattleStatus3], a - ld a, [wcf91] - ld [wEnemyMonSpecies2], a - callab LoadEnemyMonData - call SetPokedexOwnedFlag - callab SendNewMonToBox - ld hl, wcf4b - ld a, [wCurrentBoxNum] - and $7f - cp 9 - jr c, .singleDigitBoxNum - sub 9 - ld [hl], "1" - inc hl - add "0" - jr .next -.singleDigitBoxNum - add "1" -.next - ld [hli], a - ld [hl], "@" - ld hl, SentToBoxText - call PrintText - scf - ret -.boxFull - ld hl, BoxIsFullText - call PrintText - and a - ret -.addToParty - call SetPokedexOwnedFlag - call AddPartyMon - ld a, 1 - ld [wDoNotWaitForButtonPressAfterDisplayingText], a - ld [wAddedToParty], a - scf - ret - -SetPokedexOwnedFlag: - ld a, [wcf91] - push af - ld [wd11e], a - predef IndexToPokedex - ld a, [wd11e] - dec a - ld c, a - ld hl, wPokedexOwned - ld b, FLAG_SET - predef FlagActionPredef - pop af - ld [wd11e], a - call GetMonName - ld hl, GotMonText - jp PrintText - -GotMonText: - TX_FAR _GotMonText - TX_SFX_ITEM_1 - db "@" - -SentToBoxText: - TX_FAR _SentToBoxText - db "@" - -BoxIsFullText: - TX_FAR _BoxIsFullText - db "@" diff --git a/engine/hall_of_fame.asm b/engine/hall_of_fame.asm deleted file mode 100755 index 3c9b1723..00000000 --- a/engine/hall_of_fame.asm +++ /dev/null @@ -1,288 +0,0 @@ -AnimateHallOfFame: - call HoFFadeOutScreenAndMusic - call ClearScreen - ld c, 100 - call DelayFrames - call LoadFontTilePatterns - call LoadTextBoxTilePatterns - call DisableLCD - ld hl, vBGMap0 - ld bc, $800 - ld a, " " - call FillMemory - call EnableLCD - ld hl, rLCDC - set 3, [hl] - xor a - ld hl, wHallOfFame - ld bc, HOF_TEAM - call FillMemory - xor a - ld [wUpdateSpritesEnabled], a - ld [hTilesetType], a - ld [wSpriteFlipped], a - ld [wLetterPrintingDelayFlags], a ; no delay - ld [wHoFMonOrPlayer], a ; mon - inc a - ld [H_AUTOBGTRANSFERENABLED], a - ld hl, wNumHoFTeams - ld a, [hl] - inc a - jr z, .skipInc ; don't wrap around to 0 - inc [hl] -.skipInc - ld a, $90 - ld [hWY], a - ld c, BANK(Music_HallOfFame) - ld a, MUSIC_HALL_OF_FAME - call PlayMusic - ld hl, wPartySpecies - ld c, $ff -.partyMonLoop - ld a, [hli] - cp $ff - jr z, .doneShowingParty - inc c - push hl - push bc - ld [wHoFMonSpecies], a - ld a, c - ld [wHoFPartyMonIndex], a - ld hl, wPartyMon1Level - ld bc, wPartyMon2 - wPartyMon1 - call AddNTimes - ld a, [hl] - ld [wHoFMonLevel], a - call HoFShowMonOrPlayer - call HoFDisplayAndRecordMonInfo - ld c, 80 - call DelayFrames - coord hl, 2, 13 - ld b, 3 - ld c, 14 - call TextBoxBorder - coord hl, 4, 15 - ld de, HallOfFameText - call PlaceString - ld c, 180 - call DelayFrames - call GBFadeOutToWhite - pop bc - pop hl - jr .partyMonLoop -.doneShowingParty - ld a, c - inc a - ld hl, wHallOfFame - ld bc, HOF_MON - call AddNTimes - ld [hl], $ff - call SaveHallOfFameTeams - xor a - ld [wHoFMonSpecies], a - inc a - ld [wHoFMonOrPlayer], a ; player - call HoFShowMonOrPlayer - call HoFDisplayPlayerStats - call HoFFadeOutScreenAndMusic - xor a - ld [hWY], a - ld hl, rLCDC - res 3, [hl] - ret - -HallOfFameText: - db "HALL OF FAME@" - -HoFShowMonOrPlayer: - call ClearScreen - ld a, $d0 - ld [hSCY], a - ld a, $c0 - ld [hSCX], a - ld a, [wHoFMonSpecies] - ld [wcf91], a - ld [wd0b5], a - ld [wBattleMonSpecies2], a - ld [wWholeScreenPaletteMonSpecies], a - ld a, [wHoFMonOrPlayer] - and a - jr z, .showMon -; show player - call HoFLoadPlayerPics - jr .next1 -.showMon - coord hl, 12, 5 - call GetMonHeader - call LoadFrontSpriteByMonIndex - predef LoadMonBackPic -.next1 - ld b, SET_PAL_POKEMON_WHOLE_SCREEN - ld c, 0 - call RunPaletteCommand - ld a, %11100100 - ld [rBGP], a - ld c, $31 ; back pic - call HoFLoadMonPlayerPicTileIDs - ld d, $a0 - ld e, 4 - ld a, [wOnSGB] - and a - jr z, .next2 - sla e ; scroll more slowly on SGB -.next2 - call .ScrollPic ; scroll back pic left - xor a - ld [hSCY], a - ld c, a ; front pic - call HoFLoadMonPlayerPicTileIDs - ld d, 0 - ld e, -4 -; scroll front pic right - -.ScrollPic - call DelayFrame - ld a, [hSCX] - add e - ld [hSCX], a - cp d - jr nz, .ScrollPic - ret - -HoFDisplayAndRecordMonInfo: - ld a, [wHoFPartyMonIndex] - ld hl, wPartyMonNicks - call GetPartyMonName - call HoFDisplayMonInfo - jp HoFRecordMonInfo - -HoFDisplayMonInfo: - coord hl, 0, 2 - ld b, 9 - ld c, 10 - call TextBoxBorder - coord hl, 2, 6 - ld de, HoFMonInfoText - call PlaceString - coord hl, 1, 4 - ld de, wcd6d - call PlaceString - ld a, [wHoFMonLevel] - coord hl, 8, 7 - call PrintLevelCommon - ld a, [wHoFMonSpecies] - ld [wd0b5], a - coord hl, 3, 9 - predef PrintMonType - ld a, [wHoFMonSpecies] - jp PlayCry - -HoFMonInfoText: - db "LEVEL/" - next "TYPE1/" - next "TYPE2/@" - -HoFLoadPlayerPics: - ld de, RedPicFront - ld a, BANK(RedPicFront) - call UncompressSpriteFromDE - ld hl, sSpriteBuffer1 - ld de, sSpriteBuffer0 - ld bc, $310 - call CopyData - ld de, vFrontPic - call InterlaceMergeSpriteBuffers - ld de, RedPicBack - ld a, BANK(RedPicBack) - call UncompressSpriteFromDE - predef ScaleSpriteByTwo - ld de, vBackPic - call InterlaceMergeSpriteBuffers - ld c, $1 - -HoFLoadMonPlayerPicTileIDs: -; c = base tile ID - ld b, 0 - coord hl, 12, 5 - predef_jump CopyTileIDsFromList - -HoFDisplayPlayerStats: - SetEvent EVENT_HALL_OF_FAME_DEX_RATING - predef DisplayDexRating - coord hl, 0, 4 - ld b, 6 - ld c, 10 - call TextBoxBorder - coord hl, 5, 0 - ld b, 2 - ld c, 9 - call TextBoxBorder - coord hl, 7, 2 - ld de, wPlayerName - call PlaceString - coord hl, 1, 6 - ld de, HoFPlayTimeText - call PlaceString - coord hl, 5, 7 - ld de, wPlayTimeHours - lb bc, 1, 3 - call PrintNumber - ld [hl], $6d - inc hl - ld de, wPlayTimeMinutes - lb bc, LEADING_ZEROES | 1, 2 - call PrintNumber - coord hl, 1, 9 - ld de, HoFMoneyText - call PlaceString - coord hl, 4, 10 - ld de, wPlayerMoney - ld c, $a3 - call PrintBCDNumber - ld hl, DexSeenOwnedText - call HoFPrintTextAndDelay - ld hl, DexRatingText - call HoFPrintTextAndDelay - ld hl, wDexRatingText - -HoFPrintTextAndDelay: - call PrintText - ld c, 120 - jp DelayFrames - -HoFPlayTimeText: - db "PLAY TIME@" - -HoFMoneyText: - db "MONEY@" - -DexSeenOwnedText: - TX_FAR _DexSeenOwnedText - db "@" - -DexRatingText: - TX_FAR _DexRatingText - db "@" - -HoFRecordMonInfo: - ld hl, wHallOfFame - ld bc, HOF_MON - ld a, [wHoFPartyMonIndex] - call AddNTimes - ld a, [wHoFMonSpecies] - ld [hli], a - ld a, [wHoFMonLevel] - ld [hli], a - ld e, l - ld d, h - ld hl, wcd6d - ld bc, NAME_LENGTH - jp CopyData - -HoFFadeOutScreenAndMusic: - ld a, 10 - ld [wAudioFadeOutCounterReloadValue], a - ld [wAudioFadeOutCounter], a - ld a, $ff - ld [wAudioFadeOutControl], a - jp GBFadeOutToWhite diff --git a/engine/heal_party.asm b/engine/heal_party.asm deleted file mode 100644 index 7aaa1bd1..00000000 --- a/engine/heal_party.asm +++ /dev/null @@ -1,99 +0,0 @@ -HealParty: -; Restore HP and PP. - - ld hl, wPartySpecies - ld de, wPartyMon1HP -.healmon - ld a, [hli] - cp $ff - jr z, .done - - push hl - push de - - ld hl, wPartyMon1Status - wPartyMon1HP - add hl, de - xor a - ld [hl], a - - push de - ld b, NUM_MOVES ; A Pokémon has 4 moves -.pp - ld hl, wPartyMon1Moves - wPartyMon1HP - add hl, de - - ld a, [hl] - and a - jr z, .nextmove - - dec a - ld hl, wPartyMon1PP - wPartyMon1HP - add hl, de - - push hl - push de - push bc - - ld hl, Moves - ld bc, MoveEnd - Moves - call AddNTimes - ld de, wcd6d - ld a, BANK(Moves) - call FarCopyData - ld a, [wcd6d + 5] ; PP is byte 5 of move data - - pop bc - pop de - pop hl - - inc de - push bc - ld b, a - ld a, [hl] - and $c0 - add b - ld [hl], a - pop bc - -.nextmove - dec b - jr nz, .pp - pop de - - ld hl, wPartyMon1MaxHP - wPartyMon1HP - add hl, de - ld a, [hli] - ld [de], a - inc de - ld a, [hl] - ld [de], a - - pop de - pop hl - - push hl - ld bc, wPartyMon2 - wPartyMon1 - ld h, d - ld l, e - add hl, bc - ld d, h - ld e, l - pop hl - jr .healmon - -.done - xor a - ld [wWhichPokemon], a - ld [wd11e], a - - ld a, [wPartyCount] - ld b, a -.ppup - push bc - call RestoreBonusPP - pop bc - ld hl, wWhichPokemon - inc [hl] - dec b - jr nz, .ppup - ret diff --git a/engine/hidden_object_functions14.asm b/engine/hidden_object_functions14.asm deleted file mode 100755 index 9e14c6a7..00000000 --- a/engine/hidden_object_functions14.asm +++ /dev/null @@ -1,100 +0,0 @@ -PrintNotebookText: - call EnableAutoTextBoxDrawing - ld a, $1 - ld [wDoNotWaitForButtonPressAfterDisplayingText], a - ld a, [wHiddenObjectFunctionArgument] - jp PrintPredefTextID - -TMNotebook:: - TX_FAR TMNotebookText - TX_WAIT - db "@" - -ViridianSchoolNotebook:: - TX_ASM - ld hl, ViridianSchoolNotebookText1 - call PrintText - call TurnPageSchoolNotebook - jr nz, .doneReading - ld hl, ViridianSchoolNotebookText2 - call PrintText - call TurnPageSchoolNotebook - jr nz, .doneReading - ld hl, ViridianSchoolNotebookText3 - call PrintText - call TurnPageSchoolNotebook - jr nz, .doneReading - ld hl, ViridianSchoolNotebookText4 - call PrintText - ld hl, ViridianSchoolNotebookText5 - call PrintText -.doneReading - jp TextScriptEnd - -TurnPageSchoolNotebook: - ld hl, TurnPageText - call PrintText - call YesNoChoice - ld a, [wCurrentMenuItem] - and a - ret - -TurnPageText: - TX_FAR _TurnPageText - db "@" - -ViridianSchoolNotebookText5: - TX_FAR _ViridianSchoolNotebookText5 - TX_WAIT - db "@" - -ViridianSchoolNotebookText1: - TX_FAR _ViridianSchoolNotebookText1 - db "@" - -ViridianSchoolNotebookText2: - TX_FAR _ViridianSchoolNotebookText2 - db "@" - -ViridianSchoolNotebookText3: - TX_FAR _ViridianSchoolNotebookText3 - db "@" - -ViridianSchoolNotebookText4: - TX_FAR _ViridianSchoolNotebookText4 - db "@" - -PrintFightingDojoText2: - call EnableAutoTextBoxDrawing - tx_pre_jump EnemiesOnEverySideText - -EnemiesOnEverySideText:: - TX_FAR _EnemiesOnEverySideText - db "@" - -PrintFightingDojoText3: - call EnableAutoTextBoxDrawing - tx_pre_jump WhatGoesAroundComesAroundText - -WhatGoesAroundComesAroundText:: - TX_FAR _WhatGoesAroundComesAroundText - db "@" - -PrintFightingDojoText: - call EnableAutoTextBoxDrawing - tx_pre_jump FightingDojoText - -FightingDojoText:: - TX_FAR _FightingDojoText - db "@" - -PrintIndigoPlateauHQText: - ld a, [wSpriteStateData1 + 9] - cp SPRITE_FACING_UP - ret nz - call EnableAutoTextBoxDrawing - tx_pre_jump IndigoPlateauHQText - -IndigoPlateauHQText:: - TX_FAR _IndigoPlateauHQText - db "@" diff --git a/engine/hidden_object_functions17.asm b/engine/hidden_object_functions17.asm deleted file mode 100755 index bb2a358c..00000000 --- a/engine/hidden_object_functions17.asm +++ /dev/null @@ -1,475 +0,0 @@ -PrintRedSNESText: - call EnableAutoTextBoxDrawing - tx_pre_jump RedBedroomSNESText - -RedBedroomSNESText:: - TX_FAR _RedBedroomSNESText - db "@" - -OpenRedsPC: - call EnableAutoTextBoxDrawing - tx_pre_jump RedBedroomPCText - -RedBedroomPCText:: - TX_PLAYERS_PC - -Route15GateLeftBinoculars: - ld a, [wSpriteStateData1 + 9] - cp SPRITE_FACING_UP - ret nz - call EnableAutoTextBoxDrawing - tx_pre Route15UpstairsBinocularsText - ld a, ARTICUNO - ld [wcf91], a - call PlayCry - jp DisplayMonFrontSpriteInBox - -Route15UpstairsBinocularsText:: - TX_FAR _Route15UpstairsBinocularsText - db "@" - -AerodactylFossil: - ld a, FOSSIL_AERODACTYL - ld [wcf91], a - call DisplayMonFrontSpriteInBox - call EnableAutoTextBoxDrawing - tx_pre AerodactylFossilText - ret - -AerodactylFossilText:: - TX_FAR _AerodactylFossilText - db "@" - -KabutopsFossil: - ld a, FOSSIL_KABUTOPS - ld [wcf91], a - call DisplayMonFrontSpriteInBox - call EnableAutoTextBoxDrawing - tx_pre KabutopsFossilText - ret - -KabutopsFossilText:: - TX_FAR _KabutopsFossilText - db "@" - -DisplayMonFrontSpriteInBox: -; Displays a pokemon's front sprite in a pop-up window. -; [wcf91] = pokemon internal id number - ld a, 1 - ld [H_AUTOBGTRANSFERENABLED], a - call Delay3 - xor a - ld [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 - ld [hStartTileID], a - coord hl, 10, 11 - predef AnimateSendingOutMon - call WaitForTextScrollButtonPress - call LoadScreenTilesFromBuffer1 - call Delay3 - ld a, $90 - ld [hWY], a - ret - -PrintBlackboardLinkCableText: - call EnableAutoTextBoxDrawing - ld a, $1 - ld [wDoNotWaitForButtonPressAfterDisplayingText], a - ld a, [wHiddenObjectFunctionArgument] - call PrintPredefTextID - ret - -LinkCableHelp:: - TX_ASM - call SaveScreenTilesToBuffer1 - ld hl, LinkCableHelpText1 - call PrintText - xor a - ld [wMenuItemOffset], a ; not used - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - ld a, A_BUTTON | B_BUTTON - ld [wMenuWatchedKeys], a - ld a, 3 - ld [wMaxMenuItem], a - ld a, 2 - ld [wTopMenuItemY], a - ld a, 1 - ld [wTopMenuItemX], a -.linkHelpLoop - ld hl, wd730 - set 6, [hl] - coord hl, 0, 0 - ld b, 8 - ld c, 13 - call TextBoxBorder - coord hl, 2, 2 - ld de, HowToLinkText - call PlaceString - ld hl, LinkCableHelpText2 - call PrintText - call HandleMenuInput - bit 1, a ; pressed b - jr nz, .exit - ld a, [wCurrentMenuItem] - cp 3 ; pressed a on "STOP READING" - jr z, .exit - ld hl, wd730 - res 6, [hl] - ld hl, LinkCableInfoTexts - add a - ld d, 0 - ld e, a - add hl, de - ld a, [hli] - ld h, [hl] - ld l, a - call PrintText - jp .linkHelpLoop -.exit - ld hl, wd730 - res 6, [hl] - call LoadScreenTilesFromBuffer1 - jp TextScriptEnd - -LinkCableHelpText1: - TX_FAR _LinkCableHelpText1 - db "@" - -LinkCableHelpText2: - TX_FAR _LinkCableHelpText2 - db "@" - -HowToLinkText: - db "HOW TO LINK" - next "COLOSSEUM" - next "TRADE CENTER" - next "STOP READING@" - -LinkCableInfoTexts: - dw LinkCableInfoText1 - dw LinkCableInfoText2 - dw LinkCableInfoText3 - -LinkCableInfoText1: - TX_FAR _LinkCableInfoText1 - db "@" - -LinkCableInfoText2: - TX_FAR _LinkCableInfoText2 - db "@" - -LinkCableInfoText3: - TX_FAR _LinkCableInfoText3 - db "@" - -ViridianSchoolBlackboard:: - TX_ASM - call SaveScreenTilesToBuffer1 - ld hl, ViridianSchoolBlackboardText1 - call PrintText - xor a - ld [wMenuItemOffset], a - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - ld a, D_LEFT | D_RIGHT | A_BUTTON | B_BUTTON - ld [wMenuWatchedKeys], a - ld a, 2 - ld [wMaxMenuItem], a - ld a, 2 - ld [wTopMenuItemY], a - ld a, 1 - ld [wTopMenuItemX], a -.blackboardLoop - ld hl, wd730 - set 6, [hl] - coord hl, 0, 0 - lb bc, 6, 10 - call TextBoxBorder - coord hl, 1, 2 - ld de, StatusAilmentText1 - call PlaceString - coord hl, 6, 2 - ld de, StatusAilmentText2 - call PlaceString - ld hl, ViridianSchoolBlackboardText2 - call PrintText - call HandleMenuInput ; pressing up and down is handled in here - bit 1, a ; pressed b - jr nz, .exitBlackboard - bit 4, a ; pressed right - jr z, .didNotPressRight - ; move cursor to right column - ld a, 2 - ld [wMaxMenuItem], a - ld a, 2 - ld [wTopMenuItemY], a - ld a, 6 - ld [wTopMenuItemX], a - ld a, 3 ; in the the right column, use an offset to prevent overlap - ld [wMenuItemOffset], a - jr .blackboardLoop -.didNotPressRight - bit 5, a ; pressed left - jr z, .didNotPressLeftOrRight - ; move cursor to left column - ld a, 2 - ld [wMaxMenuItem], a - ld a, 2 - ld [wTopMenuItemY], a - ld a, 1 - ld [wTopMenuItemX], a - xor a - ld [wMenuItemOffset], a - jr .blackboardLoop -.didNotPressLeftOrRight - ld a, [wCurrentMenuItem] - ld b, a - ld a, [wMenuItemOffset] - add b - cp 5 ; cursor is pointing to "QUIT" - jr z, .exitBlackboard - ; we must have pressed a on a status condition - ; so print the text - ld hl, wd730 - res 6, [hl] - ld hl, ViridianBlackboardStatusPointers - add a - ld d, 0 - ld e, a - add hl, de - ld a, [hli] - ld h, [hl] - ld l, a - call PrintText - jp .blackboardLoop -.exitBlackboard - ld hl, wd730 - res 6, [hl] - call LoadScreenTilesFromBuffer1 - jp TextScriptEnd - -ViridianSchoolBlackboardText1: - TX_FAR _ViridianSchoolBlackboardText1 - db "@" - -ViridianSchoolBlackboardText2: - TX_FAR _ViridianSchoolBlackboardText2 - db "@" - -StatusAilmentText1: - db " SLP" - next " PSN" - next " PAR@" - -StatusAilmentText2: - db " BRN" - next " FRZ" - next " QUIT@@" - -ViridianBlackboardStatusPointers: - dw ViridianBlackboardSleepText - dw ViridianBlackboardPoisonText - dw ViridianBlackboardPrlzText - dw ViridianBlackboardBurnText - dw ViridianBlackboardFrozenText - -ViridianBlackboardSleepText: - TX_FAR _ViridianBlackboardSleepText - db "@" - -ViridianBlackboardPoisonText: - TX_FAR _ViridianBlackboardPoisonText - db "@" - -ViridianBlackboardPrlzText: - TX_FAR _ViridianBlackboardPrlzText - db "@" - -ViridianBlackboardBurnText: - TX_FAR _ViridianBlackboardBurnText - db "@" - -ViridianBlackboardFrozenText: - TX_FAR _ViridianBlackboardFrozenText - db "@" - -PrintTrashText: - call EnableAutoTextBoxDrawing - tx_pre_jump VermilionGymTrashText - -VermilionGymTrashText:: - TX_FAR _VermilionGymTrashText - db "@" - -GymTrashScript: - call EnableAutoTextBoxDrawing - ld a, [wHiddenObjectFunctionArgument] - ld [wGymTrashCanIndex], a - -; Don't do the trash can puzzle if it's already been done. - CheckEvent EVENT_2ND_LOCK_OPENED - jr z, .ok - - tx_pre_jump VermilionGymTrashText - -.ok - CheckEventReuseA EVENT_1ST_LOCK_OPENED - jr nz, .trySecondLock - - ld a, [wFirstLockTrashCanIndex] - ld b, a - ld a, [wGymTrashCanIndex] - cp b - jr z, .openFirstLock - - tx_pre_id VermilionGymTrashText - jr .done - -.openFirstLock -; Next can is trying for the second switch. - SetEvent EVENT_1ST_LOCK_OPENED - - ld hl, GymTrashCans - ld a, [wGymTrashCanIndex] - ; * 5 - ld b, a - add a - add a - add b - - ld d, 0 - ld e, a - add hl, de - ld a, [hli] - -; There is a bug in this code. It should calculate a value in the range [0, 3] -; but if the mask and random number don't have any 1 bits in common, then -; the result of the AND will be 0. When 1 is subtracted from that, the value -; will become $ff. This will result in 255 being added to hl, which will cause -; hl to point to one of the zero bytes that pad the end of the ROM bank. -; Trash can 0 was intended to be able to have the second lock only when the -; first lock was in trash can 1 or 3. However, due to this bug, trash can 0 can -; have the second lock regardless of which trash can had the first lock. - - ld [hGymTrashCanRandNumMask], a - push hl - call Random - swap a - ld b, a - ld a, [hGymTrashCanRandNumMask] - and b - dec a - pop hl - - ld d, 0 - ld e, a - add hl, de - ld a, [hl] - and $f - ld [wSecondLockTrashCanIndex], a - - tx_pre_id VermilionGymTrashSuccessText1 - jr .done - -.trySecondLock - ld a, [wSecondLockTrashCanIndex] - ld b, a - ld a, [wGymTrashCanIndex] - cp b - jr z, .openSecondLock - -; Reset the cans. - ResetEvent EVENT_1ST_LOCK_OPENED - call Random - - and $e - ld [wFirstLockTrashCanIndex], a - - tx_pre_id VermilionGymTrashFailText - jr .done - -.openSecondLock -; Completed the trash can puzzle. - SetEvent EVENT_2ND_LOCK_OPENED - ld hl, wCurrentMapScriptFlags - set 6, [hl] - - tx_pre_id VermilionGymTrashSuccessText3 - -.done - jp PrintPredefTextID - -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 -; 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 - db 4, 1, 3, 5, 7 ; 4 - db 3, 2, 4, 8, 0 ; 5 - db 3, 3, 7, 9, 0 ; 6 - db 4, 4, 6, 8, 10 ; 7 - db 3, 5, 7, 11, 0 ; 8 - db 3, 6, 10, 12, 0 ; 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 - -VermilionGymTrashSuccessText1:: - TX_FAR _VermilionGymTrashSuccessText1 - TX_ASM - call WaitForSoundToFinish - ld a, SFX_SWITCH - call PlaySound - call WaitForSoundToFinish - jp TextScriptEnd - -; unused -VermilionGymTrashSuccessText2:: - TX_FAR _VermilionGymTrashSuccessText2 - db "@" - -; unused -VermilionGymTrashSuccesPlaySfx: - TX_ASM - call WaitForSoundToFinish - ld a, SFX_SWITCH - call PlaySound - call WaitForSoundToFinish - jp TextScriptEnd - -VermilionGymTrashSuccessText3:: - TX_FAR _VermilionGymTrashSuccessText3 - TX_ASM - call WaitForSoundToFinish - ld a, SFX_GO_INSIDE - call PlaySound - call WaitForSoundToFinish - jp TextScriptEnd - -VermilionGymTrashFailText:: - TX_FAR _VermilionGymTrashFailText - TX_ASM - call WaitForSoundToFinish - ld a, SFX_DENIED - call PlaySound - call WaitForSoundToFinish - jp TextScriptEnd diff --git a/engine/hidden_object_functions18.asm b/engine/hidden_object_functions18.asm deleted file mode 100755 index c0e5aa34..00000000 --- a/engine/hidden_object_functions18.asm +++ /dev/null @@ -1,198 +0,0 @@ -GymStatues: -; if in a gym and have the corresponding badge, a = GymStatueText2_id and jp PrintPredefTextID -; if in a gym and don’t have the corresponding badge, a = GymStatueText1_id and jp PrintPredefTextID -; else ret - call EnableAutoTextBoxDrawing - ld a, [wSpriteStateData1 + 9] - cp SPRITE_FACING_UP - ret nz - ld hl, .BadgeFlags - ld a, [wCurMap] - ld b, a -.loop - ld a, [hli] - cp $ff - ret z - cp b - jr z, .match - inc hl - jr .loop -.match - ld b, [hl] - ld a, [wBeatGymFlags] - and b - cp b - tx_pre_id GymStatueText2 - jr z, .haveBadge - tx_pre_id GymStatueText1 -.haveBadge - jp PrintPredefTextID - -.BadgeFlags: - db PEWTER_GYM, %00000001 - db CERULEAN_GYM, %00000010 - db VERMILION_GYM,%00000100 - db CELADON_GYM, %00001000 - db FUCHSIA_GYM, %00010000 - db SAFFRON_GYM, %00100000 - db CINNABAR_GYM, %01000000 - db VIRIDIAN_GYM, %10000000 - db $ff - -GymStatueText1:: - TX_FAR _GymStatueText1 - db "@" - -GymStatueText2:: - TX_FAR _GymStatueText2 - db "@" - -PrintBenchGuyText: - call EnableAutoTextBoxDrawing - ld hl, BenchGuyTextPointers - ld a, [wCurMap] - ld b, a -.loop - ld a, [hli] - cp $ff - ret z - cp b - jr z, .match - inc hl - inc hl - jr .loop -.match - ld a, [hli] - ld b, a - ld a, [wSpriteStateData1 + 9] - cp b - jr nz, .loop ; player isn't facing left at the bench guy - ld a, [hl] - jp PrintPredefTextID - -; format: db map id, player sprite facing direction, text id of PredefTextIDPointerTable -BenchGuyTextPointers: - db VIRIDIAN_POKECENTER, SPRITE_FACING_LEFT - db_tx_pre ViridianCityPokecenterBenchGuyText - db PEWTER_POKECENTER, SPRITE_FACING_LEFT - db_tx_pre PewterCityPokecenterBenchGuyText - db CERULEAN_POKECENTER, SPRITE_FACING_LEFT - db_tx_pre CeruleanCityPokecenterBenchGuyText - db LAVENDER_POKECENTER, SPRITE_FACING_LEFT - db_tx_pre LavenderCityPokecenterBenchGuyText - db VERMILION_POKECENTER, SPRITE_FACING_LEFT - db_tx_pre VermilionCityPokecenterBenchGuyText - db CELADON_POKECENTER, SPRITE_FACING_LEFT - db_tx_pre CeladonCityPokecenterBenchGuyText - db CELADON_HOTEL, SPRITE_FACING_LEFT - db_tx_pre CeladonCityHotelText - db FUCHSIA_POKECENTER, SPRITE_FACING_LEFT - db_tx_pre FuchsiaCityPokecenterBenchGuyText - db CINNABAR_POKECENTER, SPRITE_FACING_LEFT - db_tx_pre CinnabarIslandPokecenterBenchGuyText - db SAFFRON_POKECENTER, SPRITE_FACING_LEFT - db_tx_pre SaffronCityPokecenterBenchGuyText - db MT_MOON_POKECENTER, SPRITE_FACING_LEFT - db_tx_pre MtMoonPokecenterBenchGuyText - db ROCK_TUNNEL_POKECENTER,SPRITE_FACING_LEFT - db_tx_pre RockTunnelPokecenterBenchGuyText - db $FF - -ViridianCityPokecenterBenchGuyText:: - TX_FAR _ViridianCityPokecenterGuyText - db "@" - -PewterCityPokecenterBenchGuyText:: - TX_FAR _PewterCityPokecenterGuyText - db "@" - -CeruleanCityPokecenterBenchGuyText:: - TX_FAR _CeruleanPokecenterGuyText - db "@" - -LavenderCityPokecenterBenchGuyText:: - TX_FAR _LavenderPokecenterGuyText - db "@" - -MtMoonPokecenterBenchGuyText:: - TX_FAR _MtMoonPokecenterBenchGuyText - db "@" - -RockTunnelPokecenterBenchGuyText:: - TX_FAR _RockTunnelPokecenterGuyText - db "@" - -UnusedBenchGuyText1:: - TX_FAR _UnusedBenchGuyText1 - db "@" - -UnusedBenchGuyText2:: - TX_FAR _UnusedBenchGuyText2 - db "@" - -UnusedBenchGuyText3:: - TX_FAR _UnusedBenchGuyText3 - db "@" - -VermilionCityPokecenterBenchGuyText:: - TX_FAR _VermilionPokecenterGuyText - db "@" - -CeladonCityPokecenterBenchGuyText:: - TX_FAR _CeladonCityPokecenterGuyText - db "@" - -FuchsiaCityPokecenterBenchGuyText:: - TX_FAR _FuchsiaCityPokecenterGuyText - db "@" - -CinnabarIslandPokecenterBenchGuyText:: - TX_FAR _CinnabarPokecenterGuyText - db "@" - -SaffronCityPokecenterBenchGuyText:: - TX_ASM - CheckEvent EVENT_BEAT_SILPH_CO_GIOVANNI - ld hl, SaffronCityPokecenterBenchGuyText2 - jr nz, .asm_624f2 - ld hl, SaffronCityPokecenterBenchGuyText1 -.asm_624f2 - call PrintText - jp TextScriptEnd - -SaffronCityPokecenterBenchGuyText1: - TX_FAR _SaffronCityPokecenterGuyText1 - db "@" - -SaffronCityPokecenterBenchGuyText2: - TX_FAR _SaffronCityPokecenterGuyText2 - db "@" - -CeladonCityHotelText:: - TX_FAR _CeladonCityHotelText - db "@" - - ret - -UnusedPredefText:: - db "@" - -PrintBookcaseText: - call EnableAutoTextBoxDrawing - tx_pre_jump BookcaseText - -BookcaseText:: - TX_FAR _BookcaseText - db "@" - -OpenPokemonCenterPC: - ld a, [wSpriteStateData1 + 9] - cp SPRITE_FACING_UP ; check to see if player is facing up - ret nz - call EnableAutoTextBoxDrawing - ld a, $1 - ld [wAutoTextBoxDrawingControl], a - tx_pre_jump PokemonCenterPCText - -PokemonCenterPCText:: - TX_POKECENTER_PC diff --git a/engine/hidden_object_functions3.asm b/engine/hidden_object_functions3.asm deleted file mode 100755 index 1237e960..00000000 --- a/engine/hidden_object_functions3.asm +++ /dev/null @@ -1,117 +0,0 @@ -; prints text for bookshelves in buildings without sign events -PrintBookshelfText:: - ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction - cp SPRITE_FACING_UP - jr nz, .noMatch -; facing up - ld a, [wCurMapTileset] - ld b, a - aCoord 8, 7 - ld c, a - ld hl, BookshelfTileIDs -.loop - ld a, [hli] - cp $ff - jr z, .noMatch - cp b - jr nz, .nextBookshelfEntry1 - ld a, [hli] - cp c - jr nz, .nextBookshelfEntry2 - ld a, [hl] - push af - call EnableAutoTextBoxDrawing - pop af - call PrintPredefTextID - xor a - ld [$ffdb], a - ret -.nextBookshelfEntry1 - inc hl -.nextBookshelfEntry2 - inc hl - jr .loop -.noMatch - ld a, $ff - ld [$ffdb], a - jpba PrintCardKeyText - -INCLUDE "data/bookshelf_tile_ids.asm" - -IndigoPlateauStatues:: - TX_ASM - ld hl, IndigoPlateauStatuesText1 - call PrintText - ld a, [wXCoord] - bit 0, a - ld hl, IndigoPlateauStatuesText2 - jr nz, .ok - ld hl, IndigoPlateauStatuesText3 -.ok - call PrintText - jp TextScriptEnd - -IndigoPlateauStatuesText1: - TX_FAR _IndigoPlateauStatuesText1 - db "@" - -IndigoPlateauStatuesText2: - TX_FAR _IndigoPlateauStatuesText2 - db "@" - -IndigoPlateauStatuesText3: - TX_FAR _IndigoPlateauStatuesText3 - db "@" - -BookOrSculptureText:: - TX_ASM - ld hl, PokemonBooksText - ld a, [wCurMapTileset] - cp MANSION ; Celadon Mansion tileset - jr nz, .ok - aCoord 8, 6 - cp $38 - jr nz, .ok - ld hl, DiglettSculptureText -.ok - call PrintText - jp TextScriptEnd - -PokemonBooksText: - TX_FAR _PokemonBooksText - db "@" - -DiglettSculptureText: - TX_FAR _DiglettSculptureText - db "@" - -ElevatorText:: - TX_FAR _ElevatorText - db "@" - -TownMapText:: - TX_FAR _TownMapText - TX_BLINK - TX_ASM - ld a, $1 - ld [wDoNotWaitForButtonPressAfterDisplayingText], a - ld hl, wd730 - set 6, [hl] - call GBPalWhiteOutWithDelay3 - xor a - ld [hWY], a - inc a - ld [H_AUTOBGTRANSFERENABLED], a - call LoadFontTilePatterns - callba DisplayTownMap - ld hl, wd730 - res 6, [hl] - ld de, TextScriptEnd - push de - ld a, [H_LOADEDROMBANK] - push af - jp CloseTextDisplay - -PokemonStuffText:: - TX_FAR _PokemonStuffText - db "@" diff --git a/engine/hidden_object_functions7.asm b/engine/hidden_object_functions7.asm deleted file mode 100755 index e18b9570..00000000 --- a/engine/hidden_object_functions7.asm +++ /dev/null @@ -1,467 +0,0 @@ -PrintNewBikeText: - call EnableAutoTextBoxDrawing - tx_pre_jump NewBicycleText - -NewBicycleText:: - TX_FAR _NewBicycleText - db "@" - -DisplayOakLabLeftPoster: - call EnableAutoTextBoxDrawing - tx_pre_jump PushStartText - -PushStartText:: - TX_FAR _PushStartText - db "@" - -DisplayOakLabRightPoster: - call EnableAutoTextBoxDrawing - ld hl, wPokedexOwned - ld b, wPokedexOwnedEnd - wPokedexOwned - call CountSetBits - ld a, [wNumSetBits] - cp 2 - tx_pre_id SaveOptionText - jr c, .ownLessThanTwo - ; own two or more mon - tx_pre_id StrengthsAndWeaknessesText -.ownLessThanTwo - jp PrintPredefTextID - -SaveOptionText:: - TX_FAR _SaveOptionText - db "@" - -StrengthsAndWeaknessesText:: - TX_FAR _StrengthsAndWeaknessesText - db "@" - -SafariZoneCheck:: - CheckEventHL EVENT_IN_SAFARI_ZONE ; if we are not in the Safari Zone, - jr z, SafariZoneGameStillGoing ; don't bother printing game over text - ld a, [wNumSafariBalls] - and a - jr z, SafariZoneGameOver - jr SafariZoneGameStillGoing - -SafariZoneCheckSteps:: - ld a, [wSafariSteps] - ld b, a - ld a, [wSafariSteps + 1] - ld c, a - or b - jr z, SafariZoneGameOver - dec bc - ld a, b - ld [wSafariSteps], a - ld a, c - ld [wSafariSteps + 1], a -SafariZoneGameStillGoing: - xor a - ld [wSafariZoneGameOver], a - ret - -SafariZoneGameOver: - call EnableAutoTextBoxDrawing - xor a - ld [wAudioFadeOutControl], a - dec a - call PlaySound - ld c, BANK(SFX_Safari_Zone_PA) - ld a, SFX_SAFARI_ZONE_PA - call PlayMusic -.waitForMusicToPlay - ld a, [wChannelSoundIDs + Ch5] - cp SFX_SAFARI_ZONE_PA - jr nz, .waitForMusicToPlay - ld a, TEXT_SAFARI_GAME_OVER - ld [hSpriteIndexOrTextID], a - call DisplayTextID - xor a - ld [wPlayerMovingDirection], a - ld a, SAFARI_ZONE_GATE - ld [hWarpDestinationMap], a - ld a, $3 - ld [wDestinationWarpID], a - ld a, $5 - ld [wSafariZoneGateCurScript], a - SetEvent EVENT_SAFARI_GAME_OVER - ld a, 1 - ld [wSafariZoneGameOver], a - ret - -PrintSafariGameOverText:: - xor a - ld [wJoyIgnore], a - ld hl, SafariGameOverText - jp PrintText - -SafariGameOverText: - TX_ASM - ld a, [wNumSafariBalls] - and a - jr z, .noMoreSafariBalls - ld hl, TimesUpText - call PrintText -.noMoreSafariBalls - ld hl, GameOverText - call PrintText - jp TextScriptEnd - -TimesUpText: - TX_FAR _TimesUpText - db "@" - -GameOverText: - TX_FAR _GameOverText - db "@" - -PrintCinnabarQuiz: - ld a, [wSpriteStateData1 + 9] - cp SPRITE_FACING_UP - ret nz - call EnableAutoTextBoxDrawing - tx_pre_jump CinnabarGymQuiz - -CinnabarGymQuiz:: - TX_ASM - xor a - ld [wOpponentAfterWrongAnswer], a - ld a, [wHiddenObjectFunctionArgument] - push af - and $f - ld [hGymGateIndex], a - pop af - and $f0 - swap a - ld [$ffdc], a - ld hl, CinnabarGymQuizIntroText - call PrintText - ld a, [hGymGateIndex] - dec a - add a - ld d, 0 - ld e, a - ld hl, CinnabarQuizQuestions - add hl, de - ld a, [hli] - ld h, [hl] - ld l, a - call PrintText - ld a, 1 - ld [wDoNotWaitForButtonPressAfterDisplayingText], a - call CinnabarGymQuiz_1ea92 - jp TextScriptEnd - -CinnabarGymQuizIntroText: - TX_FAR _CinnabarGymQuizIntroText - db "@" - -CinnabarQuizQuestions: - dw CinnabarQuizQuestionsText1 - dw CinnabarQuizQuestionsText2 - dw CinnabarQuizQuestionsText3 - dw CinnabarQuizQuestionsText4 - dw CinnabarQuizQuestionsText5 - dw CinnabarQuizQuestionsText6 - -CinnabarQuizQuestionsText1: - TX_FAR _CinnabarQuizQuestionsText1 - db "@" - -CinnabarQuizQuestionsText2: - TX_FAR _CinnabarQuizQuestionsText2 - db "@" - -CinnabarQuizQuestionsText3: - TX_FAR _CinnabarQuizQuestionsText3 - db "@" - -CinnabarQuizQuestionsText4: - TX_FAR _CinnabarQuizQuestionsText4 - db "@" - -CinnabarQuizQuestionsText5: - TX_FAR _CinnabarQuizQuestionsText5 - db "@" - -CinnabarQuizQuestionsText6: - TX_FAR _CinnabarQuizQuestionsText6 - db "@" - -CinnabarGymGateFlagAction: - EventFlagAddress hl, EVENT_CINNABAR_GYM_GATE0_UNLOCKED - predef_jump FlagActionPredef - -CinnabarGymQuiz_1ea92: - call YesNoChoice - ld a, [$ffdc] - ld c, a - ld a, [wCurrentMenuItem] - cp c - jr nz, .wrongAnswer - ld hl, wCurrentMapScriptFlags - set 5, [hl] - ld a, [hGymGateIndex] - ld [$ffe0], a - ld hl, CinnabarGymQuizCorrectText - call PrintText - ld a, [$ffe0] - AdjustEventBit EVENT_CINNABAR_GYM_GATE0_UNLOCKED, 0 - ld c, a - ld b, FLAG_SET - call CinnabarGymGateFlagAction - jp UpdateCinnabarGymGateTileBlocks_ -.wrongAnswer - call WaitForSoundToFinish - ld a, SFX_DENIED - call PlaySound - call WaitForSoundToFinish - ld hl, CinnabarGymQuizIncorrectText - call PrintText - ld a, [hGymGateIndex] - add $2 - AdjustEventBit EVENT_BEAT_CINNABAR_GYM_TRAINER_0, 2 - ld c, a - ld b, FLAG_TEST - EventFlagAddress hl, EVENT_BEAT_CINNABAR_GYM_TRAINER_0 - predef FlagActionPredef - ld a, c - and a - ret nz - ld a, [hGymGateIndex] - add $2 - ld [wOpponentAfterWrongAnswer], a - ret - -CinnabarGymQuizCorrectText: - TX_SFX_ITEM_1 - TX_FAR _CinnabarGymQuizCorrectText - TX_BLINK - TX_ASM - - ld a, [$ffe0] - AdjustEventBit EVENT_CINNABAR_GYM_GATE0_UNLOCKED, 0 - ld c, a - ld b, FLAG_TEST - call CinnabarGymGateFlagAction - ld a, c - and a - jp nz, TextScriptEnd - call WaitForSoundToFinish - ld a, SFX_GO_INSIDE - call PlaySound - call WaitForSoundToFinish - jp TextScriptEnd - -CinnabarGymQuizIncorrectText: - TX_FAR _CinnabarGymQuizIncorrectText - db "@" - -UpdateCinnabarGymGateTileBlocks_:: -; Update the overworld map with open floor blocks or locked gate blocks -; depending on event flags. - ld a, 6 - ld [hGymGateIndex], a -.loop - ld a, [hGymGateIndex] - dec a - add a - add a - ld d, 0 - ld e, a - ld hl, CinnabarGymGateCoords - add hl, de - ld a, [hli] - ld b, [hl] - ld c, a - inc hl - ld a, [hl] - ld [wGymGateTileBlock], a - push bc - ld a, [hGymGateIndex] - ld [$ffe0], a - AdjustEventBit EVENT_CINNABAR_GYM_GATE0_UNLOCKED, 0 - ld c, a - ld b, FLAG_TEST - call CinnabarGymGateFlagAction - ld a, c - and a - jr nz, .unlocked - ld a, [wGymGateTileBlock] - jr .next -.unlocked - ld a, $e -.next - pop bc - ld [wNewTileBlockID], a - predef ReplaceTileBlock - ld hl, hGymGateIndex - dec [hl] - jr nz, .loop - ret - -CinnabarGymGateCoords: - ; format: x-coord, y-coord, direction, padding - ; direction: $54 = horizontal gate, $5f = vertical gate - db $09,$03,$54,$00 - db $06,$03,$54,$00 - db $06,$06,$54,$00 - db $03,$08,$5f,$00 - db $02,$06,$54,$00 - db $02,$03,$54,$00 - -PrintMagazinesText: - call EnableAutoTextBoxDrawing - tx_pre MagazinesText - ret - -MagazinesText:: - TX_FAR _MagazinesText - db "@" - -BillsHousePC: - call EnableAutoTextBoxDrawing - ld a, [wSpriteStateData1 + 9] - cp SPRITE_FACING_UP - ret nz - CheckEvent EVENT_LEFT_BILLS_HOUSE_AFTER_HELPING - jr nz, .displayBillsHousePokemonList - CheckEventReuseA EVENT_USED_CELL_SEPARATOR_ON_BILL - jr nz, .displayBillsHouseMonitorText - CheckEventReuseA EVENT_BILL_SAID_USE_CELL_SEPARATOR - jr nz, .doCellSeparator -.displayBillsHouseMonitorText - tx_pre_jump BillsHouseMonitorText -.doCellSeparator - ld a, $1 - ld [wDoNotWaitForButtonPressAfterDisplayingText], a - tx_pre BillsHouseInitiatedText - ld c, 32 - call DelayFrames - ld a, SFX_TINK - call PlaySound - call WaitForSoundToFinish - ld c, 80 - call DelayFrames - ld a, SFX_SHRINK - call PlaySound - call WaitForSoundToFinish - ld c, 48 - call DelayFrames - ld a, SFX_TINK - call PlaySound - call WaitForSoundToFinish - ld c, 32 - call DelayFrames - ld a, SFX_GET_ITEM_1 - call PlaySound - call WaitForSoundToFinish - call PlayDefaultMusic - SetEvent EVENT_USED_CELL_SEPARATOR_ON_BILL - ret -.displayBillsHousePokemonList - ld a, $1 - ld [wDoNotWaitForButtonPressAfterDisplayingText], a - tx_pre BillsHousePokemonList - ret - -BillsHouseMonitorText:: - TX_FAR _BillsHouseMonitorText - db "@" - -BillsHouseInitiatedText:: - TX_FAR _BillsHouseInitiatedText - TX_BLINK - TX_ASM - ld a, $ff - ld [wNewSoundID], a - call PlaySound - ld c, 16 - call DelayFrames - ld a, SFX_SWITCH - call PlaySound - call WaitForSoundToFinish - ld c, 60 - call DelayFrames - jp TextScriptEnd - -BillsHousePokemonList:: - TX_ASM - call SaveScreenTilesToBuffer1 - ld hl, BillsHousePokemonListText1 - call PrintText - xor a - ld [wMenuItemOffset], a ; not used - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - ld a, A_BUTTON | B_BUTTON - ld [wMenuWatchedKeys], a - ld a, 4 - ld [wMaxMenuItem], a - ld a, 2 - ld [wTopMenuItemY], a - ld a, 1 - ld [wTopMenuItemX], a -.billsPokemonLoop - ld hl, wd730 - set 6, [hl] - coord hl, 0, 0 - ld b, 10 - ld c, 9 - call TextBoxBorder - coord hl, 2, 2 - ld de, BillsMonListText - call PlaceString - ld hl, BillsHousePokemonListText2 - call PrintText - call SaveScreenTilesToBuffer2 - call HandleMenuInput - bit 1, a ; pressed b - jr nz, .cancel - ld a, [wCurrentMenuItem] - add EEVEE - cp EEVEE - jr z, .displayPokedex - cp FLAREON - jr z, .displayPokedex - cp JOLTEON - jr z, .displayPokedex - cp VAPOREON - jr z, .displayPokedex - jr .cancel -.displayPokedex - call DisplayPokedex - call LoadScreenTilesFromBuffer2 - jr .billsPokemonLoop -.cancel - ld hl, wd730 - res 6, [hl] - call LoadScreenTilesFromBuffer2 - jp TextScriptEnd - -BillsHousePokemonListText1: - TX_FAR _BillsHousePokemonListText1 - db "@" - -BillsMonListText: - db "EEVEE" - next "FLAREON" - next "JOLTEON" - next "VAPOREON" - next "CANCEL@" - -BillsHousePokemonListText2: - TX_FAR _BillsHousePokemonListText2 - db "@" - -DisplayOakLabEmailText: - ld a, [wSpriteStateData1 + 9] - cp SPRITE_FACING_UP - ret nz - call EnableAutoTextBoxDrawing - tx_pre_jump OakLabEmailText - -OakLabEmailText:: - TX_FAR _OakLabEmailText - db "@" diff --git a/engine/hp_bar.asm b/engine/hp_bar.asm deleted file mode 100755 index 221bd7a9..00000000 --- a/engine/hp_bar.asm +++ /dev/null @@ -1,270 +0,0 @@ -HPBarLength: - call GetPredefRegisters - -; calculates bc * 48 / de, the number of pixels the HP bar has -; the result is always at least 1 -GetHPBarLength: - push hl - xor a - ld hl, H_MULTIPLICAND - ld [hli], a - ld a, b - ld [hli], a - ld a, c - ld [hli], a - ld [hl], $30 - call Multiply ; 48 * bc (hp bar is 48 pixels long) - ld a, d - and a - jr z, .maxHPSmaller256 - srl d ; make HP in de fit into 1 byte by dividing by 4 - rr e - srl d - rr e - ld a, [H_MULTIPLICAND+1] - ld b, a - ld a, [H_MULTIPLICAND+2] - srl b ; divide multiplication result as well - rr a - srl b - rr a - ld [H_MULTIPLICAND+2], a - ld a, b - ld [H_MULTIPLICAND+1], a -.maxHPSmaller256 - ld a, e - ld [H_DIVISOR], a - ld b, $4 - call Divide - ld a, [H_MULTIPLICAND+2] - ld e, a ; e = bc * 48 / de (num of pixels of HP bar) - pop hl - and a - ret nz - ld e, $1 ; make result at least 1 - ret - -; predef $48 -UpdateHPBar: -UpdateHPBar2: - push hl - ld hl, wHPBarOldHP - ld a, [hli] - ld c, a ; old HP into bc - ld a, [hli] - ld b, a - ld a, [hli] - ld e, a ; new HP into de - ld d, [hl] - pop hl - push de - push bc - call UpdateHPBar_CalcHPDifference - ld a, e - ld [wHPBarHPDifference+1], a - ld a, d - ld [wHPBarHPDifference], a - pop bc - pop de - call UpdateHPBar_CompareNewHPToOldHP - ret z - ld a, $ff - jr c, .HPdecrease - ld a, $1 -.HPdecrease - ld [wHPBarDelta], a - call GetPredefRegisters - ld a, [wHPBarNewHP] - ld e, a - ld a, [wHPBarNewHP+1] - ld d, a -.animateHPBarLoop - push de - ld a, [wHPBarOldHP] - ld c, a - ld a, [wHPBarOldHP+1] - ld b, a - call UpdateHPBar_CompareNewHPToOldHP - jr z, .animateHPBarDone - jr nc, .HPIncrease -; HP decrease - dec bc ; subtract 1 HP - ld a, c - ld [wHPBarNewHP], a - ld a, b - ld [wHPBarNewHP+1], a - call UpdateHPBar_CalcOldNewHPBarPixels - ld a, e - sub d ; calc pixel difference - jr .ok -.HPIncrease - inc bc ; add 1 HP - ld a, c - ld [wHPBarNewHP], a - ld a, b - ld [wHPBarNewHP+1], a - call UpdateHPBar_CalcOldNewHPBarPixels - ld a, d - sub e ; calc pixel difference -.ok - call UpdateHPBar_PrintHPNumber - and a - jr z, .noPixelDifference - call UpdateHPBar_AnimateHPBar -.noPixelDifference - ld a, [wHPBarNewHP] - ld [wHPBarOldHP], a - ld a, [wHPBarNewHP+1] - ld [wHPBarOldHP+1], a - pop de - jr .animateHPBarLoop -.animateHPBarDone - pop de - ld a, e - ld [wHPBarOldHP], a - ld a, d - ld [wHPBarOldHP+1], a - or e - jr z, .monFainted - call UpdateHPBar_CalcOldNewHPBarPixels - ld d, e -.monFainted - call UpdateHPBar_PrintHPNumber - ld a, $1 - call UpdateHPBar_AnimateHPBar - jp Delay3 - -; animates the HP bar going up or down for (a) ticks (two waiting frames each) -; stops prematurely if bar is filled up -; e: current health (in pixels) to start with -UpdateHPBar_AnimateHPBar: - push hl -.barAnimationLoop - push af - push de - ld d, $6 - call DrawHPBar - ld c, 2 - call DelayFrames - pop de - ld a, [wHPBarDelta] ; +1 or -1 - add e - cp $31 - jr nc, .barFilledUp - ld e, a - pop af - dec a - jr nz, .barAnimationLoop - pop hl - ret -.barFilledUp - pop af - pop hl - ret - -; compares old HP and new HP and sets c and z flags accordingly -UpdateHPBar_CompareNewHPToOldHP: - ld a, d - sub b - ret nz - ld a, e - sub c - ret - -; calcs HP difference between bc and de (into de) -UpdateHPBar_CalcHPDifference: - ld a, d - sub b - jr c, .oldHPGreater - jr z, .testLowerByte -.newHPGreater - ld a, e - sub c - ld e, a - ld a, d - sbc b - ld d, a - ret -.oldHPGreater - ld a, c - sub e - ld e, a - ld a, b - sbc d - ld d, a - ret -.testLowerByte - ld a, e - sub c - jr c, .oldHPGreater - jr nz, .newHPGreater - ld de, $0 - ret - -UpdateHPBar_PrintHPNumber: - push af - push de - ld a, [wHPBarType] - and a - jr z, .done ; don't print number in enemy HUD -; convert from little-endian to big-endian for PrintNumber - ld a, [wHPBarOldHP] - ld [wHPBarTempHP + 1], a - ld a, [wHPBarOldHP + 1] - ld [wHPBarTempHP], a - push hl - ld a, [hFlags_0xFFF6] - bit 0, a - jr z, .asm_fb15 - ld de, $9 - jr .next -.asm_fb15 - ld de, $15 -.next - add hl, de - push hl - ld a, " " - ld [hli], a - ld [hli], a - ld [hli], a - pop hl - ld de, wHPBarTempHP - lb bc, 2, 3 - call PrintNumber - call DelayFrame - pop hl -.done - pop de - pop af - ret - -; calcs number of HP bar pixels for old and new HP value -; d: new pixels -; e: old pixels -UpdateHPBar_CalcOldNewHPBarPixels: - push hl - ld hl, wHPBarMaxHP - ld a, [hli] ; max HP into de - ld e, a - ld a, [hli] - ld d, a - ld a, [hli] ; old HP into bc - ld c, a - ld a, [hli] - ld b, a - ld a, [hli] ; new HP into hl - ld h, [hl] - ld l, a - push hl - push de - call GetHPBarLength ; calc num pixels for old HP - ld a, e - pop de - pop bc - push af - call GetHPBarLength ; calc num pixels for new HP - pop af - ld d, e - ld e, a - pop hl - ret diff --git a/engine/in_game_trades.asm b/engine/in_game_trades.asm deleted file mode 100755 index c01bc3c3..00000000 --- a/engine/in_game_trades.asm +++ /dev/null @@ -1,330 +0,0 @@ -DoInGameTradeDialogue: -; trigger the trade offer/action specified by wWhichTrade - 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 a, [hli] - ld [wInGameTradeGiveMonSpecies], a - ld a, [hli] - ld [wInGameTradeReceiveMonSpecies], a - ld a, [hli] - push af - ld de, wInGameTradeMonNick - ld bc, NAME_LENGTH - call CopyData - pop af - ld l, a - ld h, 0 - ld de, InGameTradeTextPointers - add hl, hl - add hl, de - ld a, [hli] - ld [wInGameTradeTextPointerTablePointer], a - ld a, [hl] - ld [wInGameTradeTextPointerTablePointer + 1], a - ld a, [wInGameTradeGiveMonSpecies] - ld de, wInGameTradeGiveMonName - call InGameTrade_GetMonName - ld a, [wInGameTradeReceiveMonSpecies] - ld de, wInGameTradeReceiveMonName - call InGameTrade_GetMonName - ld hl, wCompletedInGameTradeFlags - ld a, [wWhichTrade] - ld c, a - ld b, FLAG_TEST - predef 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 [wInGameTradeTextPointerTableIndex], a - call .printText - ld a, $1 - ld [wInGameTradeTextPointerTableIndex], a - call YesNoChoice - ld a, [wCurrentMenuItem] - and a - jr nz, .printText - call InGameTrade_DoTrade - jr c, .printText - ld hl, TradedForText - call PrintText -.printText - ld hl, wInGameTradeTextPointerTableIndex - ld a, [hld] ; wInGameTradeTextPointerTableIndex - ld e, a - ld d, 0 - ld a, [hld] ; wInGameTradeTextPointerTablePointer + 1 - ld l, [hl] ; wInGameTradeTextPointerTablePointer - ld h, a - add hl, de - add hl, de - ld a, [hli] - ld h, [hl] - ld l, a - jp PrintText - -; copies name of species a to hl -InGameTrade_GetMonName: - push de - ld [wd11e], a - call GetMonName - ld hl, wcd6d - pop de - ld bc, NAME_LENGTH - jp CopyData - -INCLUDE "data/trades.asm" - -InGameTrade_DoTrade: - xor a ; NORMAL_PARTY_MENU - ld [wPartyMenuTypeOrMessageID], a - dec a - ld [wUpdateSpritesEnabled], a - call DisplayPartyMenu - push af - call InGameTrade_RestoreScreen - pop af - ld a, $1 - jp c, .tradeFailed ; jump if the player didn't select a pokemon - ld a, [wInGameTradeGiveMonSpecies] - ld b, a - ld a, [wcf91] - cp b - ld a, $2 - jr nz, .tradeFailed ; jump if the selected mon's species is not the required one - ld a, [wWhichPokemon] - ld hl, wPartyMon1Level - ld bc, wPartyMon2 - wPartyMon1 - call AddNTimes - ld a, [hl] - ld [wCurEnemyLVL], a - ld hl, wCompletedInGameTradeFlags - ld a, [wWhichTrade] - ld c, a - ld b, FLAG_SET - predef FlagActionPredef - ld hl, ConnectCableText - call PrintText - ld a, [wWhichPokemon] - push af - ld a, [wCurEnemyLVL] - push af - call LoadHpBarAndStatusTilePatterns - call InGameTrade_PrepareTradeData - predef InternalClockTradeAnim - pop af - ld [wCurEnemyLVL], a - pop af - ld [wWhichPokemon], a - ld a, [wInGameTradeReceiveMonSpecies] - ld [wcf91], a - xor a - ld [wMonDataLocation], a ; not used - ld [wRemoveMonFromBox], a - call RemovePokemon - ld a, $80 ; prevent the player from naming the mon - ld [wMonDataLocation], a - call AddPartyMon - call InGameTrade_CopyDataToReceivedMon - callab EvolveTradeMon - call ClearScreen - call InGameTrade_RestoreScreen - callba RedrawMapView - and a - ld a, $3 - jr .tradeSucceeded -.tradeFailed - scf -.tradeSucceeded - ld [wInGameTradeTextPointerTableIndex], a - ret - -InGameTrade_RestoreScreen: - call GBPalWhiteOutWithDelay3 - call RestoreScreenTilesAndReloadTilePatterns - call ReloadTilesetTilePatterns - call LoadScreenTilesFromBuffer2 - call Delay3 - call LoadGBPal - ld c, 10 - call DelayFrames - jpba LoadWildData - -InGameTrade_PrepareTradeData: - ld hl, wTradedPlayerMonSpecies - ld a, [wInGameTradeGiveMonSpecies] - ld [hli], a ; wTradedPlayerMonSpecies - ld a, [wInGameTradeReceiveMonSpecies] - ld [hl], a ; wTradedEnemyMonSpecies - ld hl, wPartyMonOT - ld bc, NAME_LENGTH - ld a, [wWhichPokemon] - call AddNTimes - ld de, wTradedPlayerMonOT - ld bc, NAME_LENGTH - call InGameTrade_CopyData - ld hl, InGameTrade_TrainerString - ld de, wTradedEnemyMonOT - call InGameTrade_CopyData - ld de, wLinkEnemyTrainerName - call InGameTrade_CopyData - ld hl, wPartyMon1OTID - ld bc, wPartyMon2 - wPartyMon1 - ld a, [wWhichPokemon] - call AddNTimes - ld de, wTradedPlayerMonOTID - ld bc, $2 - call InGameTrade_CopyData - call Random - ld hl, hRandomAdd - ld de, wTradedEnemyMonOTID - jp CopyData - -InGameTrade_CopyData: - push hl - push bc - call CopyData - pop bc - pop hl - ret - -InGameTrade_CopyDataToReceivedMon: - ld hl, wPartyMonNicks - ld bc, NAME_LENGTH - call InGameTrade_GetReceivedMonPointer - ld hl, wInGameTradeMonNick - ld bc, NAME_LENGTH - call CopyData - ld hl, wPartyMonOT - ld bc, NAME_LENGTH - call InGameTrade_GetReceivedMonPointer - ld hl, InGameTrade_TrainerString - ld bc, NAME_LENGTH - call CopyData - ld hl, wPartyMon1OTID - ld bc, wPartyMon2 - wPartyMon1 - call InGameTrade_GetReceivedMonPointer - ld hl, wTradedEnemyMonOTID - ld bc, $2 - jp CopyData - -; the received mon's index is (partyCount - 1), -; so this adds bc to hl (partyCount - 1) times and moves the result to de -InGameTrade_GetReceivedMonPointer: - ld a, [wPartyCount] - dec a - call AddNTimes - ld e, l - ld d, h - ret - -InGameTrade_TrainerString: - ; "TRAINER@@@@@@@@@@" - db $5d, "@@@@@@@@@@" - -InGameTradeTextPointers: - dw TradeTextPointers1 - dw TradeTextPointers2 - dw TradeTextPointers3 - -TradeTextPointers1: - dw WannaTrade1Text - dw NoTrade1Text - dw WrongMon1Text - dw Thanks1Text - dw AfterTrade1Text - -TradeTextPointers2: - dw WannaTrade2Text - dw NoTrade2Text - dw WrongMon2Text - dw Thanks2Text - dw AfterTrade2Text - -TradeTextPointers3: - dw WannaTrade3Text - dw NoTrade3Text - dw WrongMon3Text - dw Thanks3Text - dw AfterTrade3Text - -ConnectCableText: - TX_FAR _ConnectCableText - db "@" - -TradedForText: - TX_FAR _TradedForText - TX_SFX_KEY_ITEM - TX_DELAY - db "@" - -WannaTrade1Text: - TX_FAR _WannaTrade1Text - db "@" - -NoTrade1Text: - TX_FAR _NoTrade1Text - db "@" - -WrongMon1Text: - TX_FAR _WrongMon1Text - db "@" - -Thanks1Text: - TX_FAR _Thanks1Text - db "@" - -AfterTrade1Text: - TX_FAR _AfterTrade1Text - db "@" - -WannaTrade2Text: - TX_FAR _WannaTrade2Text - db "@" - -NoTrade2Text: - TX_FAR _NoTrade2Text - db "@" - -WrongMon2Text: - TX_FAR _WrongMon2Text - db "@" - -Thanks2Text: - TX_FAR _Thanks2Text - db "@" - -AfterTrade2Text: - TX_FAR _AfterTrade2Text - db "@" - -WannaTrade3Text: - TX_FAR _WannaTrade3Text - db "@" - -NoTrade3Text: - TX_FAR _NoTrade3Text - db "@" - -WrongMon3Text: - TX_FAR _WrongMon3Text - db "@" - -Thanks3Text: - TX_FAR _Thanks3Text - db "@" - -AfterTrade3Text: - TX_FAR _AfterTrade3Text - db "@" diff --git a/engine/init_player_data.asm b/engine/init_player_data.asm deleted file mode 100644 index c576e65a..00000000 --- a/engine/init_player_data.asm +++ /dev/null @@ -1,55 +0,0 @@ -InitPlayerData: -InitPlayerData2: - - call Random - ld a, [hRandomSub] - ld [wPlayerID], a - - call Random - ld a, [hRandomAdd] - ld [wPlayerID + 1], a - - ld a, $ff - ld [wUnusedD71B], a - - ld hl, wPartyCount - call InitializeEmptyList - ld hl, wNumInBox - call InitializeEmptyList - ld hl, wNumBagItems - call InitializeEmptyList - ld hl, wNumBoxItems - call InitializeEmptyList - -START_MONEY EQU $3000 - ld hl, wPlayerMoney + 1 - ld a, START_MONEY / $100 - ld [hld], a - xor a - ld [hli], a - inc hl - ld [hl], a - - ld [wMonDataLocation], a - - ld hl, wObtainedBadges - ld [hli], a - - ld [hl], a - - ld hl, wPlayerCoins - ld [hli], a - ld [hl], a - - ld hl, wGameProgressFlags - ld bc, wGameProgressFlagsEnd - wGameProgressFlags - call FillMemory ; clear all game progress flags - - jp InitializeMissableObjectsFlags - -InitializeEmptyList: - xor a ; count - ld [hli], a - dec a ; terminator - ld [hl], a - ret diff --git a/engine/intro.asm b/engine/intro.asm deleted file mode 100755 index 9a13c96f..00000000 --- a/engine/intro.asm +++ /dev/null @@ -1,470 +0,0 @@ -const_value = -1 - const MOVE_NIDORINO_RIGHT - const MOVE_GENGAR_RIGHT - const MOVE_GENGAR_LEFT - -ANIMATION_END EQU 80 - -const_value = 3 - const GENGAR_INTRO_TILES1 - const GENGAR_INTRO_TILES2 - const GENGAR_INTRO_TILES3 - -PlayIntro: - xor a - ld [hJoyHeld], a - inc a - ld [H_AUTOBGTRANSFERENABLED], a - call PlayShootingStar - call PlayIntroScene - call GBFadeOutToWhite - xor a - ld [hSCX], a - ld [H_AUTOBGTRANSFERENABLED], a - call ClearSprites - call DelayFrame - ret - -PlayIntroScene: - ld b, SET_PAL_NIDORINO_INTRO - call RunPaletteCommand - ldPal a, BLACK, DARK_GRAY, LIGHT_GRAY, WHITE - ld [rBGP], a - ld [rOBP0], a - ld [rOBP1], a - xor a - ld [hSCX], a - ld b, GENGAR_INTRO_TILES1 - call IntroCopyTiles - ld a, 0 - ld [wBaseCoordX], a - ld a, 80 - ld [wBaseCoordY], a - lb bc, 6, 6 - call InitIntroNidorinoOAM - lb de, 80 / 2, MOVE_NIDORINO_RIGHT - call IntroMoveMon - ret c - -; hip - ld a, SFX_INTRO_HIP - call PlaySound - xor a - ld [wIntroNidorinoBaseTile], a - ld de, IntroNidorinoAnimation1 - call AnimateIntroNidorino -; hop - ld a, SFX_INTRO_HOP - call PlaySound - ld de, IntroNidorinoAnimation2 - call AnimateIntroNidorino - ld c, 10 - call CheckForUserInterruption - ret c - -; hip - ld a, SFX_INTRO_HIP - call PlaySound - ld de, IntroNidorinoAnimation1 - call AnimateIntroNidorino -; hop - ld a, SFX_INTRO_HOP - call PlaySound - ld de, IntroNidorinoAnimation2 - call AnimateIntroNidorino - ld c, 30 - call CheckForUserInterruption - ret c - -; raise - ld b, GENGAR_INTRO_TILES2 - call IntroCopyTiles - ld a, SFX_INTRO_RAISE - call PlaySound - lb de, 8 / 2, MOVE_GENGAR_LEFT - call IntroMoveMon - ld c, 30 - call CheckForUserInterruption - ret c - -; slash - ld b, GENGAR_INTRO_TILES3 - call IntroCopyTiles - ld a, SFX_INTRO_CRASH - call PlaySound - lb de, 16 / 2, MOVE_GENGAR_RIGHT - call IntroMoveMon -; hip - ld a, SFX_INTRO_HIP - call PlaySound - ld a, (FightIntroFrontMon2 - FightIntroFrontMon) / BYTES_PER_TILE - ld [wIntroNidorinoBaseTile], a - ld de, IntroNidorinoAnimation3 - call AnimateIntroNidorino - ld c, 30 - call CheckForUserInterruption - ret c - - lb de, 8 / 2, MOVE_GENGAR_LEFT - call IntroMoveMon - ld b, GENGAR_INTRO_TILES1 - call IntroCopyTiles - ld c, 60 - call CheckForUserInterruption - ret c - -; hip - ld a, SFX_INTRO_HIP - call PlaySound - xor a - ld [wIntroNidorinoBaseTile], a - ld de, IntroNidorinoAnimation4 - call AnimateIntroNidorino -; hop - ld a, SFX_INTRO_HOP - call PlaySound - ld de, IntroNidorinoAnimation5 - call AnimateIntroNidorino - ld c, 20 - call CheckForUserInterruption - ret c - - ld a, (FightIntroFrontMon2 - FightIntroFrontMon) / BYTES_PER_TILE - ld [wIntroNidorinoBaseTile], a - ld de, IntroNidorinoAnimation6 - call AnimateIntroNidorino - ld c, 30 - call CheckForUserInterruption - ret c - -; lunge - ld a, SFX_INTRO_LUNGE - call PlaySound - ld a, (FightIntroFrontMon3 - FightIntroFrontMon) / BYTES_PER_TILE - ld [wIntroNidorinoBaseTile], a - ld de, IntroNidorinoAnimation7 - jp AnimateIntroNidorino - -AnimateIntroNidorino: - ld a, [de] - cp ANIMATION_END - ret z - ld [wBaseCoordY], a - inc de - ld a, [de] - ld [wBaseCoordX], a - push de - ld c, 6 * 6 - call UpdateIntroNidorinoOAM - ld c, 5 - call DelayFrames - pop de - inc de - jr AnimateIntroNidorino - -UpdateIntroNidorinoOAM: - ld hl, wOAMBuffer - ld a, [wIntroNidorinoBaseTile] - ld d, a -.loop - ld a, [wBaseCoordY] - add [hl] - ld [hli], a ; Y - ld a, [wBaseCoordX] - add [hl] - ld [hli], a ; X - ld a, d - ld [hli], a ; tile - inc hl - inc d - dec c - jr nz, .loop - ret - -InitIntroNidorinoOAM: - ld hl, wOAMBuffer - ld d, 0 -.loop - push bc - ld a, [wBaseCoordY] - ld e, a -.innerLoop - ld a, e - add 8 - ld e, a - ld [hli], a ; Y - ld a, [wBaseCoordX] - ld [hli], a ; X - ld a, d - ld [hli], a ; tile - ld a, OAM_BEHIND_BG - ld [hli], a ; attributes - inc d - dec c - jr nz, .innerLoop - ld a, [wBaseCoordX] - add 8 - ld [wBaseCoordX], a - pop bc - dec b - jr nz, .loop - ret - -IntroClearScreen: - ld hl, vBGMap1 - ld bc, BG_MAP_WIDTH * SCREEN_HEIGHT - jr IntroClearCommon - -IntroClearMiddleOfScreen: -; clear the area of the tile map between the black bars on the top and bottom - coord hl, 0, 4 - ld bc, SCREEN_WIDTH * 10 - -IntroClearCommon: - ld [hl], 0 - inc hl - dec bc - ld a, b - or c - jr nz, IntroClearCommon - ret - -IntroPlaceBlackTiles: - ld a, 1 -.loop - ld [hli], a - dec c - jr nz, .loop - ret - -IntroMoveMon: -; d = number of times to move the mon (2 pixels each time) - ld a, e - cp MOVE_NIDORINO_RIGHT - jr z, .moveNidorinoRight - cp MOVE_GENGAR_LEFT - jr z, .moveGengarLeft -; move Gengar right - ld a, [hSCX] - dec a - dec a - jr .next -.moveNidorinoRight - push de - ld a, 2 - ld [wBaseCoordX], a - xor a - ld [wBaseCoordY], a - ld c, 6 * 6 - call UpdateIntroNidorinoOAM - pop de -.moveGengarLeft - ld a, [hSCX] - inc a - inc a -.next - ld [hSCX], a - push de - ld c, 2 - call CheckForUserInterruption - pop de - ret c - dec d - jr nz, IntroMoveMon - ret - -IntroCopyTiles: - coord hl, 13, 7 - -CopyTileIDsFromList_ZeroBaseTileID: - ld c, 0 - predef_jump CopyTileIDsFromList - -PlayMoveSoundB: -; unused - predef GetMoveSoundB - ld a, b - jp PlaySound - -LoadIntroGraphics: - ld hl, FightIntroBackMon - ld de, vChars2 - ld bc, FightIntroBackMonEnd - FightIntroBackMon - ld a, BANK(FightIntroBackMon) - call FarCopyData2 - ld hl, GameFreakIntro - ld de, vChars2 + (FightIntroBackMonEnd - FightIntroBackMon) - ld bc, GameFreakIntroEnd - GameFreakIntro - ld a, BANK(GameFreakIntro) - call FarCopyData2 - ld hl, GameFreakIntro - ld de, vChars1 - ld bc, GameFreakIntroEnd - GameFreakIntro - ld a, BANK(GameFreakIntro) - call FarCopyData2 - ld hl, FightIntroFrontMon - ld de, vChars0 - ld bc, FightIntroFrontMonEnd - FightIntroFrontMon - ld a, BANK(FightIntroFrontMon) - jp FarCopyData2 - -PlayShootingStar: - ld b, SET_PAL_GAME_FREAK_INTRO - call RunPaletteCommand - callba LoadCopyrightAndTextBoxTiles - ldPal a, BLACK, DARK_GRAY, LIGHT_GRAY, WHITE - ld [rBGP], a - ld c, 180 - call DelayFrames - call ClearScreen - call DisableLCD - xor a - ld [wCurOpponent], a - call IntroDrawBlackBars - call LoadIntroGraphics - call EnableLCD - ld hl, rLCDC - res 5, [hl] - set 3, [hl] - ld c, 64 - call DelayFrames - callba AnimateShootingStar - push af - pop af - jr c, .next ; skip the delay if the user interrupted the animation - 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 - -IntroDrawBlackBars: -; clear the screen and draw black bars on the top and bottom - call IntroClearScreen - coord hl, 0, 0 - ld c, SCREEN_WIDTH * 4 - call IntroPlaceBlackTiles - coord hl, 0, 14 - ld c, SCREEN_WIDTH * 4 - call IntroPlaceBlackTiles - ld hl, vBGMap1 - ld c, BG_MAP_WIDTH * 4 - call IntroPlaceBlackTiles - ld hl, vBGMap1 + BG_MAP_WIDTH * 14 - ld c, BG_MAP_WIDTH * 4 - jp IntroPlaceBlackTiles - -EmptyFunc4: - ret - -IntroNidorinoAnimation0: - db 0, 0 - db ANIMATION_END - -IntroNidorinoAnimation1: -; This is a sequence of pixel movements for part of the Nidorino animation. This -; list describes how Nidorino should hop. -; First byte is y movement, second byte is x movement - db 0, 0 - db -2, 2 - db -1, 2 - db 1, 2 - db 2, 2 - db ANIMATION_END - -IntroNidorinoAnimation2: -; This is a sequence of pixel movements for part of the Nidorino animation. -; First byte is y movement, second byte is x movement - db 0, 0 - db -2, -2 - db -1, -2 - db 1, -2 - db 2, -2 - db ANIMATION_END - -IntroNidorinoAnimation3: -; This is a sequence of pixel movements for part of the Nidorino animation. -; First byte is y movement, second byte is x movement - db 0, 0 - db -12, 6 - db -8, 6 - db 8, 6 - db 12, 6 - db ANIMATION_END - -IntroNidorinoAnimation4: -; This is a sequence of pixel movements for part of the Nidorino animation. -; First byte is y movement, second byte is x movement - db 0, 0 - db -8, -4 - db -4, -4 - db 4, -4 - db 8, -4 - db ANIMATION_END - -IntroNidorinoAnimation5: -; This is a sequence of pixel movements for part of the Nidorino animation. -; First byte is y movement, second byte is x movement - db 0, 0 - db -8, 4 - db -4, 4 - db 4, 4 - db 8, 4 - db ANIMATION_END - -IntroNidorinoAnimation6: -; This is a sequence of pixel movements for part of the Nidorino animation. -; First byte is y movement, second byte is x movement - db 0, 0 - db 2, 0 - db 2, 0 - db 0, 0 - db ANIMATION_END - -IntroNidorinoAnimation7: -; This is a sequence of pixel movements for part of the Nidorino animation. -; First byte is y movement, second byte is x movement - db -8, -16 - db -7, -14 - db -6, -12 - db -4, -10 - db ANIMATION_END - -GameFreakIntro: - INCBIN "gfx/intro_credits/gamefreak_presents.2bpp" - INCBIN "gfx/intro_credits/gamefreak_logo.2bpp" - ds 16, $00 ; blank tile -GameFreakIntroEnd: - -FightIntroBackMon: - INCBIN "gfx/intro_credits/gengar.2bpp" -FightIntroBackMonEnd: - -FightIntroFrontMon: - -IF DEF(_RED) - INCBIN "gfx/intro_credits/red_nidorino_1.2bpp" -FightIntroFrontMon2: - INCBIN "gfx/intro_credits/red_nidorino_2.2bpp" -FightIntroFrontMon3: - INCBIN "gfx/intro_credits/red_nidorino_3.2bpp" -ENDC - -IF DEF(_BLUE) - INCBIN "gfx/intro_credits/blue_jigglypuff_1.2bpp" -FightIntroFrontMon2: - INCBIN "gfx/intro_credits/blue_jigglypuff_2.2bpp" -FightIntroFrontMon3: - INCBIN "gfx/intro_credits/blue_jigglypuff_3.2bpp" -ENDC - -FightIntroFrontMonEnd: - - ds 16, $00 ; blank tile diff --git a/engine/items/get_bag_item_quantity.asm b/engine/items/get_bag_item_quantity.asm new file mode 100644 index 00000000..f10df1a0 --- /dev/null +++ b/engine/items/get_bag_item_quantity.asm @@ -0,0 +1,18 @@ +GetQuantityOfItemInBag: +; In: b = item ID +; Out: b = how many of that item are in the bag + call GetPredefRegisters + ld hl, wNumBagItems +.loop + inc hl + ld a, [hli] + cp $ff + jr z, .notInBag + cp b + jr nz, .loop + ld a, [hl] + ld b, a + ret +.notInBag + ld b, 0 + ret diff --git a/engine/items/item_effects.asm b/engine/items/item_effects.asm new file mode 100755 index 00000000..6e7bed1e --- /dev/null +++ b/engine/items/item_effects.asm @@ -0,0 +1,2986 @@ +UseItem_:: + ld a, 1 + ld [wActionResultOrTookBattleTurn], a ; initialise to success value + ld a, [wcf91] ;contains item_ID + cp HM_01 + jp nc, ItemUseTMHM + ld hl, ItemUsePtrTable + dec a + add a + ld c, a + ld b, 0 + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +ItemUsePtrTable: + dw ItemUseBall ; MASTER_BALL + dw ItemUseBall ; ULTRA_BALL + dw ItemUseBall ; GREAT_BALL + dw ItemUseBall ; POKE_BALL + dw ItemUseTownMap ; TOWN_MAP + dw ItemUseBicycle ; BICYCLE + dw ItemUseSurfboard ; out-of-battle Surf effect + dw ItemUseBall ; SAFARI_BALL + dw ItemUsePokedex ; POKEDEX + dw ItemUseEvoStone ; MOON_STONE + dw ItemUseMedicine ; ANTIDOTE + dw ItemUseMedicine ; BURN_HEAL + dw ItemUseMedicine ; ICE_HEAL + dw ItemUseMedicine ; AWAKENING + dw ItemUseMedicine ; PARLYZ_HEAL + dw ItemUseMedicine ; FULL_RESTORE + dw ItemUseMedicine ; MAX_POTION + dw ItemUseMedicine ; HYPER_POTION + dw ItemUseMedicine ; SUPER_POTION + dw ItemUseMedicine ; POTION + dw ItemUseBait ; BOULDERBADGE + dw ItemUseRock ; CASCADEBADGE + dw UnusableItem ; THUNDERBADGE + dw UnusableItem ; RAINBOWBADGE + dw UnusableItem ; SOULBADGE + dw UnusableItem ; MARSHBADGE + dw UnusableItem ; VOLCANOBADGE + dw UnusableItem ; EARTHBADGE + dw ItemUseEscapeRope ; ESCAPE_ROPE + dw ItemUseRepel ; REPEL + dw UnusableItem ; OLD_AMBER + dw ItemUseEvoStone ; FIRE_STONE + dw ItemUseEvoStone ; THUNDER_STONE + dw ItemUseEvoStone ; WATER_STONE + dw ItemUseVitamin ; HP_UP + dw ItemUseVitamin ; PROTEIN + dw ItemUseVitamin ; IRON + dw ItemUseVitamin ; CARBOS + dw ItemUseVitamin ; CALCIUM + dw ItemUseVitamin ; RARE_CANDY + dw UnusableItem ; DOME_FOSSIL + dw UnusableItem ; HELIX_FOSSIL + dw UnusableItem ; SECRET_KEY + dw UnusableItem + dw UnusableItem ; BIKE_VOUCHER + dw ItemUseXAccuracy ; X_ACCURACY + dw ItemUseEvoStone ; LEAF_STONE + dw ItemUseCardKey ; CARD_KEY + dw UnusableItem ; NUGGET + dw UnusableItem ; ??? PP_UP + dw ItemUsePokedoll ; POKE_DOLL + dw ItemUseMedicine ; FULL_HEAL + dw ItemUseMedicine ; REVIVE + dw ItemUseMedicine ; MAX_REVIVE + dw ItemUseGuardSpec ; GUARD_SPEC + dw ItemUseSuperRepel ; SUPER_REPL + dw ItemUseMaxRepel ; MAX_REPEL + dw ItemUseDireHit ; DIRE_HIT + dw UnusableItem ; COIN + dw ItemUseMedicine ; FRESH_WATER + dw ItemUseMedicine ; SODA_POP + dw ItemUseMedicine ; LEMONADE + dw UnusableItem ; S_S_TICKET + dw UnusableItem ; GOLD_TEETH + dw ItemUseXStat ; X_ATTACK + dw ItemUseXStat ; X_DEFEND + dw ItemUseXStat ; X_SPEED + dw ItemUseXStat ; X_SPECIAL + dw ItemUseCoinCase ; COIN_CASE + dw ItemUseOaksParcel ; OAKS_PARCEL + dw ItemUseItemfinder ; ITEMFINDER + dw UnusableItem ; SILPH_SCOPE + dw ItemUsePokeflute ; POKE_FLUTE + dw UnusableItem ; LIFT_KEY + dw UnusableItem ; EXP_ALL + dw ItemUseOldRod ; OLD_ROD + dw ItemUseGoodRod ; GOOD_ROD + dw ItemUseSuperRod ; SUPER_ROD + dw ItemUsePPUp ; PP_UP (real one) + dw ItemUsePPRestore ; ETHER + dw ItemUsePPRestore ; MAX_ETHER + dw ItemUsePPRestore ; ELIXER + dw ItemUsePPRestore ; MAX_ELIXER + +ItemUseBall: + +; Balls can't be used out of battle. + ld a, [wIsInBattle] + and a + jp z, ItemUseNotTime + +; Balls can't catch trainers' Pokémon. + dec a + jp nz, ThrowBallAtTrainerMon + +; If this is for the old man battle, skip checking if the party & box are full. + ld a, [wBattleType] + dec a + jr z, .canUseBall + + ld a, [wPartyCount] ; is party full? + cp PARTY_LENGTH + jr nz, .canUseBall + ld a, [wNumInBox] ; is box full? + cp MONS_PER_BOX + jp z, BoxFullCannotThrowBall + +.canUseBall + xor a + ld [wCapturedMonSpecies], a + + ld a, [wBattleType] + cp BATTLE_TYPE_SAFARI + jr nz, .skipSafariZoneCode + +.safariZone + ld hl, wNumSafariBalls + dec [hl] ; remove a Safari Ball + +.skipSafariZoneCode + call RunDefaultPaletteCommand + + ld a, $43 ; successful capture value + ld [wPokeBallAnimData], a + + call LoadScreenTilesFromBuffer1 + ld hl, ItemUseText00 + call PrintText + +; If the player is fighting an unidentified ghost, set the value that indicates +; the Pokémon can't be caught and skip the capture calculations. + callab IsGhostBattle + ld b, $10 ; can't be caught value + jp z, .setAnimData + + ld a, [wBattleType] + dec a + jr nz, .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) + 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. + ld a, [wCurMap] + cp POKEMON_TOWER_6F + jr nz, .loop + ld a, [wEnemyMonSpecies2] + cp MAROWAK + ld b, $10 ; can't be caught value + jp z, .setAnimData + +; Get the first random number. Let it be called Rand1. +; Rand1 must be within a certain range according the kind of ball being thrown. +; The ranges are as follows. +; Poké Ball: [0, 255] +; Great Ball: [0, 200] +; Ultra/Safari Ball: [0, 150] +; Loop until an acceptable number is found. + +.loop + call Random + ld b, a + +; Get the item ID. + ld hl, wcf91 + ld a, [hl] + +; The Master Ball always succeeds. + cp MASTER_BALL + jp z, .captured + +; Anything will do for the basic Poké Ball. + cp POKE_BALL + jr z, .checkForAilments + +; If it's a Great/Ultra/Safari Ball and Rand1 is greater than 200, try again. + ld a, 200 + cp b + jr c, .loop + +; Less than or equal to 200 is good enough for a Great Ball. + ld a, [hl] + cp GREAT_BALL + jr z, .checkForAilments + +; If it's an Ultra/Safari Ball and Rand1 is greater than 150, try again. + ld a, 150 + cp b + jr c, .loop + +.checkForAilments +; Pokémon can be caught more easily with a status ailment. +; Depending on the status ailment, a certain value will be subtracted from +; Rand1. Let this value be called Status. +; The larger Status is, the more easily the Pokémon can be caught. +; no status ailment: Status = 0 +; Burn/Paralysis/Poison: Status = 12 +; Freeze/Sleep: Status = 25 +; If Status is greater than Rand1, the Pokémon will be caught for sure. + ld a, [wEnemyMonStatus] + and a + jr z, .skipAilmentValueSubtraction ; no ailments + and 1 << FRZ | SLP + ld c, 12 + jr z, .notFrozenOrAsleep + ld c, 25 +.notFrozenOrAsleep + ld a, b + sub c + jp c, .captured + ld b, a + +.skipAilmentValueSubtraction + push bc ; save (Rand1 - Status) + +; Calculate MaxHP * 255. + xor a + ld [H_MULTIPLICAND], a + ld hl, wEnemyMonMaxHP + ld a, [hli] + ld [H_MULTIPLICAND + 1], a + ld a, [hl] + ld [H_MULTIPLICAND + 2], a + ld a, 255 + ld [H_MULTIPLIER], a + call Multiply + +; Determine BallFactor. It's 8 for Great Balls and 12 for the others. + ld a, [wcf91] + cp GREAT_BALL + ld a, 12 + jr nz, .skip1 + ld a, 8 + +.skip1 +; Note that the results of all division operations are floored. + +; Calculate (MaxHP * 255) / BallFactor. + ld [H_DIVISOR], a + ld b, 4 ; number of bytes in dividend + call Divide + +; Divide the enemy's current HP by 4. HP is not supposed to exceed 999 so +; the result should fit in a. If the division results in a quotient of 0, +; change it to 1. + ld hl, wEnemyMonHP + ld a, [hli] + ld b, a + ld a, [hl] + srl b + rr a + srl b + rr a + and a + jr nz, .skip2 + inc a + +.skip2 +; Let W = ((MaxHP * 255) / BallFactor) / max(HP / 4, 1). Calculate W. + ld [H_DIVISOR], a + ld b, 4 + call Divide + +; If W > 255, store 255 in [H_QUOTIENT + 3]. +; Let X = min(W, 255) = [H_QUOTIENT + 3]. + ld a, [H_QUOTIENT + 2] + and a + jr z, .skip3 + ld a, 255 + ld [H_QUOTIENT + 3], a + +.skip3 + pop bc ; b = Rand1 - Status + +; If Rand1 - Status > CatchRate, the ball fails to capture the Pokémon. + ld a, [wEnemyMonActualCatchRate] + cp b + jr c, .failedToCapture + +; If W > 255, the ball captures the Pokémon. + ld a, [H_QUOTIENT + 2] + and a + jr nz, .captured + + call Random ; Let this random number be called Rand2. + +; If Rand2 > X, the ball fails to capture the Pokémon. + ld b, a + ld a, [H_QUOTIENT + 3] + cp b + jr c, .failedToCapture + +.captured + jr .skipShakeCalculations + +.failedToCapture + ld a, [H_QUOTIENT + 3] + ld [wPokeBallCaptureCalcTemp], a ; Save X. + +; Calculate CatchRate * 100. + xor a + ld [H_MULTIPLICAND], a + ld [H_MULTIPLICAND + 1], a + ld a, [wEnemyMonActualCatchRate] + ld [H_MULTIPLICAND + 2], a + ld a, 100 + ld [H_MULTIPLIER], a + call Multiply + +; Determine BallFactor2. +; Poké Ball: BallFactor2 = 255 +; Great Ball: BallFactor2 = 200 +; Ultra/Safari Ball: BallFactor2 = 150 + ld a, [wcf91] + ld b, 255 + cp POKE_BALL + jr z, .skip4 + ld b, 200 + cp GREAT_BALL + jr z, .skip4 + ld b, 150 + cp ULTRA_BALL + jr z, .skip4 + +.skip4 +; Let Y = (CatchRate * 100) / BallFactor2. Calculate Y. + ld a, b + ld [H_DIVISOR], a + ld b, 4 + call Divide + +; If Y > 255, there are 3 shakes. +; Note that this shouldn't be possible. +; The maximum value of Y is (255 * 100) / 150 = 170. + ld a, [H_QUOTIENT + 2] + and a + ld b, $63 ; 3 shakes + jr nz, .setAnimData + +; Calculate X * Y. + ld a, [wPokeBallCaptureCalcTemp] + ld [H_MULTIPLIER], a + call Multiply + +; Calculate (X * Y) / 255. + ld a, 255 + ld [H_DIVISOR], a + ld b, 4 + call Divide + +; Determine Status2. +; no status ailment: Status2 = 0 +; Burn/Paralysis/Poison: Status2 = 5 +; Freeze/Sleep: Status2 = 10 + ld a, [wEnemyMonStatus] + and a + jr z, .skip5 + and 1 << FRZ | SLP + ld b, 5 + jr z, .addAilmentValue + ld b, 10 + +.addAilmentValue +; If the Pokémon has a status ailment, add Status2. + ld a, [H_QUOTIENT + 3] + add b + ld [H_QUOTIENT + 3], a + +.skip5 +; Finally determine the number of shakes. +; Let Z = ((X * Y) / 255) + Status2 = [H_QUOTIENT + 3]. +; The number of shakes depend on the range Z is in. +; 0 ≤ Z < 10: 0 shakes (the ball misses) +; 10 ≤ Z < 30: 1 shake +; 30 ≤ Z < 70: 2 shakes +; 70 ≤ Z: 3 shakes + ld a, [H_QUOTIENT + 3] + cp 10 + ld b, $20 + jr c, .setAnimData + cp 30 + ld b, $61 + jr c, .setAnimData + cp 70 + ld b, $62 + jr c, .setAnimData + ld b, $63 + +.setAnimData + ld a, b + ld [wPokeBallAnimData], a + +.skipShakeCalculations + ld c, 20 + call DelayFrames + +; Do the animation. + ld a, TOSS_ANIM + ld [wAnimationID], a + xor a + ld [H_WHOSETURN], a + ld [wAnimationType], a + ld [wDamageMultipliers], a + ld a, [wWhichPokemon] + push af + ld a, [wcf91] + push af + predef MoveAnimation + pop af + ld [wcf91], a + pop af + ld [wWhichPokemon], a + +; Determine the message to display from the animation. + ld a, [wPokeBallAnimData] + cp $10 + ld hl, ItemUseBallText00 + jp z, .printMessage + cp $20 + ld hl, ItemUseBallText01 + jp z, .printMessage + cp $61 + ld hl, ItemUseBallText02 + jp z, .printMessage + cp $62 + ld hl, ItemUseBallText03 + jp z, .printMessage + cp $63 + ld hl, ItemUseBallText04 + jp z, .printMessage + +; Save current HP. + ld hl, wEnemyMonHP + ld a, [hli] + push af + ld a, [hli] + push af + +; Save status ailment. + inc hl + ld a, [hl] + push af + + push hl + +; If the Pokémon is transformed, the Pokémon is assumed to be a Ditto. +; This is a bug because a wild Pokémon could have used Transform via +; Mirror Move even though the only wild Pokémon that knows Transform is Ditto. + ld hl, wEnemyBattleStatus3 + bit TRANSFORMED, [hl] + jr z, .notTransformed + ld a, DITTO + ld [wEnemyMonSpecies2], a + jr .skip6 + +.notTransformed +; If the Pokémon is not transformed, set the transformed bit and copy the +; DVs to wTransformedEnemyMonOriginalDVs so that LoadEnemyMonData won't generate +; new DVs. + set TRANSFORMED, [hl] + ld hl, wTransformedEnemyMonOriginalDVs + ld a, [wEnemyMonDVs] + ld [hli], a + ld a, [wEnemyMonDVs + 1] + ld [hl], a + +.skip6 + ld a, [wcf91] + push af + ld a, [wEnemyMonSpecies2] + ld [wcf91], a + ld a, [wEnemyMonLevel] + ld [wCurEnemyLVL], a + callab LoadEnemyMonData + pop af + ld [wcf91], a + pop hl + pop af + ld [hld], a + dec hl + pop af + ld [hld], a + pop af + ld [hl], a + ld a, [wEnemyMonSpecies] + ld [wCapturedMonSpecies], a + 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 + + ld hl, ItemUseBallText05 + call PrintText + +; Add the caught Pokémon to the Pokédex. + predef IndexToPokedex + ld a, [wd11e] + dec a + ld c, a + ld b, FLAG_TEST + ld hl, wPokedexOwned + predef FlagActionPredef + ld a, c + push af + ld a, [wd11e] + dec a + ld c, a + ld b, FLAG_SET + predef FlagActionPredef + pop af + + and a ; was the Pokémon already in the Pokédex? + jr nz, .skipShowingPokedexData ; if so, don't show the Pokédex data + + ld hl, ItemUseBallText06 + call PrintText + call ClearSprites + ld a, [wEnemyMonSpecies] + ld [wd11e], a + predef ShowPokedexData + +.skipShowingPokedexData + ld a, [wPartyCount] + cp PARTY_LENGTH ; is party full? + jr z, .sendToBox + xor a ; PLAYER_PARTY_DATA + ld [wMonDataLocation], a + call ClearSprites + call AddPartyMon + jr .done + +.sendToBox + call ClearSprites + call SendNewMonToBox + ld hl, ItemUseBallText07 + CheckEvent EVENT_MET_BILL + jr nz, .printTransferredToPCText + ld hl, ItemUseBallText08 +.printTransferredToPCText + call PrintText + jr .done + +.oldManCaughtMon + ld hl, ItemUseBallText05 + +.printMessage + call PrintText + call ClearSprites + +.done + ld a, [wBattleType] + and a ; is this the old man battle? + ret nz ; if so, don't remove a ball from the bag + +; Remove a ball from the bag. + ld hl, wNumBagItems + inc a + ld [wItemQuantity], a + jp RemoveItemFromInventory + +ItemUseBallText00: +;"It dodged the thrown ball!" +;"This pokemon can't be caught" + TX_FAR _ItemUseBallText00 + db "@" +ItemUseBallText01: +;"You missed the pokemon!" + TX_FAR _ItemUseBallText01 + db "@" +ItemUseBallText02: +;"Darn! The pokemon broke free!" + TX_FAR _ItemUseBallText02 + db "@" +ItemUseBallText03: +;"Aww! It appeared to be caught!" + TX_FAR _ItemUseBallText03 + db "@" +ItemUseBallText04: +;"Shoot! It was so close too!" + TX_FAR _ItemUseBallText04 + db "@" +ItemUseBallText05: +;"All right! {MonName} was caught!" +;play sound + TX_FAR _ItemUseBallText05 + TX_SFX_CAUGHT_MON + TX_BLINK + db "@" +ItemUseBallText07: +;"X was transferred to Bill's PC" + TX_FAR _ItemUseBallText07 + db "@" +ItemUseBallText08: +;"X was transferred to someone's PC" + TX_FAR _ItemUseBallText08 + db "@" + +ItemUseBallText06: +;"New DEX data will be added..." +;play sound + TX_FAR _ItemUseBallText06 + TX_SFX_DEX_PAGE_ADDED + TX_BLINK + db "@" + +ItemUseTownMap: + ld a, [wIsInBattle] + and a + jp nz, ItemUseNotTime + jpba DisplayTownMap + +ItemUseBicycle: + ld a, [wIsInBattle] + and a + jp nz, ItemUseNotTime + ld a, [wWalkBikeSurfState] + ld [wWalkBikeSurfStateCopy], a + cp 2 ; is the player surfing? + jp z, ItemUseNotTime + dec a ; is player already bicycling? + jr nz, .tryToGetOnBike +.getOffBike + call ItemUseReloadOverworldData + xor a + ld [wWalkBikeSurfState], a ; change player state to walking + call PlayDefaultMusic ; play walking music + ld hl, GotOffBicycleText + jr .printText +.tryToGetOnBike + call IsBikeRidingAllowed + jp nc, NoCyclingAllowedHere + call ItemUseReloadOverworldData + xor a ; no keys pressed + ld [hJoyHeld], a ; current joypad state + inc a + ld [wWalkBikeSurfState], a ; change player state to bicycling + ld hl, GotOnBicycleText + call PlayDefaultMusic ; play bike riding music +.printText + jp PrintText + +; used for Surf out-of-battle effect +ItemUseSurfboard: + ld a, [wWalkBikeSurfState] + ld [wWalkBikeSurfStateCopy], a + cp 2 ; is the player already surfing? + jr z, .tryToStopSurfing +.tryToSurf + call IsNextTileShoreOrWater + jp c, SurfingAttemptFailed + ld hl, TilePairCollisionsWater + call CheckForTilePairCollisions + jp c, SurfingAttemptFailed +.surf + call .makePlayerMoveForward + ld hl, wd730 + set 7, [hl] + ld a, 2 + ld [wWalkBikeSurfState], a ; change player state to surfing + call PlayDefaultMusic ; play surfing music + ld hl, SurfingGotOnText + jp PrintText +.tryToStopSurfing + xor a + ld [hSpriteIndexOrTextID], a + ld d, 16 ; talking range in pixels (normal range) + call IsSpriteInFrontOfPlayer2 + res 7, [hl] + ld a, [hSpriteIndexOrTextID] + and a ; is there a sprite in the way? + jr nz, .cannotStopSurfing + 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 +.cannotStopSurfing + ld hl, SurfingNoPlaceToGetOffText + jp PrintText +.stopSurfing + call .makePlayerMoveForward + ld hl, wd730 + set 7, [hl] + xor a + ld [wWalkBikeSurfState], a ; change player state to walking + dec a + ld [wJoyIgnore], a + call PlayDefaultMusic ; play walking music + jp LoadWalkingPlayerSpriteGraphics +; uses a simulated button press to make the player move forward +.makePlayerMoveForward + ld a, [wPlayerDirection] ; direction the player is going + bit PLAYER_DIR_BIT_UP, a + ld b, D_UP + jr nz, .storeSimulatedButtonPress + bit PLAYER_DIR_BIT_DOWN, a + ld b, D_DOWN + jr nz, .storeSimulatedButtonPress + bit PLAYER_DIR_BIT_LEFT, a + ld b, D_LEFT + jr nz, .storeSimulatedButtonPress + ld b, D_RIGHT +.storeSimulatedButtonPress + ld a, b + ld [wSimulatedJoypadStatesEnd], a + xor a + ld [wWastedByteCD39], a + inc a + ld [wSimulatedJoypadStatesIndex], a + ret + +SurfingGotOnText: + TX_FAR _SurfingGotOnText + db "@" + +SurfingNoPlaceToGetOffText: + TX_FAR _SurfingNoPlaceToGetOffText + db "@" + +ItemUsePokedex: + predef_jump ShowPokedexMenu + +ItemUseEvoStone: + ld a, [wIsInBattle] + and a + jp nz, ItemUseNotTime + ld a, [wWhichPokemon] + push af + ld a, [wcf91] + ld [wEvoStoneItemID], a + push af + ld a, EVO_STONE_PARTY_MENU + ld [wPartyMenuTypeOrMessageID], a + ld a, $ff + ld [wUpdateSpritesEnabled], a + call DisplayPartyMenu + pop bc + jr c, .canceledItemUse + ld a, b + ld [wcf91], a + ld a, $01 + ld [wForceEvolution], a + ld a, SFX_HEAL_AILMENT + call PlaySoundWaitForCurrent + call WaitForSoundToFinish + callab TryEvolvingMon ; try to evolve pokemon + ld a, [wEvolutionOccurred] + and a + jr z, .noEffect + pop af + ld [wWhichPokemon], a + ld hl, wNumBagItems + ld a, 1 ; remove 1 stone + ld [wItemQuantity], a + jp RemoveItemFromInventory +.noEffect + call ItemUseNoEffect +.canceledItemUse + xor a + ld [wActionResultOrTookBattleTurn], a ; item not used + pop af + ret + +ItemUseVitamin: + ld a, [wIsInBattle] + and a + jp nz, ItemUseNotTime + +ItemUseMedicine: + ld a, [wPartyCount] + and a + jp z, .emptyParty + ld a, [wWhichPokemon] + push af + ld a, [wcf91] + push af + ld a, USE_ITEM_PARTY_MENU + ld [wPartyMenuTypeOrMessageID], a + ld a, $ff + ld [wUpdateSpritesEnabled], a + ld a, [wPseudoItemID] + and a ; using Softboiled? + jr z, .notUsingSoftboiled +; 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 + jp c, .canceledItemUse + ld hl, wPartyMons + ld bc, wPartyMon2 - wPartyMon1 + ld a, [wWhichPokemon] + call AddNTimes + ld a, [wWhichPokemon] + ld [wUsedItemOnWhichPokemon], a + ld d, a + ld a, [wcf91] + ld e, a + ld [wd0b5], a + pop af + ld [wcf91], a + pop af + ld [wWhichPokemon], a + ld a, [wPseudoItemID] + and a ; using Softboiled? + jr z, .checkItemType +; if using softboiled + ld a, [wWhichPokemon] + cp d ; is the pokemon trying to use softboiled on itself? + jr z, ItemUseMedicine ; if so, force another choice +.checkItemType + ld a, [wcf91] + cp REVIVE + jr nc, .healHP ; if it's a Revive or Max Revive + cp FULL_HEAL + jr z, .cureStatusAilment ; if it's a Full Heal + cp HP_UP + jp nc, .useVitamin ; if it's a vitamin or Rare Candy + cp FULL_RESTORE + jr nc, .healHP ; if it's a Full Restore or one of the potions +; fall through if it's one of the status-specific healing items +.cureStatusAilment + ld bc, wPartyMon1Status - wPartyMon1 + add hl, bc ; hl now points to status + ld a, [wcf91] + lb bc, ANTIDOTE_MSG, 1 << PSN + cp ANTIDOTE + jr z, .checkMonStatus + lb bc, BURN_HEAL_MSG, 1 << BRN + cp BURN_HEAL + jr z, .checkMonStatus + lb bc, ICE_HEAL_MSG, 1 << FRZ + cp ICE_HEAL + jr z, .checkMonStatus + lb bc, AWAKENING_MSG, SLP + cp AWAKENING + jr z, .checkMonStatus + lb bc, PARALYZ_HEAL_MSG, 1 << PAR + cp PARLYZ_HEAL + jr z, .checkMonStatus + lb bc, FULL_HEAL_MSG, $ff ; Full Heal +.checkMonStatus + ld a, [hl] ; pokemon's status + and c ; does the pokemon have a status ailment the item can cure? + jp z, .healingItemNoEffect +; if the pokemon has a status the item can heal + xor a + ld [hl], a ; remove the status ailment in the party data + ld a, b + ld [wPartyMenuTypeOrMessageID], a ; the message to display for the item used + ld a, [wPlayerMonNumber] + cp d ; is pokemon the item was used on active in battle? + jp nz, .doneHealing +; if it is active in battle + xor a + ld [wBattleMonStatus], a ; remove the status ailment in the in-battle pokemon data + push hl + ld hl, wPlayerBattleStatus3 + res BADLY_POISONED, [hl] ; heal Toxic status + pop hl + ld bc, wPartyMon1Stats - wPartyMon1Status + add hl, bc ; hl now points to party stats + ld de, wBattleMonStats + ld bc, NUM_STATS * 2 + 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] + ld b, a + ld [wHPBarOldHP+1], a + ld a, [hl] + ld c, a + ld [wHPBarOldHP], a ; current HP stored at wHPBarOldHP (2 bytes, big-endian) + or b + jr nz, .notFainted +.fainted + ld a, [wcf91] + cp REVIVE + jr z, .updateInBattleFaintedData + cp MAX_REVIVE + jr z, .updateInBattleFaintedData + jp .healingItemNoEffect +.updateInBattleFaintedData + ld a, [wIsInBattle] + and a + jr z, .compareCurrentHPToMaxHP + push hl + push de + push bc + ld a, [wUsedItemOnWhichPokemon] + ld c, a + ld hl, wPartyFoughtCurrentEnemyFlags + ld b, FLAG_TEST + predef FlagActionPredef + ld a, c + and a + jr z, .next + ld a, [wUsedItemOnWhichPokemon] + ld c, a + ld hl, wPartyGainExpFlags + ld b, FLAG_SET + predef FlagActionPredef +.next + pop bc + pop de + pop hl + jr .compareCurrentHPToMaxHP +.notFainted + ld a, [wcf91] + cp REVIVE + jp z, .healingItemNoEffect + cp MAX_REVIVE + jp z, .healingItemNoEffect +.compareCurrentHPToMaxHP + push hl + push bc + ld bc, wPartyMon1MaxHP - (wPartyMon1HP + 1) + add hl, bc ; hl now points to max HP + pop bc + ld a, [hli] + cp b + jr nz, .skipComparingLSB ; no need to compare the LSB's if the MSB's don't match + ld a, [hl] + cp c +.skipComparingLSB + pop hl + jr nz, .notFullHP +.fullHP ; if the pokemon's current HP equals its max HP + ld a, [wcf91] + cp FULL_RESTORE + jp nz, .healingItemNoEffect + inc hl + inc hl + ld a, [hld] ; status ailment + and a ; does the pokemon have a status ailment? + jp z, .healingItemNoEffect + ld a, FULL_HEAL + ld [wcf91], a + dec hl + 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 + ld [wChannelSoundIDs + Ch5], a + push hl + push de + ld bc, wPartyMon1MaxHP - (wPartyMon1HP + 1) + add hl, bc ; hl now points to max HP + ld a, [hli] + ld [wHPBarMaxHP+1], a + ld a, [hl] + ld [wHPBarMaxHP], a ; max HP stored at wHPBarMaxHP (2 bytes, big-endian) + ld a, [wPseudoItemID] + and a ; using Softboiled? + jp z, .notUsingSoftboiled2 +; if using softboiled + ld hl, wHPBarMaxHP + ld a, [hli] + push af + ld a, [hli] + push af + ld a, [hli] + push af + ld a, [hl] + push af + ld hl, wPartyMon1MaxHP + ld a, [wWhichPokemon] + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld a, [hli] + ld [wHPBarMaxHP + 1], a + ld [H_DIVIDEND], a + ld a, [hl] + ld [wHPBarMaxHP], a + ld [H_DIVIDEND + 1], a + ld a, 5 + ld [H_DIVISOR], a + ld b, 2 ; number of bytes + call Divide ; get 1/5 of max HP of pokemon that used Softboiled + ld bc, (wPartyMon1HP + 1) - (wPartyMon1MaxHP + 1) + add hl, bc ; hl now points to LSB of current HP of pokemon that used Softboiled +; subtract 1/5 of max HP from current HP of pokemon that used Softboiled + ld a, [H_QUOTIENT + 3] + push af + ld b, a + ld a, [hl] + ld [wHPBarOldHP], a + sub b + ld [hld], a + ld [wHPBarNewHP], a + ld a, [H_QUOTIENT + 2] + ld b, a + ld a, [hl] + ld [wHPBarOldHP+1], a + sbc b + ld [hl], a + ld [wHPBarNewHP+1], a + coord hl, 4, 1 + ld a, [wWhichPokemon] + ld bc, 2 * SCREEN_WIDTH + call AddNTimes ; calculate coordinates of HP bar of pokemon that used Softboiled + ld a, SFX_HEAL_HP + call PlaySoundWaitForCurrent + ld a, [hFlags_0xFFF6] + set 0, a + ld [hFlags_0xFFF6], a + ld a, $02 + ld [wHPBarType], a + predef UpdateHPBar2 ; animate HP bar decrease of pokemon that used Softboiled + ld a, [hFlags_0xFFF6] + res 0, a + ld [hFlags_0xFFF6], a + pop af + ld b, a ; store heal amount (1/5 of max HP) + ld hl, wHPBarOldHP + 1 + pop af + ld [hld], a + pop af + ld [hld], a + pop af + ld [hld], a + pop af + ld [hl], a + jr .addHealAmount +.notUsingSoftboiled2 + ld a, [wcf91] + cp SODA_POP + ld b, 60 ; Soda Pop heal amount + jr z, .addHealAmount + ld b, 80 ; Lemonade heal amount + jr nc, .addHealAmount + cp FRESH_WATER + ld b, 50 ; Fresh Water heal amount + jr z, .addHealAmount + cp SUPER_POTION + ld b, 200 ; Hyper Potion heal amount + jr c, .addHealAmount + ld b, 50 ; Super Potion heal amount + jr z, .addHealAmount + ld b, 20 ; Potion heal amount +.addHealAmount + pop de + pop hl + ld a, [hl] + add b + ld [hld], a + ld [wHPBarNewHP], a + ld a, [hl] + ld [wHPBarNewHP+1], a + jr nc, .noCarry + inc [hl] + ld a, [hl] + ld [wHPBarNewHP + 1], a +.noCarry + push de + inc hl + ld d, h + ld e, l ; de now points to current HP + ld hl, (wPartyMon1MaxHP + 1) - (wPartyMon1HP + 1) + add hl, de ; hl now points to max HP + ld a, [wcf91] + cp REVIVE + jr z, .setCurrentHPToHalfMaxHP + ld a, [hld] + ld b, a + ld a, [de] + sub b + dec de + ld b, [hl] + ld a, [de] + sbc b + jr nc, .setCurrentHPToMaxHp ; if current HP exceeds max HP after healing + ld a, [wcf91] + cp HYPER_POTION + jr c, .setCurrentHPToMaxHp ; if using a Full Restore or Max Potion + cp MAX_REVIVE + jr z, .setCurrentHPToMaxHp ; if using a Max Revive + jr .updateInBattleData +.setCurrentHPToHalfMaxHP + dec hl + dec de + ld a, [hli] + srl a + ld [de], a + ld [wHPBarNewHP+1], a + ld a, [hl] + rr a + inc de + ld [de], a + ld [wHPBarNewHP], a + dec de + jr .doneHealingPartyHP +.setCurrentHPToMaxHp + ld a, [hli] + ld [de], a + ld [wHPBarNewHP+1], a + inc de + ld a, [hl] + ld [de], a + ld [wHPBarNewHP], a + dec de +.doneHealingPartyHP ; done updating the pokemon's current HP in the party data structure + ld a, [wcf91] + cp FULL_RESTORE + jr nz, .updateInBattleData + ld bc, wPartyMon1Status - (wPartyMon1MaxHP + 1) + add hl, bc + xor a + ld [hl], a ; remove the status ailment in the party data +.updateInBattleData + ld h, d + ld l, e + pop de + ld a, [wPlayerMonNumber] + cp d ; is pokemon the item was used on active in battle? + jr nz, .calculateHPBarCoords +; copy party HP to in-battle HP + ld a, [hli] + ld [wBattleMonHP], a + ld a, [hld] + ld [wBattleMonHP + 1], a + ld a, [wcf91] + cp FULL_RESTORE + jr nz, .calculateHPBarCoords + xor a + ld [wBattleMonStatus], a ; remove the status ailment in the in-battle pokemon data +.calculateHPBarCoords + ld hl, wOAMBuffer + $90 + ld bc, 2 * SCREEN_WIDTH + inc d +.calculateHPBarCoordsLoop + add hl, bc + dec d + jr nz, .calculateHPBarCoordsLoop + jr .doneHealing +.healingItemNoEffect + call ItemUseNoEffect + jp .done +.doneHealing + ld a, [wPseudoItemID] + and a ; using Softboiled? + jr nz, .skipRemovingItem ; no item to remove if using Softboiled + push hl + call RemoveUsedItem + pop hl +.skipRemovingItem + ld a, [wcf91] + cp FULL_RESTORE + jr c, .playStatusAilmentCuringSound + cp FULL_HEAL + jr z, .playStatusAilmentCuringSound + ld a, SFX_HEAL_HP + call PlaySoundWaitForCurrent + ld a, [hFlags_0xFFF6] + set 0, a + ld [hFlags_0xFFF6], a + ld a, $02 + ld [wHPBarType], a + predef UpdateHPBar2 ; animate the HP bar lengthening + ld a, [hFlags_0xFFF6] + res 0, a + ld [hFlags_0xFFF6], a + ld a, REVIVE_MSG + ld [wPartyMenuTypeOrMessageID], a + ld a, [wcf91] + cp REVIVE + jr z, .showHealingItemMessage + cp MAX_REVIVE + jr z, .showHealingItemMessage + ld a, POTION_MSG + ld [wPartyMenuTypeOrMessageID], a + jr .showHealingItemMessage +.playStatusAilmentCuringSound + ld a, SFX_HEAL_AILMENT + call PlaySoundWaitForCurrent +.showHealingItemMessage + xor a + ld [H_AUTOBGTRANSFERENABLED], a + call ClearScreen + dec a + ld [wUpdateSpritesEnabled], a + call RedrawPartyMenu ; redraws the party menu and displays the message + ld a, 1 + ld [H_AUTOBGTRANSFERENABLED], a + ld c, 50 + call DelayFrames + call WaitForTextScrollButtonPress + jr .done +.canceledItemUse + xor a + ld [wActionResultOrTookBattleTurn], a ; item use failed + pop af + pop af +.done + ld a, [wPseudoItemID] + and a ; using Softboiled? + ret nz ; if so, return + call GBPalWhiteOut + call z, RunDefaultPaletteCommand + ld a, [wIsInBattle] + and a + ret nz + jp ReloadMapData +.useVitamin + push hl + ld a, [hl] + ld [wd0b5], a + ld [wd11e], a + ld bc, wPartyMon1Level - wPartyMon1 + add hl, bc ; hl now points to level + ld a, [hl] ; a = level + ld [wCurEnemyLVL], a ; store level + call GetMonHeader + push de + ld a, d + ld hl, wPartyMonNicks + call GetPartyMonName + pop de + pop hl + ld a, [wcf91] + cp RARE_CANDY + jp z, .useRareCandy + push hl + sub HP_UP + add a + ld bc, wPartyMon1HPExp - wPartyMon1 + add hl, bc + add l + ld l, a + jr nc, .noCarry2 + inc h +.noCarry2 + ld a, 10 + ld b, a + ld a, [hl] ; a = MSB of stat experience of the appropriate stat + cp 100 ; is there already at least 25600 (256 * 100) stat experience? + jr nc, .vitaminNoEffect ; if so, vitamins can't add any more + add b ; add 2560 (256 * 10) stat experience + jr nc, .noCarry3 ; a carry should be impossible here, so this will always jump + ld a, 255 +.noCarry3 + ld [hl], a + pop hl + call .recalculateStats + ld hl, VitaminText + ld a, [wcf91] + sub HP_UP - 1 + ld c, a +.statNameLoop ; loop to get the address of the name of the stat the vitamin increases + dec c + jr z, .gotStatName +.statNameInnerLoop + ld a, [hli] + ld b, a + ld a, $50 + cp b + jr nz, .statNameInnerLoop + jr .statNameLoop +.gotStatName + ld de, wcf4b + ld bc, 10 + call CopyData ; copy the stat's name to wcf4b + ld a, SFX_HEAL_AILMENT + call PlaySound + 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 + ld d, h + ld e, l ; de now points to stats + ld bc, (wPartyMon1Exp + 2) - wPartyMon1Stats + add hl, bc ; hl now points to LSB of experience + ld b, 1 + jp CalcStats ; recalculate stats +.useRareCandy + push hl + ld bc, wPartyMon1Level - wPartyMon1 + add hl, bc ; hl now points to level + ld a, [hl] ; a = level + cp MAX_LEVEL + jr z, .vitaminNoEffect ; can't raise level above 100 + inc a + ld [hl], a ; store incremented level + ld [wCurEnemyLVL], a + push hl + push de + ld d, a + callab CalcExperience ; calculate experience for next level and store it at $ff96 + pop de + pop hl + ld bc, wPartyMon1Exp - wPartyMon1Level + add hl, bc ; hl now points to MSB of experience +; update experience to minimum for new level + ld a, [hExperience] + ld [hli], a + ld a, [hExperience + 1] + ld [hli], a + ld a, [hExperience + 2] + ld [hl], a + pop hl + ld a, [wWhichPokemon] + push af + ld a, [wcf91] + push af + push de + push hl + ld bc, wPartyMon1MaxHP - wPartyMon1 + add hl, bc ; hl now points to MSB of max HP + ld a, [hli] + ld b, a + ld c, [hl] + pop hl + push bc + push hl + call .recalculateStats + pop hl + ld bc, (wPartyMon1MaxHP + 1) - wPartyMon1 + add hl, bc ; hl now points to LSB of max HP + pop bc + ld a, [hld] + sub c + ld c, a + ld a, [hl] + sbc b + ld b, a ; bc = the amount of max HP gained from leveling up +; add the amount gained to the current HP + ld de, (wPartyMon1HP + 1) - wPartyMon1MaxHP + add hl, de ; hl now points to LSB of current HP + ld a, [hl] + add c + ld [hld], a + ld a, [hl] + adc b + ld [hl], a + ld a, RARE_CANDY_MSG + ld [wPartyMenuTypeOrMessageID], a + call RedrawPartyMenu + pop de + ld a, d + ld [wWhichPokemon], a + ld a, e + ld [wd11e], a + xor a ; PLAYER_PARTY_DATA + ld [wMonDataLocation], a + call LoadMonData + ld d, $01 + callab PrintStatsBox ; display new stats text box + call WaitForTextScrollButtonPress ; wait for button press + xor a ; PLAYER_PARTY_DATA + ld [wMonDataLocation], a + predef LearnMoveFromLevelUp ; learn level up move, if any + xor a + ld [wForceEvolution], a + callab TryEvolvingMon ; evolve pokemon, if appropriate + ld a, $01 + ld [wUpdateSpritesEnabled], a + pop af + ld [wcf91], a + pop af + ld [wWhichPokemon], a + jp RemoveUsedItem + +VitaminStatRoseText: + TX_FAR _VitaminStatRoseText + db "@" + +VitaminNoEffectText: + TX_FAR _VitaminNoEffectText + db "@" + +VitaminText: + db "HEALTH@" + db "ATTACK@" + db "DEFENSE@" + db "SPEED@" + db "SPECIAL@" + +ItemUseBait: + ld hl, ThrewBaitText + call PrintText + ld hl, wEnemyMonActualCatchRate ; catch rate + srl [hl] ; halve catch rate + ld a, BAIT_ANIM + ld hl, wSafariBaitFactor ; bait factor + ld de, wSafariEscapeFactor ; escape factor + jr BaitRockCommon + +ItemUseRock: + ld hl, ThrewRockText + call PrintText + ld hl, wEnemyMonActualCatchRate ; catch rate + ld a, [hl] + add a ; double catch rate + jr nc, .noCarry + ld a, $ff +.noCarry + ld [hl], a + ld a, ROCK_ANIM + ld hl, wSafariEscapeFactor ; escape factor + ld de, wSafariBaitFactor ; bait factor + +BaitRockCommon: + ld [wAnimationID], a + xor a + ld [wAnimationType], a + ld [H_WHOSETURN], a + ld [de], a ; zero escape factor (for bait), zero bait factor (for rock) +.randomLoop ; loop until a random number less than 5 is generated + call Random + and 7 + cp 5 + jr nc, .randomLoop + inc a ; increment the random number, giving a range from 1 to 5 inclusive + ld b, a + ld a, [hl] + add b ; increase bait factor (for bait), increase escape factor (for rock) + jr nc, .noCarry + ld a, $ff +.noCarry + ld [hl], a + predef MoveAnimation ; do animation + ld c, 70 + jp DelayFrames + +ThrewBaitText: + TX_FAR _ThrewBaitText + db "@" + +ThrewRockText: + TX_FAR _ThrewRockText + db "@" + +; also used for Dig out-of-battle effect +ItemUseEscapeRope: + ld a, [wIsInBattle] + and a + jr nz, .notUsable + ld a, [wCurMap] + cp AGATHAS_ROOM + jr z, .notUsable + ld a, [wCurMapTileset] + ld b, a + ld hl, EscapeRopeTilesets +.loop + ld a, [hli] + cp $ff + jr z, .notUsable + cp b + jr nz, .loop + ld hl, wd732 + set 3, [hl] + set 6, [hl] + ld hl, wd72e + res 4, [hl] + ResetEvent EVENT_IN_SAFARI_ZONE + xor a + ld [wNumSafariBalls], a + ld [wSafariZoneGateCurScript], a + inc a + ld [wEscapedFromBattle], a + ld [wActionResultOrTookBattleTurn], a ; item used + ld a, [wPseudoItemID] + and a ; using Dig? + ret nz ; if so, return + call ItemUseReloadOverworldData + ld c, 30 + call DelayFrames + jp RemoveUsedItem +.notUsable + jp ItemUseNotTime + +EscapeRopeTilesets: + db FOREST, CEMETERY, CAVERN, FACILITY, INTERIOR + db $ff ; terminator + +ItemUseRepel: + ld b, 100 + +ItemUseRepelCommon: + ld a, [wIsInBattle] + and a + jp nz, ItemUseNotTime + ld a, b + ld [wRepelRemainingSteps], a + jp PrintItemUseTextAndRemoveItem + +; handles X Accuracy item +ItemUseXAccuracy: + ld a, [wIsInBattle] + and a + jp z, ItemUseNotTime + ld hl, wPlayerBattleStatus2 + set USING_X_ACCURACY, [hl] ; X Accuracy bit + jp PrintItemUseTextAndRemoveItem + +; This function is bugged and never works. It always jumps to ItemUseNotTime. +; The Card Key is handled in a different way. +ItemUseCardKey: + xor a + ld [wUnusedD71F], a + call GetTileAndCoordsInFrontOfPlayer + ld a, [GetTileAndCoordsInFrontOfPlayer] + cp $18 + 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 + ld hl, CardKeyTable3 +.next1 + ld a, [wCurMap] + ld b, a +.loop + ld a, [hli] + cp $ff + jp z, ItemUseNotTime + cp b + jr nz, .nextEntry1 + ld a, [hli] + cp d + jr nz, .nextEntry2 + ld a, [hli] + cp e + jr nz, .nextEntry3 + ld a, [hl] + ld [wUnusedD71F], a + jr .done +.nextEntry1 + inc hl +.nextEntry2 + inc hl +.nextEntry3 + inc hl + jr .loop +.done + ld hl, ItemUseText00 + call PrintText + ld hl, wd728 + set 7, [hl] + ret + +; These tables are probably supposed to be door locations in Silph Co., +; but they are unused. +; The reason there are 3 tables is unknown. + +; Format: +; 00: Map ID +; 01: Y +; 02: X +; 03: ID? + +CardKeyTable1: + db SILPH_CO_2F,$04,$04,$00 + db SILPH_CO_2F,$04,$05,$01 + db SILPH_CO_4F,$0C,$04,$02 + db SILPH_CO_4F,$0C,$05,$03 + db SILPH_CO_7F,$06,$0A,$04 + db SILPH_CO_7F,$06,$0B,$05 + db SILPH_CO_9F,$04,$12,$06 + db SILPH_CO_9F,$04,$13,$07 + db SILPH_CO_10F,$08,$0A,$08 + db SILPH_CO_10F,$08,$0B,$09 + db $ff + +CardKeyTable2: + db SILPH_CO_3F,$08,$09,$0A + db SILPH_CO_3F,$09,$09,$0B + db SILPH_CO_5F,$04,$07,$0C + db SILPH_CO_5F,$05,$07,$0D + db SILPH_CO_6F,$0C,$05,$0E + db SILPH_CO_6F,$0D,$05,$0F + db SILPH_CO_8F,$08,$07,$10 + db SILPH_CO_8F,$09,$07,$11 + db SILPH_CO_9F,$08,$03,$12 + db SILPH_CO_9F,$09,$03,$13 + db $ff + +CardKeyTable3: + db SILPH_CO_11F,$08,$09,$14 + db SILPH_CO_11F,$09,$09,$15 + db $ff + +ItemUsePokedoll: + ld a, [wIsInBattle] + dec a + jp nz, ItemUseNotTime + ld a, $01 + ld [wEscapedFromBattle], a + jp PrintItemUseTextAndRemoveItem + +ItemUseGuardSpec: + ld a, [wIsInBattle] + and a + jp z, ItemUseNotTime + ld hl, wPlayerBattleStatus2 + set PROTECTED_BY_MIST, [hl] ; Mist bit + jp PrintItemUseTextAndRemoveItem + +ItemUseSuperRepel: + ld b, 200 + jp ItemUseRepelCommon + +ItemUseMaxRepel: + ld b, 250 + jp ItemUseRepelCommon + +ItemUseDireHit: + ld a, [wIsInBattle] + and a + jp z, ItemUseNotTime + ld hl, wPlayerBattleStatus2 + set GETTING_PUMPED, [hl] ; Focus Energy bit + jp PrintItemUseTextAndRemoveItem + +ItemUseXStat: + ld a, [wIsInBattle] + and a + jr nz, .inBattle + call ItemUseNotTime + ld a, 2 + ld [wActionResultOrTookBattleTurn], a ; item not used + ret +.inBattle + ld hl, wPlayerMoveNum + ld a, [hli] + push af ; save [wPlayerMoveNum] + ld a, [hl] + push af ; save [wPlayerMoveEffect] + push hl + ld a, [wcf91] + sub X_ATTACK - ATTACK_UP1_EFFECT + ld [hl], a ; store player move effect + call PrintItemUseTextAndRemoveItem + ld a, XSTATITEM_ANIM ; X stat item animation ID + ld [wPlayerMoveNum], a + call LoadScreenTilesFromBuffer1 ; restore saved screen + call Delay3 + xor a + ld [H_WHOSETURN], a ; set turn to player's turn + callba StatModifierUpEffect ; do stat increase move + pop hl + pop af + ld [hld], a ; restore [wPlayerMoveEffect] + pop af + ld [hl], a ; restore [wPlayerMoveNum] + ret + +ItemUsePokeflute: + ld a, [wIsInBattle] + and a + jr nz, .inBattle +; if not in battle + call ItemUseReloadOverworldData + ld a, [wCurMap] + cp ROUTE_12 + jr nz, .notRoute12 + CheckEvent EVENT_BEAT_ROUTE12_SNORLAX + jr nz, .noSnorlaxToWakeUp +; if the player hasn't beaten Route 12 Snorlax + ld hl, Route12SnorlaxFluteCoords + call ArePlayerCoordsInArray + jr nc, .noSnorlaxToWakeUp + ld hl, PlayedFluteHadEffectText + call PrintText + SetEvent EVENT_FIGHT_ROUTE12_SNORLAX + ret +.notRoute12 + cp ROUTE_16 + jr nz, .noSnorlaxToWakeUp + CheckEvent EVENT_BEAT_ROUTE16_SNORLAX + jr nz, .noSnorlaxToWakeUp +; if the player hasn't beaten Route 16 Snorlax + ld hl, Route16SnorlaxFluteCoords + call ArePlayerCoordsInArray + jr nc, .noSnorlaxToWakeUp + ld hl, PlayedFluteHadEffectText + call PrintText + SetEvent EVENT_FIGHT_ROUTE16_SNORLAX + ret +.noSnorlaxToWakeUp + ld hl, PlayedFluteNoEffectText + jp PrintText +.inBattle + xor a + ld [wWereAnyMonsAsleep], a + ld b, ~SLP & $ff + ld hl, wPartyMon1Status + call WakeUpEntireParty + ld a, [wIsInBattle] + dec a ; is it a trainer battle? + jr z, .skipWakingUpEnemyParty +; if it's a trainer battle + ld hl, wEnemyMon1Status + call WakeUpEntireParty +.skipWakingUpEnemyParty + ld hl, wBattleMonStatus + ld a, [hl] + and b ; remove Sleep status + ld [hl], a + ld hl, wEnemyMonStatus + ld a, [hl] + and b ; remove Sleep status + ld [hl], a + call LoadScreenTilesFromBuffer2 ; restore saved screen + ld a, [wWereAnyMonsAsleep] + and a ; were any pokemon asleep before playing the flute? + ld hl, PlayedFluteNoEffectText + jp z, PrintText ; if no pokemon were asleep +; if some pokemon were asleep + ld hl, PlayedFluteHadEffectText + call PrintText + ld a, [wLowHealthAlarm] + and $80 + jr nz, .skipMusic + call WaitForSoundToFinish ; wait for sound to end + callba Music_PokeFluteInBattle ; play in-battle pokeflute music +.musicWaitLoop ; wait for music to finish playing + ld a, [wChannelSoundIDs + Ch7] + and a ; music off? + jr nz, .musicWaitLoop +.skipMusic + ld hl, FluteWokeUpText + jp PrintText + +; wakes up all party pokemon +; INPUT: +; hl must point to status of first pokemon in party (player's or enemy's) +; b must equal ~SLP +; [wWereAnyMonsAsleep] should be initialized to 0 +; OUTPUT: +; [wWereAnyMonsAsleep]: set to 1 if any pokemon were asleep +WakeUpEntireParty: + ld de, 44 + ld c, 6 +.loop + ld a, [hl] + push af + and SLP ; is pokemon asleep? + jr z, .notAsleep + ld a, 1 + ld [wWereAnyMonsAsleep], a ; indicate that a pokemon had to be woken up +.notAsleep + pop af + and b ; remove Sleep status + ld [hl], a + add hl, de + dec c + jr nz, .loop + ret + +; Format: +; 00: Y +; 01: X +Route12SnorlaxFluteCoords: + db 62,9 ; one space West of Snorlax + db 61,10 ; one space North of Snorlax + db 63,10 ; one space South of Snorlax + db 62,11 ; one space East of Snorlax + db $ff ; terminator + +; Format: +; 00: Y +; 01: X +Route16SnorlaxFluteCoords: + db 10,27 ; one space East of Snorlax + db 10,25 ; one space West of Snorlax + db $ff ; terminator + +PlayedFluteNoEffectText: + TX_FAR _PlayedFluteNoEffectText + db "@" + +FluteWokeUpText: + TX_FAR _FluteWokeUpText + db "@" + +PlayedFluteHadEffectText: + TX_FAR _PlayedFluteHadEffectText + TX_BLINK + TX_ASM + ld a, [wIsInBattle] + and a + jr nz, .done +; play out-of-battle pokeflute music + ld a, $ff + call PlaySound ; turn off music + ld a, SFX_POKEFLUTE + ld c, BANK(SFX_Pokeflute) + call PlayMusic +.musicWaitLoop ; wait for music to finish playing + ld a, [wChannelSoundIDs + Ch3] + cp SFX_POKEFLUTE + jr z, .musicWaitLoop + call PlayDefaultMusic ; start playing normal music again +.done + jp TextScriptEnd ; end text + +ItemUseCoinCase: + ld a, [wIsInBattle] + and a + jp nz, ItemUseNotTime + ld hl, CoinCaseNumCoinsText + jp PrintText + +CoinCaseNumCoinsText: + TX_FAR _CoinCaseNumCoinsText + db "@" + +ItemUseOldRod: + call FishingInit + jp c, ItemUseNotTime + lb bc, 5, MAGIKARP + ld a, $1 ; set bite + jr RodResponse + +ItemUseGoodRod: + call FishingInit + jp c, ItemUseNotTime +.RandomLoop + call Random + srl a + jr c, .SetBite + and %11 + cp 2 + jr nc, .RandomLoop + ; choose which monster appears + ld hl, GoodRodMons + add a + ld c, a + ld b, 0 + add hl, bc + ld b, [hl] + inc hl + ld c, [hl] + and a +.SetBite + ld a, 0 + rla + xor 1 + jr RodResponse + +INCLUDE "data/good_rod.asm" + +ItemUseSuperRod: + call FishingInit + jp c, ItemUseNotTime + call ReadSuperRodData + ld a, e +RodResponse: + ld [wRodResponse], a + + dec a ; is there a bite? + jr nz, .next + ; if yes, store level and species data + ld a, 1 + ld [wMoveMissed], a + ld a, b ; level + ld [wCurEnemyLVL], a + ld a, c ; species + ld [wCurOpponent], a + +.next + ld hl, wWalkBikeSurfState + ld a, [hl] ; store the value in a + push af + push hl + ld [hl], 0 + callba FishingAnim + pop hl + pop af + ld [hl], a + ret + +; checks if fishing is possible and if so, runs initialization code common to all rods +; unsets carry if fishing is possible, sets carry if not +FishingInit: + ld a, [wIsInBattle] + and a + jr z, .notInBattle + scf ; can't fish during battle + ret +.notInBattle + call IsNextTileShoreOrWater + ret c + ld a, [wWalkBikeSurfState] + cp 2 ; Surfing? + jr z, .surfing + call ItemUseReloadOverworldData + ld hl, ItemUseText00 + call PrintText + ld a, SFX_HEAL_AILMENT + call PlaySound + ld c, 80 + call DelayFrames + and a + ret +.surfing + scf ; can't fish when surfing + ret + +ItemUseOaksParcel: + jp ItemUseNotYoursToUse + +ItemUseItemfinder: + ld a, [wIsInBattle] + and a + jp nz, ItemUseNotTime + call ItemUseReloadOverworldData + callba HiddenItemNear ; check for hidden items + ld hl, ItemfinderFoundNothingText + jr nc, .printText ; if no hidden items + ld c, 4 +.loop + ld a, SFX_HEALING_MACHINE + call PlaySoundWaitForCurrent + ld a, SFX_PURCHASE + call PlaySoundWaitForCurrent + dec c + jr nz, .loop + ld hl, ItemfinderFoundItemText +.printText + jp PrintText + +ItemfinderFoundItemText: + TX_FAR _ItemfinderFoundItemText + db "@" + +ItemfinderFoundNothingText: + TX_FAR _ItemfinderFoundNothingText + db "@" + +ItemUsePPUp: + ld a, [wIsInBattle] + and a + jp nz, ItemUseNotTime + +ItemUsePPRestore: + ld a, [wWhichPokemon] + push af + ld a, [wcf91] + ld [wPPRestoreItem], a +.chooseMon + xor a + ld [wUpdateSpritesEnabled], a + ld a, USE_ITEM_PARTY_MENU + ld [wPartyMenuTypeOrMessageID], a + call DisplayPartyMenu + jr nc, .chooseMove + jp .itemNotUsed +.chooseMove + ld a, [wPPRestoreItem] + cp ELIXER + jp nc, .useElixir ; if Elixir or Max Elixir + ld a, $02 + ld [wMoveMenuType], a + ld hl, RaisePPWhichTechniqueText + ld a, [wPPRestoreItem] + cp ETHER ; is it a PP Up? + jr c, .printWhichTechniqueMessage ; if so, print the raise PP message + ld hl, RestorePPWhichTechniqueText ; otherwise, print the restore PP message +.printWhichTechniqueMessage + call PrintText + xor a + ld [wPlayerMoveListIndex], a + callab MoveSelectionMenu ; move selection menu + ld a, 0 + ld [wPlayerMoveListIndex], a + jr nz, .chooseMon + ld hl, wPartyMon1Moves + ld bc, wPartyMon2 - wPartyMon1 + call GetSelectedMoveOffset + push hl + ld a, [hl] + ld [wd11e], a + call GetMoveName + call CopyStringToCF4B ; copy name to wcf4b + pop hl + ld a, [wPPRestoreItem] + cp ETHER + jr nc, .useEther ; if Ether or Max Ether +.usePPUp + ld bc, wPartyMon1PP - wPartyMon1Moves + add hl, bc + ld a, [hl] ; move PP + cp 3 << 6 ; have 3 PP Ups already been used? + jr c, .PPNotMaxedOut + ld hl, PPMaxedOutText + call PrintText + jr .chooseMove +.PPNotMaxedOut + ld a, [hl] + add 1 << 6 ; increase PP Up count by 1 + ld [hl], a + ld a, 1 ; 1 PP Up used + ld [wd11e], a + call RestoreBonusPP ; add the bonus PP to current PP + ld hl, PPIncreasedText + call PrintText +.done + pop af + ld [wWhichPokemon], a + call GBPalWhiteOut + call RunDefaultPaletteCommand + jp RemoveUsedItem +.afterRestoringPP ; after using a (Max) Ether/Elixir + ld a, [wWhichPokemon] + ld b, a + ld a, [wPlayerMonNumber] + cp b ; is the pokemon whose PP was restored active in battle? + jr nz, .skipUpdatingInBattleData + ld hl, wPartyMon1PP + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld de, wBattleMonPP + ld bc, 4 + call CopyData ; copy party data to in-battle data +.skipUpdatingInBattleData + ld a, SFX_HEAL_AILMENT + call PlaySound + 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 + xor a ; PLAYER_PARTY_DATA + ld [wMonDataLocation], a + call GetMaxPP + ld hl, wPartyMon1Moves + ld bc, wPartyMon2 - wPartyMon1 + call GetSelectedMoveOffset + ld bc, wPartyMon1PP - wPartyMon1Moves + add hl, bc ; hl now points to move's PP + ld a, [wMaxPP] + ld b, a + ld a, [wPPRestoreItem] + cp MAX_ETHER + jr z, .fullyRestorePP + ld a, [hl] ; move PP + and %00111111 ; lower 6 bit bits store current PP + cp b ; does current PP equal max PP? + ret z ; if so, return + add 10 ; increase current PP by 10 +; b holds the max PP amount and b will hold the new PP amount. +; So, if the new amount meets or exceeds the max amount, +; cap the amount to the max amount by leaving b unchanged. +; Otherwise, store the new amount in b. + cp b ; does the new amount meet or exceed the maximum? + jr nc, .storeNewAmount + ld b, a +.storeNewAmount + ld a, [hl] ; move PP + and %11000000 ; PP Up counter bits + 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 +; are used to count how many PP Ups have been used on the move. So, Max Ethers +; and Max Elixirs will not be detected as having no effect on a move with full +; PP if the move has had any PP Ups used on it. + 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 + dec [hl] + dec [hl] + xor a + ld hl, wCurrentMenuItem + ld [hli], a + ld [hl], a ; zero the counter for number of moves that had their PP restored + ld b, 4 +; loop through each move and restore PP +.elixirLoop + push bc + ld hl, wPartyMon1Moves + ld bc, wPartyMon2 - wPartyMon1 + call GetSelectedMoveOffset + ld a, [hl] + and a ; does the current slot have a move? + jr z, .nextMove + call .restorePP + jr z, .nextMove +; if some PP was restored + ld hl, wTileBehindCursor ; counter for number of moves that had their PP restored + inc [hl] +.nextMove + ld hl, wCurrentMenuItem + inc [hl] + pop bc + dec b + jr nz, .elixirLoop + ld a, [wTileBehindCursor] + and a ; did any moves have their PP restored? + jp nz, .afterRestoringPP +.noEffect + call ItemUseNoEffect +.itemNotUsed + call GBPalWhiteOut + call RunDefaultPaletteCommand + pop af + xor a + ld [wActionResultOrTookBattleTurn], a ; item use failed + ret + +RaisePPWhichTechniqueText: + TX_FAR _RaisePPWhichTechniqueText + db "@" + +RestorePPWhichTechniqueText: + TX_FAR _RestorePPWhichTechniqueText + db "@" + +PPMaxedOutText: + TX_FAR _PPMaxedOutText + db "@" + +PPIncreasedText: + TX_FAR _PPIncreasedText + db "@" + +PPRestoredText: + TX_FAR _PPRestoredText + db "@" + +; for items that can't be used from the Item menu +UnusableItem: + jp ItemUseNotTime + +ItemUseTMHM: + ld a, [wIsInBattle] + and a + jp nz, ItemUseNotTime + ld a, [wcf91] + sub TM_01 + push af + jr nc, .skipAdding + add 55 ; if item is an HM, add 55 +.skipAdding + inc a + ld [wd11e], a + predef TMToMove ; get move ID from TM/HM ID + ld a, [wd11e] + ld [wMoveNum], a + call GetMoveName + call CopyStringToCF4B ; copy name to wcf4b + pop af + ld hl, BootedUpTMText + jr nc, .printBootedUpMachineText + ld hl, BootedUpHMText +.printBootedUpMachineText + call PrintText + ld hl, TeachMachineMoveText + call PrintText + coord hl, 14, 7 + lb bc, 8, 15 + ld a, TWO_OPTION_MENU + ld [wTextBoxID], a + call DisplayTextBoxID ; yes/no menu + ld a, [wCurrentMenuItem] + and a + jr z, .useMachine + ld a, 2 + ld [wActionResultOrTookBattleTurn], a ; item not used + ret +.useMachine + ld a, [wWhichPokemon] + push af + ld a, [wcf91] + push af +.chooseMon + ld hl, wcf4b + ld de, wTempMoveNameBuffer + ld bc, 14 + call CopyData ; save the move name because DisplayPartyMenu will overwrite it + ld a, $ff + ld [wUpdateSpritesEnabled], a + ld a, TMHM_PARTY_MENU + ld [wPartyMenuTypeOrMessageID], a + call DisplayPartyMenu + push af + ld hl, wTempMoveNameBuffer + ld de, wcf4b + ld bc, 14 + call CopyData + pop af + jr nc, .checkIfAbleToLearnMove +; if the player canceled teaching the move + pop af + pop af + call GBPalWhiteOutWithDelay3 + call ClearSprites + call RunDefaultPaletteCommand + jp LoadScreenTilesFromBuffer1 ; restore saved screen +.checkIfAbleToLearnMove + predef CanLearnTM ; check if the pokemon can learn the move + push bc + ld a, [wWhichPokemon] + ld hl, wPartyMonNicks + call GetPartyMonName + pop bc + ld a, c + and a ; can the pokemon learn the move? + jr nz, .checkIfAlreadyLearnedMove +; if the pokemon can't learn the move + ld a, SFX_DENIED + call PlaySoundWaitForCurrent + ld hl, MonCannotLearnMachineMoveText + call PrintText + jr .chooseMon +.checkIfAlreadyLearnedMove + callab CheckIfMoveIsKnown ; check if the pokemon already knows the move + jr c, .chooseMon + predef LearnMove ; teach move + pop af + ld [wcf91], a + pop af + ld [wWhichPokemon], a + ld a, b + and a + ret z + ld a, [wcf91] + call IsItemHM + ret c + jp RemoveUsedItem + +BootedUpTMText: + TX_FAR _BootedUpTMText + db "@" + +BootedUpHMText: + TX_FAR _BootedUpHMText + db "@" + +TeachMachineMoveText: + TX_FAR _TeachMachineMoveText + db "@" + +MonCannotLearnMachineMoveText: + TX_FAR _MonCannotLearnMachineMoveText + db "@" + +PrintItemUseTextAndRemoveItem: + ld hl, ItemUseText00 + call PrintText + ld a, SFX_HEAL_AILMENT + call PlaySound + call WaitForTextScrollButtonPress ; wait for button press + +RemoveUsedItem: + ld hl, wNumBagItems + ld a, 1 ; one item + ld [wItemQuantity], a + jp RemoveItemFromInventory + +ItemUseNoEffect: + ld hl, ItemUseNoEffectText + jr ItemUseFailed + +ItemUseNotTime: + ld hl, ItemUseNotTimeText + jr ItemUseFailed + +ItemUseNotYoursToUse: + ld hl, ItemUseNotYoursToUseText + jr ItemUseFailed + +ThrowBallAtTrainerMon: + call RunDefaultPaletteCommand + call LoadScreenTilesFromBuffer1 ; restore saved screen + call Delay3 + ld a, TOSS_ANIM + ld [wAnimationID], a + predef MoveAnimation ; do animation + ld hl, ThrowBallAtTrainerMonText1 + call PrintText + ld hl, ThrowBallAtTrainerMonText2 + call PrintText + jr RemoveUsedItem + +NoCyclingAllowedHere: + ld hl, NoCyclingAllowedHereText + jr ItemUseFailed + +BoxFullCannotThrowBall: + ld hl, BoxFullCannotThrowBallText + jr ItemUseFailed + +SurfingAttemptFailed: + ld hl, NoSurfingHereText + +ItemUseFailed: + xor a + ld [wActionResultOrTookBattleTurn], a ; item use failed + jp PrintText + +ItemUseNotTimeText: + TX_FAR _ItemUseNotTimeText + db "@" + +ItemUseNotYoursToUseText: + TX_FAR _ItemUseNotYoursToUseText + db "@" + +ItemUseNoEffectText: + TX_FAR _ItemUseNoEffectText + db "@" + +ThrowBallAtTrainerMonText1: + TX_FAR _ThrowBallAtTrainerMonText1 + db "@" + +ThrowBallAtTrainerMonText2: + TX_FAR _ThrowBallAtTrainerMonText2 + db "@" + +NoCyclingAllowedHereText: + TX_FAR _NoCyclingAllowedHereText + db "@" + +NoSurfingHereText: + TX_FAR _NoSurfingHereText + db "@" + +BoxFullCannotThrowBallText: + TX_FAR _BoxFullCannotThrowBallText + db "@" + +ItemUseText00: + TX_FAR _ItemUseText001 + TX_LINE + TX_FAR _ItemUseText002 + db "@" + +GotOnBicycleText: + TX_FAR _GotOnBicycleText1 + TX_LINE + TX_FAR _GotOnBicycleText2 + db "@" + +GotOffBicycleText: + TX_FAR _GotOffBicycleText1 + TX_LINE + TX_FAR _GotOffBicycleText2 + db "@" + +; restores bonus PP (from PP Ups) when healing at a pokemon center +; also, when a PP Up is used, it increases the current PP by one PP Up bonus +; INPUT: +; [wWhichPokemon] = index of pokemon in party +; [wCurrentMenuItem] = index of move (when using a PP Up) +RestoreBonusPP: + ld hl, wPartyMon1Moves + ld bc, wPartyMon2 - wPartyMon1 + ld a, [wWhichPokemon] + call AddNTimes + push hl + ld de, wNormalMaxPPList - 1 + predef LoadMovePPs ; loads the normal max PP of each of the pokemon's moves to wNormalMaxPPList + pop hl + ld c, wPartyMon1PP - wPartyMon1Moves + ld b, 0 + add hl, bc ; hl now points to move 1 PP + ld de, wNormalMaxPPList + ld b, 0 ; initialize move counter to zero +; loop through the pokemon's moves +.loop + inc b + ld a, b + cp 5 ; reached the end of the pokemon's moves? + ret z ; if so, return + ld a, [wUsingPPUp] + dec a ; using a PP Up? + jr nz, .skipMenuItemIDCheck +; if using a PP Up, check if this is the move it's being used on + ld a, [wCurrentMenuItem] + inc a + cp b + jr nz, .nextMove +.skipMenuItemIDCheck + ld a, [hl] + and %11000000 ; have any PP Ups been used? + call nz, AddBonusPP ; if so, add bonus PP +.nextMove + inc hl + inc de + jr .loop + +; adds bonus PP from PP Ups to current PP +; 1/5 of normal max PP (capped at 7) is added for each PP Up +; INPUT: +; [de] = normal max PP +; [hl] = move PP +AddBonusPP: + push bc + ld a, [de] ; normal max PP of move + ld [H_DIVIDEND + 3], a + xor a + ld [H_DIVIDEND], a + ld [H_DIVIDEND + 1], a + ld [H_DIVIDEND + 2], a + ld a, 5 + ld [H_DIVISOR], a + ld b, 4 + call Divide + ld a, [hl] ; move PP + ld b, a + swap a + and %00001111 + srl a + srl a + ld c, a ; c = number of PP Ups used +.loop + ld a, [H_QUOTIENT + 3] + cp 8 ; is the amount greater than or equal to 8? + jr c, .addAmount + ld a, 7 ; cap the amount at 7 +.addAmount + add b + ld b, a + ld a, [wUsingPPUp] + dec a ; is the player using a PP Up right now? + jr z, .done ; if so, only add the bonus once + dec c + jr nz, .loop +.done + ld [hl], b + pop bc + ret + +; gets max PP of a pokemon's move (including PP from PP Ups) +; INPUT: +; [wWhichPokemon] = index of pokemon within party/box +; [wMonDataLocation] = pokemon source +; 00: player's party +; 01: enemy's party +; 02: current box +; 03: daycare +; 04: player's in-battle pokemon +; [wCurrentMenuItem] = move index +; OUTPUT: +; [wMaxPP] = max PP +GetMaxPP: + ld a, [wMonDataLocation] + and a + ld hl, wPartyMon1Moves + ld bc, wPartyMon2 - wPartyMon1 + jr z, .sourceWithMultipleMon + ld hl, wEnemyMon1Moves + dec a + jr z, .sourceWithMultipleMon + ld hl, wBoxMon1Moves + ld bc, wBoxMon2 - wBoxMon1 + dec a + jr z, .sourceWithMultipleMon + ld hl, wDayCareMonMoves + dec a + jr z, .sourceWithOneMon + ld hl, wBattleMonMoves ; player's in-battle pokemon +.sourceWithOneMon + call GetSelectedMoveOffset2 + jr .next +.sourceWithMultipleMon + call GetSelectedMoveOffset +.next + ld a, [hl] + dec a + push hl + ld hl, Moves + ld bc, MoveEnd - Moves + call AddNTimes + ld de, wcd6d + ld a, BANK(Moves) + call FarCopyData + ld de, wcd6d + 5 ; PP is byte 5 of move data + ld a, [de] + ld b, a ; b = normal max PP + pop hl + push bc + ld bc, wPartyMon1PP - wPartyMon1Moves ; PP offset if not player's in-battle pokemon data + ld a, [wMonDataLocation] + cp 4 ; player's in-battle pokemon? + jr nz, .addPPOffset + ld bc, wBattleMonPP - wBattleMonMoves ; PP offset if player's in-battle pokemon data +.addPPOffset + add hl, bc + ld a, [hl] ; a = current PP + and %11000000 ; get PP Up count + pop bc + or b ; place normal max PP in 6 lower bits of a + ld h, d + ld l, e + inc hl ; hl = wcd73 + ld [hl], a + xor a ; add the bonus for the existing PP Up count + ld [wUsingPPUp], a + call AddBonusPP ; add bonus PP from PP Ups + ld a, [hl] + and %00111111 ; mask out the PP Up count + ld [wMaxPP], a ; store max PP + ret + +GetSelectedMoveOffset: + ld a, [wWhichPokemon] + call AddNTimes + +GetSelectedMoveOffset2: + ld a, [wCurrentMenuItem] + ld c, a + ld b, 0 + add hl, bc + ret + +; confirms the item toss and then tosses the item +; INPUT: +; hl = address of inventory (either wNumBagItems or wNumBoxItems) +; [wcf91] = item ID +; [wWhichPokemon] = index of item within inventory +; [wItemQuantity] = quantity to toss +; OUTPUT: +; clears carry flag if the item is tossed, sets carry flag if not +TossItem_:: + push hl + ld a, [wcf91] + call IsItemHM + pop hl + jr c, .tooImportantToToss + push hl + call IsKeyItem_ + ld a, [wIsKeyItem] + pop hl + and a + jr nz, .tooImportantToToss + push hl + ld a, [wcf91] + ld [wd11e], a + call GetItemName + call CopyStringToCF4B ; copy name to wcf4b + ld hl, IsItOKToTossItemText + call PrintText + coord hl, 14, 7 + lb bc, 8, 15 + ld a, TWO_OPTION_MENU + ld [wTextBoxID], a + call DisplayTextBoxID ; yes/no menu + ld a, [wMenuExitMethod] + cp CHOSE_SECOND_ITEM + pop hl + scf + ret z ; return if the player chose No +; if the player chose Yes + push hl + ld a, [wWhichPokemon] + call RemoveItemFromInventory + ld a, [wcf91] + ld [wd11e], a + call GetItemName + call CopyStringToCF4B ; copy name to wcf4b + ld hl, ThrewAwayItemText + call PrintText + pop hl + and a + ret +.tooImportantToToss + push hl + ld hl, TooImportantToTossText + call PrintText + pop hl + scf + ret + +ThrewAwayItemText: + TX_FAR _ThrewAwayItemText + db "@" + +IsItOKToTossItemText: + TX_FAR _IsItOKToTossItemText + db "@" + +TooImportantToTossText: + TX_FAR _TooImportantToTossText + db "@" + +; checks if an item is a key item +; INPUT: +; [wcf91] = item ID +; OUTPUT: +; [wIsKeyItem] = result +; 00: item is not key item +; 01: item is key item +IsKeyItem_:: + ld a, $01 + ld [wIsKeyItem], a + ld a, [wcf91] + cp HM_01 ; is the item an HM or TM? + jr nc, .checkIfItemIsHM +; if the item is not an HM or TM + push af + ld hl, KeyItemBitfield + ld de, wBuffer + ld bc, 15 ; only 11 bytes are actually used + call CopyData + pop af + dec a + ld c, a + ld hl, wBuffer + ld b, FLAG_TEST + predef FlagActionPredef + ld a, c + and a + ret nz +.checkIfItemIsHM + ld a, [wcf91] + call IsItemHM + ret c + xor a + ld [wIsKeyItem], a + ret + +INCLUDE "data/key_items.asm" + +SendNewMonToBox: + ld de, wNumInBox + ld a, [de] + inc a + ld [de], a + ld a, [wcf91] + ld [wd0b5], a + ld c, a +.asm_e7b1 + inc de + ld a, [de] + ld b, a + ld a, c + ld c, b + ld [de], a + cp $ff + jr nz, .asm_e7b1 + call GetMonHeader + ld hl, wBoxMonOT + ld bc, NAME_LENGTH + ld a, [wNumInBox] + dec a + jr z, .asm_e7ee + dec a + call AddNTimes + push hl + ld bc, NAME_LENGTH + add hl, bc + ld d, h + ld e, l + pop hl + ld a, [wNumInBox] + dec a + ld b, a +.asm_e7db + push bc + push hl + ld bc, NAME_LENGTH + call CopyData + pop hl + ld d, h + ld e, l + ld bc, -NAME_LENGTH + add hl, bc + pop bc + dec b + jr nz, .asm_e7db +.asm_e7ee + ld hl, wPlayerName + ld de, wBoxMonOT + ld bc, NAME_LENGTH + call CopyData + ld a, [wNumInBox] + dec a + jr z, .asm_e82a + ld hl, wBoxMonNicks + ld bc, NAME_LENGTH + dec a + call AddNTimes + push hl + ld bc, NAME_LENGTH + add hl, bc + ld d, h + ld e, l + pop hl + ld a, [wNumInBox] + dec a + ld b, a +.asm_e817 + push bc + push hl + ld bc, NAME_LENGTH + call CopyData + pop hl + ld d, h + ld e, l + ld bc, -NAME_LENGTH + add hl, bc + pop bc + dec b + jr nz, .asm_e817 +.asm_e82a + ld hl, wBoxMonNicks + ld a, NAME_MON_SCREEN + ld [wNamingScreenType], a + predef AskName + ld a, [wNumInBox] + dec a + jr z, .asm_e867 + ld hl, wBoxMons + ld bc, wBoxMon2 - wBoxMon1 + dec a + call AddNTimes + push hl + ld bc, wBoxMon2 - wBoxMon1 + add hl, bc + ld d, h + ld e, l + pop hl + ld a, [wNumInBox] + dec a + ld b, a +.asm_e854 + push bc + push hl + ld bc, wBoxMon2 - wBoxMon1 + call CopyData + pop hl + ld d, h + ld e, l + ld bc, wBoxMon1 - wBoxMon2 + add hl, bc + pop bc + dec b + jr nz, .asm_e854 +.asm_e867 + ld a, [wEnemyMonLevel] + ld [wEnemyMonBoxLevel], a + ld hl, wEnemyMon + ld de, wBoxMon1 + ld bc, wEnemyMonDVs - wEnemyMon + call CopyData + ld hl, wPlayerID + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + inc de + push de + ld a, [wCurEnemyLVL] + ld d, a + callab CalcExperience + pop de + ld a, [hExperience] + ld [de], a + inc de + ld a, [hExperience + 1] + ld [de], a + inc de + ld a, [hExperience + 2] + ld [de], a + inc de + xor a + ld b, NUM_STATS * 2 +.asm_e89f + ld [de], a + inc de + dec b + jr nz, .asm_e89f + ld hl, wEnemyMonDVs + ld a, [hli] + ld [de], a + inc de + ld a, [hli] + ld [de], a + ld hl, wEnemyMonPP + ld b, NUM_MOVES +.asm_e8b1 + ld a, [hli] + inc de + ld [de], a + dec b + jr nz, .asm_e8b1 + 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: + ld a, [wCurMapTileset] + ld hl, WaterTilesets + ld de, 1 + call IsInArray + jr nc, .notShoreOrWater + 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 +.skipShoreTiles + cp $14 ; water tile + jr z, .shoreOrWater +.notShoreOrWater + scf + ret +.shoreOrWater + and a + ret + +INCLUDE "data/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 + call IsInArray + jr c, .ReadFishingGroup + ld e, $2 ; $2 if no fishing groups found + ret + +.ReadFishingGroup +; hl points to the fishing group entry in the index + inc hl ; skip map id + + ; read fishing group address + ld a, [hli] + ld h, [hl] + ld l, a + + ld b, [hl] ; how many mons in group + inc hl ; point to data + ld e, $0 ; no bite yet + +.RandomLoop + call Random + srl a + ret c ; 50% chance of no battle + + and %11 ; 2-bit random number + cp b + jr nc, .RandomLoop ; if a is greater than the number of mons, regenerate + + ; get the mon + add a + ld c, a + ld b, $0 + add hl, bc + ld b, [hl] ; level + inc hl + ld c, [hl] ; species + ld e, $1 ; $1 if there's a bite + ret + +INCLUDE "data/super_rod.asm" + +; reloads map view and processes sprite data +; for items that cause the overworld to be displayed +ItemUseReloadOverworldData: + call LoadCurrentMapView + jp UpdateSprites + +; creates a list at wBuffer of maps where the mon in [wd11e] can be found. +; this is used by the pokedex to display locations the mon can be found on the map. +FindWildLocationsOfMon: + ld hl, WildDataPointers + ld de, wBuffer + ld c, $0 +.loop + inc hl + ld a, [hld] + inc a + jr z, .done + push hl + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [hli] + and a + call nz, CheckMapForMon ; land + ld a, [hli] + and a + call nz, CheckMapForMon ; water + pop hl + inc hl + inc hl + inc c + jr .loop +.done + ld a, $ff ; list terminator + ld [de], a + ret + +CheckMapForMon: + inc hl + ld b, $a +.loop + ld a, [wd11e] + cp [hl] + jr nz, .nextEntry + ld a, c + ld [de], a + inc de +.nextEntry + inc hl + inc hl + dec b + jr nz, .loop + dec hl + ret diff --git a/engine/items/items.asm b/engine/items/items.asm deleted file mode 100755 index 6e7bed1e..00000000 --- a/engine/items/items.asm +++ /dev/null @@ -1,2986 +0,0 @@ -UseItem_:: - ld a, 1 - ld [wActionResultOrTookBattleTurn], a ; initialise to success value - ld a, [wcf91] ;contains item_ID - cp HM_01 - jp nc, ItemUseTMHM - ld hl, ItemUsePtrTable - dec a - add a - ld c, a - ld b, 0 - add hl, bc - ld a, [hli] - ld h, [hl] - ld l, a - jp hl - -ItemUsePtrTable: - dw ItemUseBall ; MASTER_BALL - dw ItemUseBall ; ULTRA_BALL - dw ItemUseBall ; GREAT_BALL - dw ItemUseBall ; POKE_BALL - dw ItemUseTownMap ; TOWN_MAP - dw ItemUseBicycle ; BICYCLE - dw ItemUseSurfboard ; out-of-battle Surf effect - dw ItemUseBall ; SAFARI_BALL - dw ItemUsePokedex ; POKEDEX - dw ItemUseEvoStone ; MOON_STONE - dw ItemUseMedicine ; ANTIDOTE - dw ItemUseMedicine ; BURN_HEAL - dw ItemUseMedicine ; ICE_HEAL - dw ItemUseMedicine ; AWAKENING - dw ItemUseMedicine ; PARLYZ_HEAL - dw ItemUseMedicine ; FULL_RESTORE - dw ItemUseMedicine ; MAX_POTION - dw ItemUseMedicine ; HYPER_POTION - dw ItemUseMedicine ; SUPER_POTION - dw ItemUseMedicine ; POTION - dw ItemUseBait ; BOULDERBADGE - dw ItemUseRock ; CASCADEBADGE - dw UnusableItem ; THUNDERBADGE - dw UnusableItem ; RAINBOWBADGE - dw UnusableItem ; SOULBADGE - dw UnusableItem ; MARSHBADGE - dw UnusableItem ; VOLCANOBADGE - dw UnusableItem ; EARTHBADGE - dw ItemUseEscapeRope ; ESCAPE_ROPE - dw ItemUseRepel ; REPEL - dw UnusableItem ; OLD_AMBER - dw ItemUseEvoStone ; FIRE_STONE - dw ItemUseEvoStone ; THUNDER_STONE - dw ItemUseEvoStone ; WATER_STONE - dw ItemUseVitamin ; HP_UP - dw ItemUseVitamin ; PROTEIN - dw ItemUseVitamin ; IRON - dw ItemUseVitamin ; CARBOS - dw ItemUseVitamin ; CALCIUM - dw ItemUseVitamin ; RARE_CANDY - dw UnusableItem ; DOME_FOSSIL - dw UnusableItem ; HELIX_FOSSIL - dw UnusableItem ; SECRET_KEY - dw UnusableItem - dw UnusableItem ; BIKE_VOUCHER - dw ItemUseXAccuracy ; X_ACCURACY - dw ItemUseEvoStone ; LEAF_STONE - dw ItemUseCardKey ; CARD_KEY - dw UnusableItem ; NUGGET - dw UnusableItem ; ??? PP_UP - dw ItemUsePokedoll ; POKE_DOLL - dw ItemUseMedicine ; FULL_HEAL - dw ItemUseMedicine ; REVIVE - dw ItemUseMedicine ; MAX_REVIVE - dw ItemUseGuardSpec ; GUARD_SPEC - dw ItemUseSuperRepel ; SUPER_REPL - dw ItemUseMaxRepel ; MAX_REPEL - dw ItemUseDireHit ; DIRE_HIT - dw UnusableItem ; COIN - dw ItemUseMedicine ; FRESH_WATER - dw ItemUseMedicine ; SODA_POP - dw ItemUseMedicine ; LEMONADE - dw UnusableItem ; S_S_TICKET - dw UnusableItem ; GOLD_TEETH - dw ItemUseXStat ; X_ATTACK - dw ItemUseXStat ; X_DEFEND - dw ItemUseXStat ; X_SPEED - dw ItemUseXStat ; X_SPECIAL - dw ItemUseCoinCase ; COIN_CASE - dw ItemUseOaksParcel ; OAKS_PARCEL - dw ItemUseItemfinder ; ITEMFINDER - dw UnusableItem ; SILPH_SCOPE - dw ItemUsePokeflute ; POKE_FLUTE - dw UnusableItem ; LIFT_KEY - dw UnusableItem ; EXP_ALL - dw ItemUseOldRod ; OLD_ROD - dw ItemUseGoodRod ; GOOD_ROD - dw ItemUseSuperRod ; SUPER_ROD - dw ItemUsePPUp ; PP_UP (real one) - dw ItemUsePPRestore ; ETHER - dw ItemUsePPRestore ; MAX_ETHER - dw ItemUsePPRestore ; ELIXER - dw ItemUsePPRestore ; MAX_ELIXER - -ItemUseBall: - -; Balls can't be used out of battle. - ld a, [wIsInBattle] - and a - jp z, ItemUseNotTime - -; Balls can't catch trainers' Pokémon. - dec a - jp nz, ThrowBallAtTrainerMon - -; If this is for the old man battle, skip checking if the party & box are full. - ld a, [wBattleType] - dec a - jr z, .canUseBall - - ld a, [wPartyCount] ; is party full? - cp PARTY_LENGTH - jr nz, .canUseBall - ld a, [wNumInBox] ; is box full? - cp MONS_PER_BOX - jp z, BoxFullCannotThrowBall - -.canUseBall - xor a - ld [wCapturedMonSpecies], a - - ld a, [wBattleType] - cp BATTLE_TYPE_SAFARI - jr nz, .skipSafariZoneCode - -.safariZone - ld hl, wNumSafariBalls - dec [hl] ; remove a Safari Ball - -.skipSafariZoneCode - call RunDefaultPaletteCommand - - ld a, $43 ; successful capture value - ld [wPokeBallAnimData], a - - call LoadScreenTilesFromBuffer1 - ld hl, ItemUseText00 - call PrintText - -; If the player is fighting an unidentified ghost, set the value that indicates -; the Pokémon can't be caught and skip the capture calculations. - callab IsGhostBattle - ld b, $10 ; can't be caught value - jp z, .setAnimData - - ld a, [wBattleType] - dec a - jr nz, .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) - 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. - ld a, [wCurMap] - cp POKEMON_TOWER_6F - jr nz, .loop - ld a, [wEnemyMonSpecies2] - cp MAROWAK - ld b, $10 ; can't be caught value - jp z, .setAnimData - -; Get the first random number. Let it be called Rand1. -; Rand1 must be within a certain range according the kind of ball being thrown. -; The ranges are as follows. -; Poké Ball: [0, 255] -; Great Ball: [0, 200] -; Ultra/Safari Ball: [0, 150] -; Loop until an acceptable number is found. - -.loop - call Random - ld b, a - -; Get the item ID. - ld hl, wcf91 - ld a, [hl] - -; The Master Ball always succeeds. - cp MASTER_BALL - jp z, .captured - -; Anything will do for the basic Poké Ball. - cp POKE_BALL - jr z, .checkForAilments - -; If it's a Great/Ultra/Safari Ball and Rand1 is greater than 200, try again. - ld a, 200 - cp b - jr c, .loop - -; Less than or equal to 200 is good enough for a Great Ball. - ld a, [hl] - cp GREAT_BALL - jr z, .checkForAilments - -; If it's an Ultra/Safari Ball and Rand1 is greater than 150, try again. - ld a, 150 - cp b - jr c, .loop - -.checkForAilments -; Pokémon can be caught more easily with a status ailment. -; Depending on the status ailment, a certain value will be subtracted from -; Rand1. Let this value be called Status. -; The larger Status is, the more easily the Pokémon can be caught. -; no status ailment: Status = 0 -; Burn/Paralysis/Poison: Status = 12 -; Freeze/Sleep: Status = 25 -; If Status is greater than Rand1, the Pokémon will be caught for sure. - ld a, [wEnemyMonStatus] - and a - jr z, .skipAilmentValueSubtraction ; no ailments - and 1 << FRZ | SLP - ld c, 12 - jr z, .notFrozenOrAsleep - ld c, 25 -.notFrozenOrAsleep - ld a, b - sub c - jp c, .captured - ld b, a - -.skipAilmentValueSubtraction - push bc ; save (Rand1 - Status) - -; Calculate MaxHP * 255. - xor a - ld [H_MULTIPLICAND], a - ld hl, wEnemyMonMaxHP - ld a, [hli] - ld [H_MULTIPLICAND + 1], a - ld a, [hl] - ld [H_MULTIPLICAND + 2], a - ld a, 255 - ld [H_MULTIPLIER], a - call Multiply - -; Determine BallFactor. It's 8 for Great Balls and 12 for the others. - ld a, [wcf91] - cp GREAT_BALL - ld a, 12 - jr nz, .skip1 - ld a, 8 - -.skip1 -; Note that the results of all division operations are floored. - -; Calculate (MaxHP * 255) / BallFactor. - ld [H_DIVISOR], a - ld b, 4 ; number of bytes in dividend - call Divide - -; Divide the enemy's current HP by 4. HP is not supposed to exceed 999 so -; the result should fit in a. If the division results in a quotient of 0, -; change it to 1. - ld hl, wEnemyMonHP - ld a, [hli] - ld b, a - ld a, [hl] - srl b - rr a - srl b - rr a - and a - jr nz, .skip2 - inc a - -.skip2 -; Let W = ((MaxHP * 255) / BallFactor) / max(HP / 4, 1). Calculate W. - ld [H_DIVISOR], a - ld b, 4 - call Divide - -; If W > 255, store 255 in [H_QUOTIENT + 3]. -; Let X = min(W, 255) = [H_QUOTIENT + 3]. - ld a, [H_QUOTIENT + 2] - and a - jr z, .skip3 - ld a, 255 - ld [H_QUOTIENT + 3], a - -.skip3 - pop bc ; b = Rand1 - Status - -; If Rand1 - Status > CatchRate, the ball fails to capture the Pokémon. - ld a, [wEnemyMonActualCatchRate] - cp b - jr c, .failedToCapture - -; If W > 255, the ball captures the Pokémon. - ld a, [H_QUOTIENT + 2] - and a - jr nz, .captured - - call Random ; Let this random number be called Rand2. - -; If Rand2 > X, the ball fails to capture the Pokémon. - ld b, a - ld a, [H_QUOTIENT + 3] - cp b - jr c, .failedToCapture - -.captured - jr .skipShakeCalculations - -.failedToCapture - ld a, [H_QUOTIENT + 3] - ld [wPokeBallCaptureCalcTemp], a ; Save X. - -; Calculate CatchRate * 100. - xor a - ld [H_MULTIPLICAND], a - ld [H_MULTIPLICAND + 1], a - ld a, [wEnemyMonActualCatchRate] - ld [H_MULTIPLICAND + 2], a - ld a, 100 - ld [H_MULTIPLIER], a - call Multiply - -; Determine BallFactor2. -; Poké Ball: BallFactor2 = 255 -; Great Ball: BallFactor2 = 200 -; Ultra/Safari Ball: BallFactor2 = 150 - ld a, [wcf91] - ld b, 255 - cp POKE_BALL - jr z, .skip4 - ld b, 200 - cp GREAT_BALL - jr z, .skip4 - ld b, 150 - cp ULTRA_BALL - jr z, .skip4 - -.skip4 -; Let Y = (CatchRate * 100) / BallFactor2. Calculate Y. - ld a, b - ld [H_DIVISOR], a - ld b, 4 - call Divide - -; If Y > 255, there are 3 shakes. -; Note that this shouldn't be possible. -; The maximum value of Y is (255 * 100) / 150 = 170. - ld a, [H_QUOTIENT + 2] - and a - ld b, $63 ; 3 shakes - jr nz, .setAnimData - -; Calculate X * Y. - ld a, [wPokeBallCaptureCalcTemp] - ld [H_MULTIPLIER], a - call Multiply - -; Calculate (X * Y) / 255. - ld a, 255 - ld [H_DIVISOR], a - ld b, 4 - call Divide - -; Determine Status2. -; no status ailment: Status2 = 0 -; Burn/Paralysis/Poison: Status2 = 5 -; Freeze/Sleep: Status2 = 10 - ld a, [wEnemyMonStatus] - and a - jr z, .skip5 - and 1 << FRZ | SLP - ld b, 5 - jr z, .addAilmentValue - ld b, 10 - -.addAilmentValue -; If the Pokémon has a status ailment, add Status2. - ld a, [H_QUOTIENT + 3] - add b - ld [H_QUOTIENT + 3], a - -.skip5 -; Finally determine the number of shakes. -; Let Z = ((X * Y) / 255) + Status2 = [H_QUOTIENT + 3]. -; The number of shakes depend on the range Z is in. -; 0 ≤ Z < 10: 0 shakes (the ball misses) -; 10 ≤ Z < 30: 1 shake -; 30 ≤ Z < 70: 2 shakes -; 70 ≤ Z: 3 shakes - ld a, [H_QUOTIENT + 3] - cp 10 - ld b, $20 - jr c, .setAnimData - cp 30 - ld b, $61 - jr c, .setAnimData - cp 70 - ld b, $62 - jr c, .setAnimData - ld b, $63 - -.setAnimData - ld a, b - ld [wPokeBallAnimData], a - -.skipShakeCalculations - ld c, 20 - call DelayFrames - -; Do the animation. - ld a, TOSS_ANIM - ld [wAnimationID], a - xor a - ld [H_WHOSETURN], a - ld [wAnimationType], a - ld [wDamageMultipliers], a - ld a, [wWhichPokemon] - push af - ld a, [wcf91] - push af - predef MoveAnimation - pop af - ld [wcf91], a - pop af - ld [wWhichPokemon], a - -; Determine the message to display from the animation. - ld a, [wPokeBallAnimData] - cp $10 - ld hl, ItemUseBallText00 - jp z, .printMessage - cp $20 - ld hl, ItemUseBallText01 - jp z, .printMessage - cp $61 - ld hl, ItemUseBallText02 - jp z, .printMessage - cp $62 - ld hl, ItemUseBallText03 - jp z, .printMessage - cp $63 - ld hl, ItemUseBallText04 - jp z, .printMessage - -; Save current HP. - ld hl, wEnemyMonHP - ld a, [hli] - push af - ld a, [hli] - push af - -; Save status ailment. - inc hl - ld a, [hl] - push af - - push hl - -; If the Pokémon is transformed, the Pokémon is assumed to be a Ditto. -; This is a bug because a wild Pokémon could have used Transform via -; Mirror Move even though the only wild Pokémon that knows Transform is Ditto. - ld hl, wEnemyBattleStatus3 - bit TRANSFORMED, [hl] - jr z, .notTransformed - ld a, DITTO - ld [wEnemyMonSpecies2], a - jr .skip6 - -.notTransformed -; If the Pokémon is not transformed, set the transformed bit and copy the -; DVs to wTransformedEnemyMonOriginalDVs so that LoadEnemyMonData won't generate -; new DVs. - set TRANSFORMED, [hl] - ld hl, wTransformedEnemyMonOriginalDVs - ld a, [wEnemyMonDVs] - ld [hli], a - ld a, [wEnemyMonDVs + 1] - ld [hl], a - -.skip6 - ld a, [wcf91] - push af - ld a, [wEnemyMonSpecies2] - ld [wcf91], a - ld a, [wEnemyMonLevel] - ld [wCurEnemyLVL], a - callab LoadEnemyMonData - pop af - ld [wcf91], a - pop hl - pop af - ld [hld], a - dec hl - pop af - ld [hld], a - pop af - ld [hl], a - ld a, [wEnemyMonSpecies] - ld [wCapturedMonSpecies], a - 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 - - ld hl, ItemUseBallText05 - call PrintText - -; Add the caught Pokémon to the Pokédex. - predef IndexToPokedex - ld a, [wd11e] - dec a - ld c, a - ld b, FLAG_TEST - ld hl, wPokedexOwned - predef FlagActionPredef - ld a, c - push af - ld a, [wd11e] - dec a - ld c, a - ld b, FLAG_SET - predef FlagActionPredef - pop af - - and a ; was the Pokémon already in the Pokédex? - jr nz, .skipShowingPokedexData ; if so, don't show the Pokédex data - - ld hl, ItemUseBallText06 - call PrintText - call ClearSprites - ld a, [wEnemyMonSpecies] - ld [wd11e], a - predef ShowPokedexData - -.skipShowingPokedexData - ld a, [wPartyCount] - cp PARTY_LENGTH ; is party full? - jr z, .sendToBox - xor a ; PLAYER_PARTY_DATA - ld [wMonDataLocation], a - call ClearSprites - call AddPartyMon - jr .done - -.sendToBox - call ClearSprites - call SendNewMonToBox - ld hl, ItemUseBallText07 - CheckEvent EVENT_MET_BILL - jr nz, .printTransferredToPCText - ld hl, ItemUseBallText08 -.printTransferredToPCText - call PrintText - jr .done - -.oldManCaughtMon - ld hl, ItemUseBallText05 - -.printMessage - call PrintText - call ClearSprites - -.done - ld a, [wBattleType] - and a ; is this the old man battle? - ret nz ; if so, don't remove a ball from the bag - -; Remove a ball from the bag. - ld hl, wNumBagItems - inc a - ld [wItemQuantity], a - jp RemoveItemFromInventory - -ItemUseBallText00: -;"It dodged the thrown ball!" -;"This pokemon can't be caught" - TX_FAR _ItemUseBallText00 - db "@" -ItemUseBallText01: -;"You missed the pokemon!" - TX_FAR _ItemUseBallText01 - db "@" -ItemUseBallText02: -;"Darn! The pokemon broke free!" - TX_FAR _ItemUseBallText02 - db "@" -ItemUseBallText03: -;"Aww! It appeared to be caught!" - TX_FAR _ItemUseBallText03 - db "@" -ItemUseBallText04: -;"Shoot! It was so close too!" - TX_FAR _ItemUseBallText04 - db "@" -ItemUseBallText05: -;"All right! {MonName} was caught!" -;play sound - TX_FAR _ItemUseBallText05 - TX_SFX_CAUGHT_MON - TX_BLINK - db "@" -ItemUseBallText07: -;"X was transferred to Bill's PC" - TX_FAR _ItemUseBallText07 - db "@" -ItemUseBallText08: -;"X was transferred to someone's PC" - TX_FAR _ItemUseBallText08 - db "@" - -ItemUseBallText06: -;"New DEX data will be added..." -;play sound - TX_FAR _ItemUseBallText06 - TX_SFX_DEX_PAGE_ADDED - TX_BLINK - db "@" - -ItemUseTownMap: - ld a, [wIsInBattle] - and a - jp nz, ItemUseNotTime - jpba DisplayTownMap - -ItemUseBicycle: - ld a, [wIsInBattle] - and a - jp nz, ItemUseNotTime - ld a, [wWalkBikeSurfState] - ld [wWalkBikeSurfStateCopy], a - cp 2 ; is the player surfing? - jp z, ItemUseNotTime - dec a ; is player already bicycling? - jr nz, .tryToGetOnBike -.getOffBike - call ItemUseReloadOverworldData - xor a - ld [wWalkBikeSurfState], a ; change player state to walking - call PlayDefaultMusic ; play walking music - ld hl, GotOffBicycleText - jr .printText -.tryToGetOnBike - call IsBikeRidingAllowed - jp nc, NoCyclingAllowedHere - call ItemUseReloadOverworldData - xor a ; no keys pressed - ld [hJoyHeld], a ; current joypad state - inc a - ld [wWalkBikeSurfState], a ; change player state to bicycling - ld hl, GotOnBicycleText - call PlayDefaultMusic ; play bike riding music -.printText - jp PrintText - -; used for Surf out-of-battle effect -ItemUseSurfboard: - ld a, [wWalkBikeSurfState] - ld [wWalkBikeSurfStateCopy], a - cp 2 ; is the player already surfing? - jr z, .tryToStopSurfing -.tryToSurf - call IsNextTileShoreOrWater - jp c, SurfingAttemptFailed - ld hl, TilePairCollisionsWater - call CheckForTilePairCollisions - jp c, SurfingAttemptFailed -.surf - call .makePlayerMoveForward - ld hl, wd730 - set 7, [hl] - ld a, 2 - ld [wWalkBikeSurfState], a ; change player state to surfing - call PlayDefaultMusic ; play surfing music - ld hl, SurfingGotOnText - jp PrintText -.tryToStopSurfing - xor a - ld [hSpriteIndexOrTextID], a - ld d, 16 ; talking range in pixels (normal range) - call IsSpriteInFrontOfPlayer2 - res 7, [hl] - ld a, [hSpriteIndexOrTextID] - and a ; is there a sprite in the way? - jr nz, .cannotStopSurfing - 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 -.cannotStopSurfing - ld hl, SurfingNoPlaceToGetOffText - jp PrintText -.stopSurfing - call .makePlayerMoveForward - ld hl, wd730 - set 7, [hl] - xor a - ld [wWalkBikeSurfState], a ; change player state to walking - dec a - ld [wJoyIgnore], a - call PlayDefaultMusic ; play walking music - jp LoadWalkingPlayerSpriteGraphics -; uses a simulated button press to make the player move forward -.makePlayerMoveForward - ld a, [wPlayerDirection] ; direction the player is going - bit PLAYER_DIR_BIT_UP, a - ld b, D_UP - jr nz, .storeSimulatedButtonPress - bit PLAYER_DIR_BIT_DOWN, a - ld b, D_DOWN - jr nz, .storeSimulatedButtonPress - bit PLAYER_DIR_BIT_LEFT, a - ld b, D_LEFT - jr nz, .storeSimulatedButtonPress - ld b, D_RIGHT -.storeSimulatedButtonPress - ld a, b - ld [wSimulatedJoypadStatesEnd], a - xor a - ld [wWastedByteCD39], a - inc a - ld [wSimulatedJoypadStatesIndex], a - ret - -SurfingGotOnText: - TX_FAR _SurfingGotOnText - db "@" - -SurfingNoPlaceToGetOffText: - TX_FAR _SurfingNoPlaceToGetOffText - db "@" - -ItemUsePokedex: - predef_jump ShowPokedexMenu - -ItemUseEvoStone: - ld a, [wIsInBattle] - and a - jp nz, ItemUseNotTime - ld a, [wWhichPokemon] - push af - ld a, [wcf91] - ld [wEvoStoneItemID], a - push af - ld a, EVO_STONE_PARTY_MENU - ld [wPartyMenuTypeOrMessageID], a - ld a, $ff - ld [wUpdateSpritesEnabled], a - call DisplayPartyMenu - pop bc - jr c, .canceledItemUse - ld a, b - ld [wcf91], a - ld a, $01 - ld [wForceEvolution], a - ld a, SFX_HEAL_AILMENT - call PlaySoundWaitForCurrent - call WaitForSoundToFinish - callab TryEvolvingMon ; try to evolve pokemon - ld a, [wEvolutionOccurred] - and a - jr z, .noEffect - pop af - ld [wWhichPokemon], a - ld hl, wNumBagItems - ld a, 1 ; remove 1 stone - ld [wItemQuantity], a - jp RemoveItemFromInventory -.noEffect - call ItemUseNoEffect -.canceledItemUse - xor a - ld [wActionResultOrTookBattleTurn], a ; item not used - pop af - ret - -ItemUseVitamin: - ld a, [wIsInBattle] - and a - jp nz, ItemUseNotTime - -ItemUseMedicine: - ld a, [wPartyCount] - and a - jp z, .emptyParty - ld a, [wWhichPokemon] - push af - ld a, [wcf91] - push af - ld a, USE_ITEM_PARTY_MENU - ld [wPartyMenuTypeOrMessageID], a - ld a, $ff - ld [wUpdateSpritesEnabled], a - ld a, [wPseudoItemID] - and a ; using Softboiled? - jr z, .notUsingSoftboiled -; 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 - jp c, .canceledItemUse - ld hl, wPartyMons - ld bc, wPartyMon2 - wPartyMon1 - ld a, [wWhichPokemon] - call AddNTimes - ld a, [wWhichPokemon] - ld [wUsedItemOnWhichPokemon], a - ld d, a - ld a, [wcf91] - ld e, a - ld [wd0b5], a - pop af - ld [wcf91], a - pop af - ld [wWhichPokemon], a - ld a, [wPseudoItemID] - and a ; using Softboiled? - jr z, .checkItemType -; if using softboiled - ld a, [wWhichPokemon] - cp d ; is the pokemon trying to use softboiled on itself? - jr z, ItemUseMedicine ; if so, force another choice -.checkItemType - ld a, [wcf91] - cp REVIVE - jr nc, .healHP ; if it's a Revive or Max Revive - cp FULL_HEAL - jr z, .cureStatusAilment ; if it's a Full Heal - cp HP_UP - jp nc, .useVitamin ; if it's a vitamin or Rare Candy - cp FULL_RESTORE - jr nc, .healHP ; if it's a Full Restore or one of the potions -; fall through if it's one of the status-specific healing items -.cureStatusAilment - ld bc, wPartyMon1Status - wPartyMon1 - add hl, bc ; hl now points to status - ld a, [wcf91] - lb bc, ANTIDOTE_MSG, 1 << PSN - cp ANTIDOTE - jr z, .checkMonStatus - lb bc, BURN_HEAL_MSG, 1 << BRN - cp BURN_HEAL - jr z, .checkMonStatus - lb bc, ICE_HEAL_MSG, 1 << FRZ - cp ICE_HEAL - jr z, .checkMonStatus - lb bc, AWAKENING_MSG, SLP - cp AWAKENING - jr z, .checkMonStatus - lb bc, PARALYZ_HEAL_MSG, 1 << PAR - cp PARLYZ_HEAL - jr z, .checkMonStatus - lb bc, FULL_HEAL_MSG, $ff ; Full Heal -.checkMonStatus - ld a, [hl] ; pokemon's status - and c ; does the pokemon have a status ailment the item can cure? - jp z, .healingItemNoEffect -; if the pokemon has a status the item can heal - xor a - ld [hl], a ; remove the status ailment in the party data - ld a, b - ld [wPartyMenuTypeOrMessageID], a ; the message to display for the item used - ld a, [wPlayerMonNumber] - cp d ; is pokemon the item was used on active in battle? - jp nz, .doneHealing -; if it is active in battle - xor a - ld [wBattleMonStatus], a ; remove the status ailment in the in-battle pokemon data - push hl - ld hl, wPlayerBattleStatus3 - res BADLY_POISONED, [hl] ; heal Toxic status - pop hl - ld bc, wPartyMon1Stats - wPartyMon1Status - add hl, bc ; hl now points to party stats - ld de, wBattleMonStats - ld bc, NUM_STATS * 2 - 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] - ld b, a - ld [wHPBarOldHP+1], a - ld a, [hl] - ld c, a - ld [wHPBarOldHP], a ; current HP stored at wHPBarOldHP (2 bytes, big-endian) - or b - jr nz, .notFainted -.fainted - ld a, [wcf91] - cp REVIVE - jr z, .updateInBattleFaintedData - cp MAX_REVIVE - jr z, .updateInBattleFaintedData - jp .healingItemNoEffect -.updateInBattleFaintedData - ld a, [wIsInBattle] - and a - jr z, .compareCurrentHPToMaxHP - push hl - push de - push bc - ld a, [wUsedItemOnWhichPokemon] - ld c, a - ld hl, wPartyFoughtCurrentEnemyFlags - ld b, FLAG_TEST - predef FlagActionPredef - ld a, c - and a - jr z, .next - ld a, [wUsedItemOnWhichPokemon] - ld c, a - ld hl, wPartyGainExpFlags - ld b, FLAG_SET - predef FlagActionPredef -.next - pop bc - pop de - pop hl - jr .compareCurrentHPToMaxHP -.notFainted - ld a, [wcf91] - cp REVIVE - jp z, .healingItemNoEffect - cp MAX_REVIVE - jp z, .healingItemNoEffect -.compareCurrentHPToMaxHP - push hl - push bc - ld bc, wPartyMon1MaxHP - (wPartyMon1HP + 1) - add hl, bc ; hl now points to max HP - pop bc - ld a, [hli] - cp b - jr nz, .skipComparingLSB ; no need to compare the LSB's if the MSB's don't match - ld a, [hl] - cp c -.skipComparingLSB - pop hl - jr nz, .notFullHP -.fullHP ; if the pokemon's current HP equals its max HP - ld a, [wcf91] - cp FULL_RESTORE - jp nz, .healingItemNoEffect - inc hl - inc hl - ld a, [hld] ; status ailment - and a ; does the pokemon have a status ailment? - jp z, .healingItemNoEffect - ld a, FULL_HEAL - ld [wcf91], a - dec hl - 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 - ld [wChannelSoundIDs + Ch5], a - push hl - push de - ld bc, wPartyMon1MaxHP - (wPartyMon1HP + 1) - add hl, bc ; hl now points to max HP - ld a, [hli] - ld [wHPBarMaxHP+1], a - ld a, [hl] - ld [wHPBarMaxHP], a ; max HP stored at wHPBarMaxHP (2 bytes, big-endian) - ld a, [wPseudoItemID] - and a ; using Softboiled? - jp z, .notUsingSoftboiled2 -; if using softboiled - ld hl, wHPBarMaxHP - ld a, [hli] - push af - ld a, [hli] - push af - ld a, [hli] - push af - ld a, [hl] - push af - ld hl, wPartyMon1MaxHP - ld a, [wWhichPokemon] - ld bc, wPartyMon2 - wPartyMon1 - call AddNTimes - ld a, [hli] - ld [wHPBarMaxHP + 1], a - ld [H_DIVIDEND], a - ld a, [hl] - ld [wHPBarMaxHP], a - ld [H_DIVIDEND + 1], a - ld a, 5 - ld [H_DIVISOR], a - ld b, 2 ; number of bytes - call Divide ; get 1/5 of max HP of pokemon that used Softboiled - ld bc, (wPartyMon1HP + 1) - (wPartyMon1MaxHP + 1) - add hl, bc ; hl now points to LSB of current HP of pokemon that used Softboiled -; subtract 1/5 of max HP from current HP of pokemon that used Softboiled - ld a, [H_QUOTIENT + 3] - push af - ld b, a - ld a, [hl] - ld [wHPBarOldHP], a - sub b - ld [hld], a - ld [wHPBarNewHP], a - ld a, [H_QUOTIENT + 2] - ld b, a - ld a, [hl] - ld [wHPBarOldHP+1], a - sbc b - ld [hl], a - ld [wHPBarNewHP+1], a - coord hl, 4, 1 - ld a, [wWhichPokemon] - ld bc, 2 * SCREEN_WIDTH - call AddNTimes ; calculate coordinates of HP bar of pokemon that used Softboiled - ld a, SFX_HEAL_HP - call PlaySoundWaitForCurrent - ld a, [hFlags_0xFFF6] - set 0, a - ld [hFlags_0xFFF6], a - ld a, $02 - ld [wHPBarType], a - predef UpdateHPBar2 ; animate HP bar decrease of pokemon that used Softboiled - ld a, [hFlags_0xFFF6] - res 0, a - ld [hFlags_0xFFF6], a - pop af - ld b, a ; store heal amount (1/5 of max HP) - ld hl, wHPBarOldHP + 1 - pop af - ld [hld], a - pop af - ld [hld], a - pop af - ld [hld], a - pop af - ld [hl], a - jr .addHealAmount -.notUsingSoftboiled2 - ld a, [wcf91] - cp SODA_POP - ld b, 60 ; Soda Pop heal amount - jr z, .addHealAmount - ld b, 80 ; Lemonade heal amount - jr nc, .addHealAmount - cp FRESH_WATER - ld b, 50 ; Fresh Water heal amount - jr z, .addHealAmount - cp SUPER_POTION - ld b, 200 ; Hyper Potion heal amount - jr c, .addHealAmount - ld b, 50 ; Super Potion heal amount - jr z, .addHealAmount - ld b, 20 ; Potion heal amount -.addHealAmount - pop de - pop hl - ld a, [hl] - add b - ld [hld], a - ld [wHPBarNewHP], a - ld a, [hl] - ld [wHPBarNewHP+1], a - jr nc, .noCarry - inc [hl] - ld a, [hl] - ld [wHPBarNewHP + 1], a -.noCarry - push de - inc hl - ld d, h - ld e, l ; de now points to current HP - ld hl, (wPartyMon1MaxHP + 1) - (wPartyMon1HP + 1) - add hl, de ; hl now points to max HP - ld a, [wcf91] - cp REVIVE - jr z, .setCurrentHPToHalfMaxHP - ld a, [hld] - ld b, a - ld a, [de] - sub b - dec de - ld b, [hl] - ld a, [de] - sbc b - jr nc, .setCurrentHPToMaxHp ; if current HP exceeds max HP after healing - ld a, [wcf91] - cp HYPER_POTION - jr c, .setCurrentHPToMaxHp ; if using a Full Restore or Max Potion - cp MAX_REVIVE - jr z, .setCurrentHPToMaxHp ; if using a Max Revive - jr .updateInBattleData -.setCurrentHPToHalfMaxHP - dec hl - dec de - ld a, [hli] - srl a - ld [de], a - ld [wHPBarNewHP+1], a - ld a, [hl] - rr a - inc de - ld [de], a - ld [wHPBarNewHP], a - dec de - jr .doneHealingPartyHP -.setCurrentHPToMaxHp - ld a, [hli] - ld [de], a - ld [wHPBarNewHP+1], a - inc de - ld a, [hl] - ld [de], a - ld [wHPBarNewHP], a - dec de -.doneHealingPartyHP ; done updating the pokemon's current HP in the party data structure - ld a, [wcf91] - cp FULL_RESTORE - jr nz, .updateInBattleData - ld bc, wPartyMon1Status - (wPartyMon1MaxHP + 1) - add hl, bc - xor a - ld [hl], a ; remove the status ailment in the party data -.updateInBattleData - ld h, d - ld l, e - pop de - ld a, [wPlayerMonNumber] - cp d ; is pokemon the item was used on active in battle? - jr nz, .calculateHPBarCoords -; copy party HP to in-battle HP - ld a, [hli] - ld [wBattleMonHP], a - ld a, [hld] - ld [wBattleMonHP + 1], a - ld a, [wcf91] - cp FULL_RESTORE - jr nz, .calculateHPBarCoords - xor a - ld [wBattleMonStatus], a ; remove the status ailment in the in-battle pokemon data -.calculateHPBarCoords - ld hl, wOAMBuffer + $90 - ld bc, 2 * SCREEN_WIDTH - inc d -.calculateHPBarCoordsLoop - add hl, bc - dec d - jr nz, .calculateHPBarCoordsLoop - jr .doneHealing -.healingItemNoEffect - call ItemUseNoEffect - jp .done -.doneHealing - ld a, [wPseudoItemID] - and a ; using Softboiled? - jr nz, .skipRemovingItem ; no item to remove if using Softboiled - push hl - call RemoveUsedItem - pop hl -.skipRemovingItem - ld a, [wcf91] - cp FULL_RESTORE - jr c, .playStatusAilmentCuringSound - cp FULL_HEAL - jr z, .playStatusAilmentCuringSound - ld a, SFX_HEAL_HP - call PlaySoundWaitForCurrent - ld a, [hFlags_0xFFF6] - set 0, a - ld [hFlags_0xFFF6], a - ld a, $02 - ld [wHPBarType], a - predef UpdateHPBar2 ; animate the HP bar lengthening - ld a, [hFlags_0xFFF6] - res 0, a - ld [hFlags_0xFFF6], a - ld a, REVIVE_MSG - ld [wPartyMenuTypeOrMessageID], a - ld a, [wcf91] - cp REVIVE - jr z, .showHealingItemMessage - cp MAX_REVIVE - jr z, .showHealingItemMessage - ld a, POTION_MSG - ld [wPartyMenuTypeOrMessageID], a - jr .showHealingItemMessage -.playStatusAilmentCuringSound - ld a, SFX_HEAL_AILMENT - call PlaySoundWaitForCurrent -.showHealingItemMessage - xor a - ld [H_AUTOBGTRANSFERENABLED], a - call ClearScreen - dec a - ld [wUpdateSpritesEnabled], a - call RedrawPartyMenu ; redraws the party menu and displays the message - ld a, 1 - ld [H_AUTOBGTRANSFERENABLED], a - ld c, 50 - call DelayFrames - call WaitForTextScrollButtonPress - jr .done -.canceledItemUse - xor a - ld [wActionResultOrTookBattleTurn], a ; item use failed - pop af - pop af -.done - ld a, [wPseudoItemID] - and a ; using Softboiled? - ret nz ; if so, return - call GBPalWhiteOut - call z, RunDefaultPaletteCommand - ld a, [wIsInBattle] - and a - ret nz - jp ReloadMapData -.useVitamin - push hl - ld a, [hl] - ld [wd0b5], a - ld [wd11e], a - ld bc, wPartyMon1Level - wPartyMon1 - add hl, bc ; hl now points to level - ld a, [hl] ; a = level - ld [wCurEnemyLVL], a ; store level - call GetMonHeader - push de - ld a, d - ld hl, wPartyMonNicks - call GetPartyMonName - pop de - pop hl - ld a, [wcf91] - cp RARE_CANDY - jp z, .useRareCandy - push hl - sub HP_UP - add a - ld bc, wPartyMon1HPExp - wPartyMon1 - add hl, bc - add l - ld l, a - jr nc, .noCarry2 - inc h -.noCarry2 - ld a, 10 - ld b, a - ld a, [hl] ; a = MSB of stat experience of the appropriate stat - cp 100 ; is there already at least 25600 (256 * 100) stat experience? - jr nc, .vitaminNoEffect ; if so, vitamins can't add any more - add b ; add 2560 (256 * 10) stat experience - jr nc, .noCarry3 ; a carry should be impossible here, so this will always jump - ld a, 255 -.noCarry3 - ld [hl], a - pop hl - call .recalculateStats - ld hl, VitaminText - ld a, [wcf91] - sub HP_UP - 1 - ld c, a -.statNameLoop ; loop to get the address of the name of the stat the vitamin increases - dec c - jr z, .gotStatName -.statNameInnerLoop - ld a, [hli] - ld b, a - ld a, $50 - cp b - jr nz, .statNameInnerLoop - jr .statNameLoop -.gotStatName - ld de, wcf4b - ld bc, 10 - call CopyData ; copy the stat's name to wcf4b - ld a, SFX_HEAL_AILMENT - call PlaySound - 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 - ld d, h - ld e, l ; de now points to stats - ld bc, (wPartyMon1Exp + 2) - wPartyMon1Stats - add hl, bc ; hl now points to LSB of experience - ld b, 1 - jp CalcStats ; recalculate stats -.useRareCandy - push hl - ld bc, wPartyMon1Level - wPartyMon1 - add hl, bc ; hl now points to level - ld a, [hl] ; a = level - cp MAX_LEVEL - jr z, .vitaminNoEffect ; can't raise level above 100 - inc a - ld [hl], a ; store incremented level - ld [wCurEnemyLVL], a - push hl - push de - ld d, a - callab CalcExperience ; calculate experience for next level and store it at $ff96 - pop de - pop hl - ld bc, wPartyMon1Exp - wPartyMon1Level - add hl, bc ; hl now points to MSB of experience -; update experience to minimum for new level - ld a, [hExperience] - ld [hli], a - ld a, [hExperience + 1] - ld [hli], a - ld a, [hExperience + 2] - ld [hl], a - pop hl - ld a, [wWhichPokemon] - push af - ld a, [wcf91] - push af - push de - push hl - ld bc, wPartyMon1MaxHP - wPartyMon1 - add hl, bc ; hl now points to MSB of max HP - ld a, [hli] - ld b, a - ld c, [hl] - pop hl - push bc - push hl - call .recalculateStats - pop hl - ld bc, (wPartyMon1MaxHP + 1) - wPartyMon1 - add hl, bc ; hl now points to LSB of max HP - pop bc - ld a, [hld] - sub c - ld c, a - ld a, [hl] - sbc b - ld b, a ; bc = the amount of max HP gained from leveling up -; add the amount gained to the current HP - ld de, (wPartyMon1HP + 1) - wPartyMon1MaxHP - add hl, de ; hl now points to LSB of current HP - ld a, [hl] - add c - ld [hld], a - ld a, [hl] - adc b - ld [hl], a - ld a, RARE_CANDY_MSG - ld [wPartyMenuTypeOrMessageID], a - call RedrawPartyMenu - pop de - ld a, d - ld [wWhichPokemon], a - ld a, e - ld [wd11e], a - xor a ; PLAYER_PARTY_DATA - ld [wMonDataLocation], a - call LoadMonData - ld d, $01 - callab PrintStatsBox ; display new stats text box - call WaitForTextScrollButtonPress ; wait for button press - xor a ; PLAYER_PARTY_DATA - ld [wMonDataLocation], a - predef LearnMoveFromLevelUp ; learn level up move, if any - xor a - ld [wForceEvolution], a - callab TryEvolvingMon ; evolve pokemon, if appropriate - ld a, $01 - ld [wUpdateSpritesEnabled], a - pop af - ld [wcf91], a - pop af - ld [wWhichPokemon], a - jp RemoveUsedItem - -VitaminStatRoseText: - TX_FAR _VitaminStatRoseText - db "@" - -VitaminNoEffectText: - TX_FAR _VitaminNoEffectText - db "@" - -VitaminText: - db "HEALTH@" - db "ATTACK@" - db "DEFENSE@" - db "SPEED@" - db "SPECIAL@" - -ItemUseBait: - ld hl, ThrewBaitText - call PrintText - ld hl, wEnemyMonActualCatchRate ; catch rate - srl [hl] ; halve catch rate - ld a, BAIT_ANIM - ld hl, wSafariBaitFactor ; bait factor - ld de, wSafariEscapeFactor ; escape factor - jr BaitRockCommon - -ItemUseRock: - ld hl, ThrewRockText - call PrintText - ld hl, wEnemyMonActualCatchRate ; catch rate - ld a, [hl] - add a ; double catch rate - jr nc, .noCarry - ld a, $ff -.noCarry - ld [hl], a - ld a, ROCK_ANIM - ld hl, wSafariEscapeFactor ; escape factor - ld de, wSafariBaitFactor ; bait factor - -BaitRockCommon: - ld [wAnimationID], a - xor a - ld [wAnimationType], a - ld [H_WHOSETURN], a - ld [de], a ; zero escape factor (for bait), zero bait factor (for rock) -.randomLoop ; loop until a random number less than 5 is generated - call Random - and 7 - cp 5 - jr nc, .randomLoop - inc a ; increment the random number, giving a range from 1 to 5 inclusive - ld b, a - ld a, [hl] - add b ; increase bait factor (for bait), increase escape factor (for rock) - jr nc, .noCarry - ld a, $ff -.noCarry - ld [hl], a - predef MoveAnimation ; do animation - ld c, 70 - jp DelayFrames - -ThrewBaitText: - TX_FAR _ThrewBaitText - db "@" - -ThrewRockText: - TX_FAR _ThrewRockText - db "@" - -; also used for Dig out-of-battle effect -ItemUseEscapeRope: - ld a, [wIsInBattle] - and a - jr nz, .notUsable - ld a, [wCurMap] - cp AGATHAS_ROOM - jr z, .notUsable - ld a, [wCurMapTileset] - ld b, a - ld hl, EscapeRopeTilesets -.loop - ld a, [hli] - cp $ff - jr z, .notUsable - cp b - jr nz, .loop - ld hl, wd732 - set 3, [hl] - set 6, [hl] - ld hl, wd72e - res 4, [hl] - ResetEvent EVENT_IN_SAFARI_ZONE - xor a - ld [wNumSafariBalls], a - ld [wSafariZoneGateCurScript], a - inc a - ld [wEscapedFromBattle], a - ld [wActionResultOrTookBattleTurn], a ; item used - ld a, [wPseudoItemID] - and a ; using Dig? - ret nz ; if so, return - call ItemUseReloadOverworldData - ld c, 30 - call DelayFrames - jp RemoveUsedItem -.notUsable - jp ItemUseNotTime - -EscapeRopeTilesets: - db FOREST, CEMETERY, CAVERN, FACILITY, INTERIOR - db $ff ; terminator - -ItemUseRepel: - ld b, 100 - -ItemUseRepelCommon: - ld a, [wIsInBattle] - and a - jp nz, ItemUseNotTime - ld a, b - ld [wRepelRemainingSteps], a - jp PrintItemUseTextAndRemoveItem - -; handles X Accuracy item -ItemUseXAccuracy: - ld a, [wIsInBattle] - and a - jp z, ItemUseNotTime - ld hl, wPlayerBattleStatus2 - set USING_X_ACCURACY, [hl] ; X Accuracy bit - jp PrintItemUseTextAndRemoveItem - -; This function is bugged and never works. It always jumps to ItemUseNotTime. -; The Card Key is handled in a different way. -ItemUseCardKey: - xor a - ld [wUnusedD71F], a - call GetTileAndCoordsInFrontOfPlayer - ld a, [GetTileAndCoordsInFrontOfPlayer] - cp $18 - 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 - ld hl, CardKeyTable3 -.next1 - ld a, [wCurMap] - ld b, a -.loop - ld a, [hli] - cp $ff - jp z, ItemUseNotTime - cp b - jr nz, .nextEntry1 - ld a, [hli] - cp d - jr nz, .nextEntry2 - ld a, [hli] - cp e - jr nz, .nextEntry3 - ld a, [hl] - ld [wUnusedD71F], a - jr .done -.nextEntry1 - inc hl -.nextEntry2 - inc hl -.nextEntry3 - inc hl - jr .loop -.done - ld hl, ItemUseText00 - call PrintText - ld hl, wd728 - set 7, [hl] - ret - -; These tables are probably supposed to be door locations in Silph Co., -; but they are unused. -; The reason there are 3 tables is unknown. - -; Format: -; 00: Map ID -; 01: Y -; 02: X -; 03: ID? - -CardKeyTable1: - db SILPH_CO_2F,$04,$04,$00 - db SILPH_CO_2F,$04,$05,$01 - db SILPH_CO_4F,$0C,$04,$02 - db SILPH_CO_4F,$0C,$05,$03 - db SILPH_CO_7F,$06,$0A,$04 - db SILPH_CO_7F,$06,$0B,$05 - db SILPH_CO_9F,$04,$12,$06 - db SILPH_CO_9F,$04,$13,$07 - db SILPH_CO_10F,$08,$0A,$08 - db SILPH_CO_10F,$08,$0B,$09 - db $ff - -CardKeyTable2: - db SILPH_CO_3F,$08,$09,$0A - db SILPH_CO_3F,$09,$09,$0B - db SILPH_CO_5F,$04,$07,$0C - db SILPH_CO_5F,$05,$07,$0D - db SILPH_CO_6F,$0C,$05,$0E - db SILPH_CO_6F,$0D,$05,$0F - db SILPH_CO_8F,$08,$07,$10 - db SILPH_CO_8F,$09,$07,$11 - db SILPH_CO_9F,$08,$03,$12 - db SILPH_CO_9F,$09,$03,$13 - db $ff - -CardKeyTable3: - db SILPH_CO_11F,$08,$09,$14 - db SILPH_CO_11F,$09,$09,$15 - db $ff - -ItemUsePokedoll: - ld a, [wIsInBattle] - dec a - jp nz, ItemUseNotTime - ld a, $01 - ld [wEscapedFromBattle], a - jp PrintItemUseTextAndRemoveItem - -ItemUseGuardSpec: - ld a, [wIsInBattle] - and a - jp z, ItemUseNotTime - ld hl, wPlayerBattleStatus2 - set PROTECTED_BY_MIST, [hl] ; Mist bit - jp PrintItemUseTextAndRemoveItem - -ItemUseSuperRepel: - ld b, 200 - jp ItemUseRepelCommon - -ItemUseMaxRepel: - ld b, 250 - jp ItemUseRepelCommon - -ItemUseDireHit: - ld a, [wIsInBattle] - and a - jp z, ItemUseNotTime - ld hl, wPlayerBattleStatus2 - set GETTING_PUMPED, [hl] ; Focus Energy bit - jp PrintItemUseTextAndRemoveItem - -ItemUseXStat: - ld a, [wIsInBattle] - and a - jr nz, .inBattle - call ItemUseNotTime - ld a, 2 - ld [wActionResultOrTookBattleTurn], a ; item not used - ret -.inBattle - ld hl, wPlayerMoveNum - ld a, [hli] - push af ; save [wPlayerMoveNum] - ld a, [hl] - push af ; save [wPlayerMoveEffect] - push hl - ld a, [wcf91] - sub X_ATTACK - ATTACK_UP1_EFFECT - ld [hl], a ; store player move effect - call PrintItemUseTextAndRemoveItem - ld a, XSTATITEM_ANIM ; X stat item animation ID - ld [wPlayerMoveNum], a - call LoadScreenTilesFromBuffer1 ; restore saved screen - call Delay3 - xor a - ld [H_WHOSETURN], a ; set turn to player's turn - callba StatModifierUpEffect ; do stat increase move - pop hl - pop af - ld [hld], a ; restore [wPlayerMoveEffect] - pop af - ld [hl], a ; restore [wPlayerMoveNum] - ret - -ItemUsePokeflute: - ld a, [wIsInBattle] - and a - jr nz, .inBattle -; if not in battle - call ItemUseReloadOverworldData - ld a, [wCurMap] - cp ROUTE_12 - jr nz, .notRoute12 - CheckEvent EVENT_BEAT_ROUTE12_SNORLAX - jr nz, .noSnorlaxToWakeUp -; if the player hasn't beaten Route 12 Snorlax - ld hl, Route12SnorlaxFluteCoords - call ArePlayerCoordsInArray - jr nc, .noSnorlaxToWakeUp - ld hl, PlayedFluteHadEffectText - call PrintText - SetEvent EVENT_FIGHT_ROUTE12_SNORLAX - ret -.notRoute12 - cp ROUTE_16 - jr nz, .noSnorlaxToWakeUp - CheckEvent EVENT_BEAT_ROUTE16_SNORLAX - jr nz, .noSnorlaxToWakeUp -; if the player hasn't beaten Route 16 Snorlax - ld hl, Route16SnorlaxFluteCoords - call ArePlayerCoordsInArray - jr nc, .noSnorlaxToWakeUp - ld hl, PlayedFluteHadEffectText - call PrintText - SetEvent EVENT_FIGHT_ROUTE16_SNORLAX - ret -.noSnorlaxToWakeUp - ld hl, PlayedFluteNoEffectText - jp PrintText -.inBattle - xor a - ld [wWereAnyMonsAsleep], a - ld b, ~SLP & $ff - ld hl, wPartyMon1Status - call WakeUpEntireParty - ld a, [wIsInBattle] - dec a ; is it a trainer battle? - jr z, .skipWakingUpEnemyParty -; if it's a trainer battle - ld hl, wEnemyMon1Status - call WakeUpEntireParty -.skipWakingUpEnemyParty - ld hl, wBattleMonStatus - ld a, [hl] - and b ; remove Sleep status - ld [hl], a - ld hl, wEnemyMonStatus - ld a, [hl] - and b ; remove Sleep status - ld [hl], a - call LoadScreenTilesFromBuffer2 ; restore saved screen - ld a, [wWereAnyMonsAsleep] - and a ; were any pokemon asleep before playing the flute? - ld hl, PlayedFluteNoEffectText - jp z, PrintText ; if no pokemon were asleep -; if some pokemon were asleep - ld hl, PlayedFluteHadEffectText - call PrintText - ld a, [wLowHealthAlarm] - and $80 - jr nz, .skipMusic - call WaitForSoundToFinish ; wait for sound to end - callba Music_PokeFluteInBattle ; play in-battle pokeflute music -.musicWaitLoop ; wait for music to finish playing - ld a, [wChannelSoundIDs + Ch7] - and a ; music off? - jr nz, .musicWaitLoop -.skipMusic - ld hl, FluteWokeUpText - jp PrintText - -; wakes up all party pokemon -; INPUT: -; hl must point to status of first pokemon in party (player's or enemy's) -; b must equal ~SLP -; [wWereAnyMonsAsleep] should be initialized to 0 -; OUTPUT: -; [wWereAnyMonsAsleep]: set to 1 if any pokemon were asleep -WakeUpEntireParty: - ld de, 44 - ld c, 6 -.loop - ld a, [hl] - push af - and SLP ; is pokemon asleep? - jr z, .notAsleep - ld a, 1 - ld [wWereAnyMonsAsleep], a ; indicate that a pokemon had to be woken up -.notAsleep - pop af - and b ; remove Sleep status - ld [hl], a - add hl, de - dec c - jr nz, .loop - ret - -; Format: -; 00: Y -; 01: X -Route12SnorlaxFluteCoords: - db 62,9 ; one space West of Snorlax - db 61,10 ; one space North of Snorlax - db 63,10 ; one space South of Snorlax - db 62,11 ; one space East of Snorlax - db $ff ; terminator - -; Format: -; 00: Y -; 01: X -Route16SnorlaxFluteCoords: - db 10,27 ; one space East of Snorlax - db 10,25 ; one space West of Snorlax - db $ff ; terminator - -PlayedFluteNoEffectText: - TX_FAR _PlayedFluteNoEffectText - db "@" - -FluteWokeUpText: - TX_FAR _FluteWokeUpText - db "@" - -PlayedFluteHadEffectText: - TX_FAR _PlayedFluteHadEffectText - TX_BLINK - TX_ASM - ld a, [wIsInBattle] - and a - jr nz, .done -; play out-of-battle pokeflute music - ld a, $ff - call PlaySound ; turn off music - ld a, SFX_POKEFLUTE - ld c, BANK(SFX_Pokeflute) - call PlayMusic -.musicWaitLoop ; wait for music to finish playing - ld a, [wChannelSoundIDs + Ch3] - cp SFX_POKEFLUTE - jr z, .musicWaitLoop - call PlayDefaultMusic ; start playing normal music again -.done - jp TextScriptEnd ; end text - -ItemUseCoinCase: - ld a, [wIsInBattle] - and a - jp nz, ItemUseNotTime - ld hl, CoinCaseNumCoinsText - jp PrintText - -CoinCaseNumCoinsText: - TX_FAR _CoinCaseNumCoinsText - db "@" - -ItemUseOldRod: - call FishingInit - jp c, ItemUseNotTime - lb bc, 5, MAGIKARP - ld a, $1 ; set bite - jr RodResponse - -ItemUseGoodRod: - call FishingInit - jp c, ItemUseNotTime -.RandomLoop - call Random - srl a - jr c, .SetBite - and %11 - cp 2 - jr nc, .RandomLoop - ; choose which monster appears - ld hl, GoodRodMons - add a - ld c, a - ld b, 0 - add hl, bc - ld b, [hl] - inc hl - ld c, [hl] - and a -.SetBite - ld a, 0 - rla - xor 1 - jr RodResponse - -INCLUDE "data/good_rod.asm" - -ItemUseSuperRod: - call FishingInit - jp c, ItemUseNotTime - call ReadSuperRodData - ld a, e -RodResponse: - ld [wRodResponse], a - - dec a ; is there a bite? - jr nz, .next - ; if yes, store level and species data - ld a, 1 - ld [wMoveMissed], a - ld a, b ; level - ld [wCurEnemyLVL], a - ld a, c ; species - ld [wCurOpponent], a - -.next - ld hl, wWalkBikeSurfState - ld a, [hl] ; store the value in a - push af - push hl - ld [hl], 0 - callba FishingAnim - pop hl - pop af - ld [hl], a - ret - -; checks if fishing is possible and if so, runs initialization code common to all rods -; unsets carry if fishing is possible, sets carry if not -FishingInit: - ld a, [wIsInBattle] - and a - jr z, .notInBattle - scf ; can't fish during battle - ret -.notInBattle - call IsNextTileShoreOrWater - ret c - ld a, [wWalkBikeSurfState] - cp 2 ; Surfing? - jr z, .surfing - call ItemUseReloadOverworldData - ld hl, ItemUseText00 - call PrintText - ld a, SFX_HEAL_AILMENT - call PlaySound - ld c, 80 - call DelayFrames - and a - ret -.surfing - scf ; can't fish when surfing - ret - -ItemUseOaksParcel: - jp ItemUseNotYoursToUse - -ItemUseItemfinder: - ld a, [wIsInBattle] - and a - jp nz, ItemUseNotTime - call ItemUseReloadOverworldData - callba HiddenItemNear ; check for hidden items - ld hl, ItemfinderFoundNothingText - jr nc, .printText ; if no hidden items - ld c, 4 -.loop - ld a, SFX_HEALING_MACHINE - call PlaySoundWaitForCurrent - ld a, SFX_PURCHASE - call PlaySoundWaitForCurrent - dec c - jr nz, .loop - ld hl, ItemfinderFoundItemText -.printText - jp PrintText - -ItemfinderFoundItemText: - TX_FAR _ItemfinderFoundItemText - db "@" - -ItemfinderFoundNothingText: - TX_FAR _ItemfinderFoundNothingText - db "@" - -ItemUsePPUp: - ld a, [wIsInBattle] - and a - jp nz, ItemUseNotTime - -ItemUsePPRestore: - ld a, [wWhichPokemon] - push af - ld a, [wcf91] - ld [wPPRestoreItem], a -.chooseMon - xor a - ld [wUpdateSpritesEnabled], a - ld a, USE_ITEM_PARTY_MENU - ld [wPartyMenuTypeOrMessageID], a - call DisplayPartyMenu - jr nc, .chooseMove - jp .itemNotUsed -.chooseMove - ld a, [wPPRestoreItem] - cp ELIXER - jp nc, .useElixir ; if Elixir or Max Elixir - ld a, $02 - ld [wMoveMenuType], a - ld hl, RaisePPWhichTechniqueText - ld a, [wPPRestoreItem] - cp ETHER ; is it a PP Up? - jr c, .printWhichTechniqueMessage ; if so, print the raise PP message - ld hl, RestorePPWhichTechniqueText ; otherwise, print the restore PP message -.printWhichTechniqueMessage - call PrintText - xor a - ld [wPlayerMoveListIndex], a - callab MoveSelectionMenu ; move selection menu - ld a, 0 - ld [wPlayerMoveListIndex], a - jr nz, .chooseMon - ld hl, wPartyMon1Moves - ld bc, wPartyMon2 - wPartyMon1 - call GetSelectedMoveOffset - push hl - ld a, [hl] - ld [wd11e], a - call GetMoveName - call CopyStringToCF4B ; copy name to wcf4b - pop hl - ld a, [wPPRestoreItem] - cp ETHER - jr nc, .useEther ; if Ether or Max Ether -.usePPUp - ld bc, wPartyMon1PP - wPartyMon1Moves - add hl, bc - ld a, [hl] ; move PP - cp 3 << 6 ; have 3 PP Ups already been used? - jr c, .PPNotMaxedOut - ld hl, PPMaxedOutText - call PrintText - jr .chooseMove -.PPNotMaxedOut - ld a, [hl] - add 1 << 6 ; increase PP Up count by 1 - ld [hl], a - ld a, 1 ; 1 PP Up used - ld [wd11e], a - call RestoreBonusPP ; add the bonus PP to current PP - ld hl, PPIncreasedText - call PrintText -.done - pop af - ld [wWhichPokemon], a - call GBPalWhiteOut - call RunDefaultPaletteCommand - jp RemoveUsedItem -.afterRestoringPP ; after using a (Max) Ether/Elixir - ld a, [wWhichPokemon] - ld b, a - ld a, [wPlayerMonNumber] - cp b ; is the pokemon whose PP was restored active in battle? - jr nz, .skipUpdatingInBattleData - ld hl, wPartyMon1PP - ld bc, wPartyMon2 - wPartyMon1 - call AddNTimes - ld de, wBattleMonPP - ld bc, 4 - call CopyData ; copy party data to in-battle data -.skipUpdatingInBattleData - ld a, SFX_HEAL_AILMENT - call PlaySound - 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 - xor a ; PLAYER_PARTY_DATA - ld [wMonDataLocation], a - call GetMaxPP - ld hl, wPartyMon1Moves - ld bc, wPartyMon2 - wPartyMon1 - call GetSelectedMoveOffset - ld bc, wPartyMon1PP - wPartyMon1Moves - add hl, bc ; hl now points to move's PP - ld a, [wMaxPP] - ld b, a - ld a, [wPPRestoreItem] - cp MAX_ETHER - jr z, .fullyRestorePP - ld a, [hl] ; move PP - and %00111111 ; lower 6 bit bits store current PP - cp b ; does current PP equal max PP? - ret z ; if so, return - add 10 ; increase current PP by 10 -; b holds the max PP amount and b will hold the new PP amount. -; So, if the new amount meets or exceeds the max amount, -; cap the amount to the max amount by leaving b unchanged. -; Otherwise, store the new amount in b. - cp b ; does the new amount meet or exceed the maximum? - jr nc, .storeNewAmount - ld b, a -.storeNewAmount - ld a, [hl] ; move PP - and %11000000 ; PP Up counter bits - 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 -; are used to count how many PP Ups have been used on the move. So, Max Ethers -; and Max Elixirs will not be detected as having no effect on a move with full -; PP if the move has had any PP Ups used on it. - 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 - dec [hl] - dec [hl] - xor a - ld hl, wCurrentMenuItem - ld [hli], a - ld [hl], a ; zero the counter for number of moves that had their PP restored - ld b, 4 -; loop through each move and restore PP -.elixirLoop - push bc - ld hl, wPartyMon1Moves - ld bc, wPartyMon2 - wPartyMon1 - call GetSelectedMoveOffset - ld a, [hl] - and a ; does the current slot have a move? - jr z, .nextMove - call .restorePP - jr z, .nextMove -; if some PP was restored - ld hl, wTileBehindCursor ; counter for number of moves that had their PP restored - inc [hl] -.nextMove - ld hl, wCurrentMenuItem - inc [hl] - pop bc - dec b - jr nz, .elixirLoop - ld a, [wTileBehindCursor] - and a ; did any moves have their PP restored? - jp nz, .afterRestoringPP -.noEffect - call ItemUseNoEffect -.itemNotUsed - call GBPalWhiteOut - call RunDefaultPaletteCommand - pop af - xor a - ld [wActionResultOrTookBattleTurn], a ; item use failed - ret - -RaisePPWhichTechniqueText: - TX_FAR _RaisePPWhichTechniqueText - db "@" - -RestorePPWhichTechniqueText: - TX_FAR _RestorePPWhichTechniqueText - db "@" - -PPMaxedOutText: - TX_FAR _PPMaxedOutText - db "@" - -PPIncreasedText: - TX_FAR _PPIncreasedText - db "@" - -PPRestoredText: - TX_FAR _PPRestoredText - db "@" - -; for items that can't be used from the Item menu -UnusableItem: - jp ItemUseNotTime - -ItemUseTMHM: - ld a, [wIsInBattle] - and a - jp nz, ItemUseNotTime - ld a, [wcf91] - sub TM_01 - push af - jr nc, .skipAdding - add 55 ; if item is an HM, add 55 -.skipAdding - inc a - ld [wd11e], a - predef TMToMove ; get move ID from TM/HM ID - ld a, [wd11e] - ld [wMoveNum], a - call GetMoveName - call CopyStringToCF4B ; copy name to wcf4b - pop af - ld hl, BootedUpTMText - jr nc, .printBootedUpMachineText - ld hl, BootedUpHMText -.printBootedUpMachineText - call PrintText - ld hl, TeachMachineMoveText - call PrintText - coord hl, 14, 7 - lb bc, 8, 15 - ld a, TWO_OPTION_MENU - ld [wTextBoxID], a - call DisplayTextBoxID ; yes/no menu - ld a, [wCurrentMenuItem] - and a - jr z, .useMachine - ld a, 2 - ld [wActionResultOrTookBattleTurn], a ; item not used - ret -.useMachine - ld a, [wWhichPokemon] - push af - ld a, [wcf91] - push af -.chooseMon - ld hl, wcf4b - ld de, wTempMoveNameBuffer - ld bc, 14 - call CopyData ; save the move name because DisplayPartyMenu will overwrite it - ld a, $ff - ld [wUpdateSpritesEnabled], a - ld a, TMHM_PARTY_MENU - ld [wPartyMenuTypeOrMessageID], a - call DisplayPartyMenu - push af - ld hl, wTempMoveNameBuffer - ld de, wcf4b - ld bc, 14 - call CopyData - pop af - jr nc, .checkIfAbleToLearnMove -; if the player canceled teaching the move - pop af - pop af - call GBPalWhiteOutWithDelay3 - call ClearSprites - call RunDefaultPaletteCommand - jp LoadScreenTilesFromBuffer1 ; restore saved screen -.checkIfAbleToLearnMove - predef CanLearnTM ; check if the pokemon can learn the move - push bc - ld a, [wWhichPokemon] - ld hl, wPartyMonNicks - call GetPartyMonName - pop bc - ld a, c - and a ; can the pokemon learn the move? - jr nz, .checkIfAlreadyLearnedMove -; if the pokemon can't learn the move - ld a, SFX_DENIED - call PlaySoundWaitForCurrent - ld hl, MonCannotLearnMachineMoveText - call PrintText - jr .chooseMon -.checkIfAlreadyLearnedMove - callab CheckIfMoveIsKnown ; check if the pokemon already knows the move - jr c, .chooseMon - predef LearnMove ; teach move - pop af - ld [wcf91], a - pop af - ld [wWhichPokemon], a - ld a, b - and a - ret z - ld a, [wcf91] - call IsItemHM - ret c - jp RemoveUsedItem - -BootedUpTMText: - TX_FAR _BootedUpTMText - db "@" - -BootedUpHMText: - TX_FAR _BootedUpHMText - db "@" - -TeachMachineMoveText: - TX_FAR _TeachMachineMoveText - db "@" - -MonCannotLearnMachineMoveText: - TX_FAR _MonCannotLearnMachineMoveText - db "@" - -PrintItemUseTextAndRemoveItem: - ld hl, ItemUseText00 - call PrintText - ld a, SFX_HEAL_AILMENT - call PlaySound - call WaitForTextScrollButtonPress ; wait for button press - -RemoveUsedItem: - ld hl, wNumBagItems - ld a, 1 ; one item - ld [wItemQuantity], a - jp RemoveItemFromInventory - -ItemUseNoEffect: - ld hl, ItemUseNoEffectText - jr ItemUseFailed - -ItemUseNotTime: - ld hl, ItemUseNotTimeText - jr ItemUseFailed - -ItemUseNotYoursToUse: - ld hl, ItemUseNotYoursToUseText - jr ItemUseFailed - -ThrowBallAtTrainerMon: - call RunDefaultPaletteCommand - call LoadScreenTilesFromBuffer1 ; restore saved screen - call Delay3 - ld a, TOSS_ANIM - ld [wAnimationID], a - predef MoveAnimation ; do animation - ld hl, ThrowBallAtTrainerMonText1 - call PrintText - ld hl, ThrowBallAtTrainerMonText2 - call PrintText - jr RemoveUsedItem - -NoCyclingAllowedHere: - ld hl, NoCyclingAllowedHereText - jr ItemUseFailed - -BoxFullCannotThrowBall: - ld hl, BoxFullCannotThrowBallText - jr ItemUseFailed - -SurfingAttemptFailed: - ld hl, NoSurfingHereText - -ItemUseFailed: - xor a - ld [wActionResultOrTookBattleTurn], a ; item use failed - jp PrintText - -ItemUseNotTimeText: - TX_FAR _ItemUseNotTimeText - db "@" - -ItemUseNotYoursToUseText: - TX_FAR _ItemUseNotYoursToUseText - db "@" - -ItemUseNoEffectText: - TX_FAR _ItemUseNoEffectText - db "@" - -ThrowBallAtTrainerMonText1: - TX_FAR _ThrowBallAtTrainerMonText1 - db "@" - -ThrowBallAtTrainerMonText2: - TX_FAR _ThrowBallAtTrainerMonText2 - db "@" - -NoCyclingAllowedHereText: - TX_FAR _NoCyclingAllowedHereText - db "@" - -NoSurfingHereText: - TX_FAR _NoSurfingHereText - db "@" - -BoxFullCannotThrowBallText: - TX_FAR _BoxFullCannotThrowBallText - db "@" - -ItemUseText00: - TX_FAR _ItemUseText001 - TX_LINE - TX_FAR _ItemUseText002 - db "@" - -GotOnBicycleText: - TX_FAR _GotOnBicycleText1 - TX_LINE - TX_FAR _GotOnBicycleText2 - db "@" - -GotOffBicycleText: - TX_FAR _GotOffBicycleText1 - TX_LINE - TX_FAR _GotOffBicycleText2 - db "@" - -; restores bonus PP (from PP Ups) when healing at a pokemon center -; also, when a PP Up is used, it increases the current PP by one PP Up bonus -; INPUT: -; [wWhichPokemon] = index of pokemon in party -; [wCurrentMenuItem] = index of move (when using a PP Up) -RestoreBonusPP: - ld hl, wPartyMon1Moves - ld bc, wPartyMon2 - wPartyMon1 - ld a, [wWhichPokemon] - call AddNTimes - push hl - ld de, wNormalMaxPPList - 1 - predef LoadMovePPs ; loads the normal max PP of each of the pokemon's moves to wNormalMaxPPList - pop hl - ld c, wPartyMon1PP - wPartyMon1Moves - ld b, 0 - add hl, bc ; hl now points to move 1 PP - ld de, wNormalMaxPPList - ld b, 0 ; initialize move counter to zero -; loop through the pokemon's moves -.loop - inc b - ld a, b - cp 5 ; reached the end of the pokemon's moves? - ret z ; if so, return - ld a, [wUsingPPUp] - dec a ; using a PP Up? - jr nz, .skipMenuItemIDCheck -; if using a PP Up, check if this is the move it's being used on - ld a, [wCurrentMenuItem] - inc a - cp b - jr nz, .nextMove -.skipMenuItemIDCheck - ld a, [hl] - and %11000000 ; have any PP Ups been used? - call nz, AddBonusPP ; if so, add bonus PP -.nextMove - inc hl - inc de - jr .loop - -; adds bonus PP from PP Ups to current PP -; 1/5 of normal max PP (capped at 7) is added for each PP Up -; INPUT: -; [de] = normal max PP -; [hl] = move PP -AddBonusPP: - push bc - ld a, [de] ; normal max PP of move - ld [H_DIVIDEND + 3], a - xor a - ld [H_DIVIDEND], a - ld [H_DIVIDEND + 1], a - ld [H_DIVIDEND + 2], a - ld a, 5 - ld [H_DIVISOR], a - ld b, 4 - call Divide - ld a, [hl] ; move PP - ld b, a - swap a - and %00001111 - srl a - srl a - ld c, a ; c = number of PP Ups used -.loop - ld a, [H_QUOTIENT + 3] - cp 8 ; is the amount greater than or equal to 8? - jr c, .addAmount - ld a, 7 ; cap the amount at 7 -.addAmount - add b - ld b, a - ld a, [wUsingPPUp] - dec a ; is the player using a PP Up right now? - jr z, .done ; if so, only add the bonus once - dec c - jr nz, .loop -.done - ld [hl], b - pop bc - ret - -; gets max PP of a pokemon's move (including PP from PP Ups) -; INPUT: -; [wWhichPokemon] = index of pokemon within party/box -; [wMonDataLocation] = pokemon source -; 00: player's party -; 01: enemy's party -; 02: current box -; 03: daycare -; 04: player's in-battle pokemon -; [wCurrentMenuItem] = move index -; OUTPUT: -; [wMaxPP] = max PP -GetMaxPP: - ld a, [wMonDataLocation] - and a - ld hl, wPartyMon1Moves - ld bc, wPartyMon2 - wPartyMon1 - jr z, .sourceWithMultipleMon - ld hl, wEnemyMon1Moves - dec a - jr z, .sourceWithMultipleMon - ld hl, wBoxMon1Moves - ld bc, wBoxMon2 - wBoxMon1 - dec a - jr z, .sourceWithMultipleMon - ld hl, wDayCareMonMoves - dec a - jr z, .sourceWithOneMon - ld hl, wBattleMonMoves ; player's in-battle pokemon -.sourceWithOneMon - call GetSelectedMoveOffset2 - jr .next -.sourceWithMultipleMon - call GetSelectedMoveOffset -.next - ld a, [hl] - dec a - push hl - ld hl, Moves - ld bc, MoveEnd - Moves - call AddNTimes - ld de, wcd6d - ld a, BANK(Moves) - call FarCopyData - ld de, wcd6d + 5 ; PP is byte 5 of move data - ld a, [de] - ld b, a ; b = normal max PP - pop hl - push bc - ld bc, wPartyMon1PP - wPartyMon1Moves ; PP offset if not player's in-battle pokemon data - ld a, [wMonDataLocation] - cp 4 ; player's in-battle pokemon? - jr nz, .addPPOffset - ld bc, wBattleMonPP - wBattleMonMoves ; PP offset if player's in-battle pokemon data -.addPPOffset - add hl, bc - ld a, [hl] ; a = current PP - and %11000000 ; get PP Up count - pop bc - or b ; place normal max PP in 6 lower bits of a - ld h, d - ld l, e - inc hl ; hl = wcd73 - ld [hl], a - xor a ; add the bonus for the existing PP Up count - ld [wUsingPPUp], a - call AddBonusPP ; add bonus PP from PP Ups - ld a, [hl] - and %00111111 ; mask out the PP Up count - ld [wMaxPP], a ; store max PP - ret - -GetSelectedMoveOffset: - ld a, [wWhichPokemon] - call AddNTimes - -GetSelectedMoveOffset2: - ld a, [wCurrentMenuItem] - ld c, a - ld b, 0 - add hl, bc - ret - -; confirms the item toss and then tosses the item -; INPUT: -; hl = address of inventory (either wNumBagItems or wNumBoxItems) -; [wcf91] = item ID -; [wWhichPokemon] = index of item within inventory -; [wItemQuantity] = quantity to toss -; OUTPUT: -; clears carry flag if the item is tossed, sets carry flag if not -TossItem_:: - push hl - ld a, [wcf91] - call IsItemHM - pop hl - jr c, .tooImportantToToss - push hl - call IsKeyItem_ - ld a, [wIsKeyItem] - pop hl - and a - jr nz, .tooImportantToToss - push hl - ld a, [wcf91] - ld [wd11e], a - call GetItemName - call CopyStringToCF4B ; copy name to wcf4b - ld hl, IsItOKToTossItemText - call PrintText - coord hl, 14, 7 - lb bc, 8, 15 - ld a, TWO_OPTION_MENU - ld [wTextBoxID], a - call DisplayTextBoxID ; yes/no menu - ld a, [wMenuExitMethod] - cp CHOSE_SECOND_ITEM - pop hl - scf - ret z ; return if the player chose No -; if the player chose Yes - push hl - ld a, [wWhichPokemon] - call RemoveItemFromInventory - ld a, [wcf91] - ld [wd11e], a - call GetItemName - call CopyStringToCF4B ; copy name to wcf4b - ld hl, ThrewAwayItemText - call PrintText - pop hl - and a - ret -.tooImportantToToss - push hl - ld hl, TooImportantToTossText - call PrintText - pop hl - scf - ret - -ThrewAwayItemText: - TX_FAR _ThrewAwayItemText - db "@" - -IsItOKToTossItemText: - TX_FAR _IsItOKToTossItemText - db "@" - -TooImportantToTossText: - TX_FAR _TooImportantToTossText - db "@" - -; checks if an item is a key item -; INPUT: -; [wcf91] = item ID -; OUTPUT: -; [wIsKeyItem] = result -; 00: item is not key item -; 01: item is key item -IsKeyItem_:: - ld a, $01 - ld [wIsKeyItem], a - ld a, [wcf91] - cp HM_01 ; is the item an HM or TM? - jr nc, .checkIfItemIsHM -; if the item is not an HM or TM - push af - ld hl, KeyItemBitfield - ld de, wBuffer - ld bc, 15 ; only 11 bytes are actually used - call CopyData - pop af - dec a - ld c, a - ld hl, wBuffer - ld b, FLAG_TEST - predef FlagActionPredef - ld a, c - and a - ret nz -.checkIfItemIsHM - ld a, [wcf91] - call IsItemHM - ret c - xor a - ld [wIsKeyItem], a - ret - -INCLUDE "data/key_items.asm" - -SendNewMonToBox: - ld de, wNumInBox - ld a, [de] - inc a - ld [de], a - ld a, [wcf91] - ld [wd0b5], a - ld c, a -.asm_e7b1 - inc de - ld a, [de] - ld b, a - ld a, c - ld c, b - ld [de], a - cp $ff - jr nz, .asm_e7b1 - call GetMonHeader - ld hl, wBoxMonOT - ld bc, NAME_LENGTH - ld a, [wNumInBox] - dec a - jr z, .asm_e7ee - dec a - call AddNTimes - push hl - ld bc, NAME_LENGTH - add hl, bc - ld d, h - ld e, l - pop hl - ld a, [wNumInBox] - dec a - ld b, a -.asm_e7db - push bc - push hl - ld bc, NAME_LENGTH - call CopyData - pop hl - ld d, h - ld e, l - ld bc, -NAME_LENGTH - add hl, bc - pop bc - dec b - jr nz, .asm_e7db -.asm_e7ee - ld hl, wPlayerName - ld de, wBoxMonOT - ld bc, NAME_LENGTH - call CopyData - ld a, [wNumInBox] - dec a - jr z, .asm_e82a - ld hl, wBoxMonNicks - ld bc, NAME_LENGTH - dec a - call AddNTimes - push hl - ld bc, NAME_LENGTH - add hl, bc - ld d, h - ld e, l - pop hl - ld a, [wNumInBox] - dec a - ld b, a -.asm_e817 - push bc - push hl - ld bc, NAME_LENGTH - call CopyData - pop hl - ld d, h - ld e, l - ld bc, -NAME_LENGTH - add hl, bc - pop bc - dec b - jr nz, .asm_e817 -.asm_e82a - ld hl, wBoxMonNicks - ld a, NAME_MON_SCREEN - ld [wNamingScreenType], a - predef AskName - ld a, [wNumInBox] - dec a - jr z, .asm_e867 - ld hl, wBoxMons - ld bc, wBoxMon2 - wBoxMon1 - dec a - call AddNTimes - push hl - ld bc, wBoxMon2 - wBoxMon1 - add hl, bc - ld d, h - ld e, l - pop hl - ld a, [wNumInBox] - dec a - ld b, a -.asm_e854 - push bc - push hl - ld bc, wBoxMon2 - wBoxMon1 - call CopyData - pop hl - ld d, h - ld e, l - ld bc, wBoxMon1 - wBoxMon2 - add hl, bc - pop bc - dec b - jr nz, .asm_e854 -.asm_e867 - ld a, [wEnemyMonLevel] - ld [wEnemyMonBoxLevel], a - ld hl, wEnemyMon - ld de, wBoxMon1 - ld bc, wEnemyMonDVs - wEnemyMon - call CopyData - ld hl, wPlayerID - ld a, [hli] - ld [de], a - inc de - ld a, [hl] - ld [de], a - inc de - push de - ld a, [wCurEnemyLVL] - ld d, a - callab CalcExperience - pop de - ld a, [hExperience] - ld [de], a - inc de - ld a, [hExperience + 1] - ld [de], a - inc de - ld a, [hExperience + 2] - ld [de], a - inc de - xor a - ld b, NUM_STATS * 2 -.asm_e89f - ld [de], a - inc de - dec b - jr nz, .asm_e89f - ld hl, wEnemyMonDVs - ld a, [hli] - ld [de], a - inc de - ld a, [hli] - ld [de], a - ld hl, wEnemyMonPP - ld b, NUM_MOVES -.asm_e8b1 - ld a, [hli] - inc de - ld [de], a - dec b - jr nz, .asm_e8b1 - 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: - ld a, [wCurMapTileset] - ld hl, WaterTilesets - ld de, 1 - call IsInArray - jr nc, .notShoreOrWater - 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 -.skipShoreTiles - cp $14 ; water tile - jr z, .shoreOrWater -.notShoreOrWater - scf - ret -.shoreOrWater - and a - ret - -INCLUDE "data/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 - call IsInArray - jr c, .ReadFishingGroup - ld e, $2 ; $2 if no fishing groups found - ret - -.ReadFishingGroup -; hl points to the fishing group entry in the index - inc hl ; skip map id - - ; read fishing group address - ld a, [hli] - ld h, [hl] - ld l, a - - ld b, [hl] ; how many mons in group - inc hl ; point to data - ld e, $0 ; no bite yet - -.RandomLoop - call Random - srl a - ret c ; 50% chance of no battle - - and %11 ; 2-bit random number - cp b - jr nc, .RandomLoop ; if a is greater than the number of mons, regenerate - - ; get the mon - add a - ld c, a - ld b, $0 - add hl, bc - ld b, [hl] ; level - inc hl - ld c, [hl] ; species - ld e, $1 ; $1 if there's a bite - ret - -INCLUDE "data/super_rod.asm" - -; reloads map view and processes sprite data -; for items that cause the overworld to be displayed -ItemUseReloadOverworldData: - call LoadCurrentMapView - jp UpdateSprites - -; creates a list at wBuffer of maps where the mon in [wd11e] can be found. -; this is used by the pokedex to display locations the mon can be found on the map. -FindWildLocationsOfMon: - ld hl, WildDataPointers - ld de, wBuffer - ld c, $0 -.loop - inc hl - ld a, [hld] - inc a - jr z, .done - push hl - ld a, [hli] - ld h, [hl] - ld l, a - ld a, [hli] - and a - call nz, CheckMapForMon ; land - ld a, [hli] - and a - call nz, CheckMapForMon ; water - pop hl - inc hl - inc hl - inc c - jr .loop -.done - ld a, $ff ; list terminator - ld [de], a - ret - -CheckMapForMon: - inc hl - ld b, $a -.loop - ld a, [wd11e] - cp [hl] - jr nz, .nextEntry - ld a, c - ld [de], a - inc de -.nextEntry - inc hl - inc hl - dec b - jr nz, .loop - dec hl - ret diff --git a/engine/items/subtract_paid_money.asm b/engine/items/subtract_paid_money.asm new file mode 100644 index 00000000..fdefe3d6 --- /dev/null +++ b/engine/items/subtract_paid_money.asm @@ -0,0 +1,17 @@ +; subtracts the amount the player paid from their money +; OUTPUT: carry = 0(success) or 1(fail because there is not enough money) +SubtractAmountPaidFromMoney_:: + ld de, wPlayerMoney + ld hl, hMoney ; total price of items + ld c, 3 ; length of money in bytes + call StringCmp + ret c + ld de, wPlayerMoney + 2 + ld hl, hMoney + 2 ; total price of items + ld c, 3 ; length of money in bytes + predef SubBCDPredef ; subtract total price from money + ld a, MONEY_BOX + ld [wTextBoxID], a + call DisplayTextBoxID ; redraw money text box + and a + ret diff --git a/engine/items/town_map.asm b/engine/items/town_map.asm new file mode 100755 index 00000000..84a92994 --- /dev/null +++ b/engine/items/town_map.asm @@ -0,0 +1,618 @@ +DisplayTownMap: + call LoadTownMap + ld hl, wUpdateSpritesEnabled + ld a, [hl] + push af + ld [hl], $ff + push hl + ld a, $1 + ld [hJoy7], a + ld a, [wCurMap] + push af + ld b, $0 + call DrawPlayerOrBirdSprite ; player sprite + coord hl, 1, 0 + ld de, wcd6d + call PlaceString + ld hl, wOAMBuffer + ld de, wTileMapBackup + ld bc, $10 + call CopyData + ld hl, vSprites + $40 + ld de, TownMapCursor + lb bc, BANK(TownMapCursor), (TownMapCursorEnd - TownMapCursor) / $8 + call CopyVideoDataDouble + xor a + ld [wWhichTownMapLocation], a + pop af + jr .enterLoop + +.townMapLoop + coord hl, 0, 0 + lb bc, 1, 20 + call ClearScreenArea + ld hl, TownMapOrder + ld a, [wWhichTownMapLocation] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] +.enterLoop + ld de, wTownMapCoords + call LoadTownMapEntry + ld a, [de] + push hl + call TownMapCoordsToOAMCoords + ld a, $4 + ld [wOAMBaseTile], a + ld hl, wOAMBuffer + $10 + call WriteTownMapSpriteOAM ; town map cursor sprite + pop hl + ld de, wcd6d +.copyMapName + ld a, [hli] + ld [de], a + inc de + cp $50 + jr nz, .copyMapName + coord hl, 1, 0 + ld de, wcd6d + call PlaceString + ld hl, wOAMBuffer + $10 + ld de, wTileMapBackup + 16 + ld bc, $10 + call CopyData +.inputLoop + call TownMapSpriteBlinkingAnimation + call JoypadLowSensitivity + ld a, [hJoy5] + ld b, a + and A_BUTTON | B_BUTTON | D_UP | D_DOWN + jr z, .inputLoop + ld a, SFX_TINK + call PlaySound + bit 6, b + jr nz, .pressedUp + bit 7, b + jr nz, .pressedDown + xor a + ld [wTownMapSpriteBlinkingEnabled], a + ld [hJoy7], a + ld [wAnimCounter], a + call ExitTownMap + pop hl + pop af + ld [hl], a + ret +.pressedUp + ld a, [wWhichTownMapLocation] + inc a + cp TownMapOrderEnd - TownMapOrder ; number of list items + 1 + jr nz, .noOverflow + xor a +.noOverflow + ld [wWhichTownMapLocation], a + jp .townMapLoop +.pressedDown + ld a, [wWhichTownMapLocation] + dec a + cp -1 + jr nz, .noUnderflow + ld a, TownMapOrderEnd - TownMapOrder - 1 ; number of list items +.noUnderflow + ld [wWhichTownMapLocation], a + jp .townMapLoop + +INCLUDE "data/town_map_order.asm" + +TownMapCursor: + INCBIN "gfx/town_map/town_map_cursor.1bpp" +TownMapCursorEnd: + +LoadTownMap_Nest: + call LoadTownMap + ld hl, wUpdateSpritesEnabled + ld a, [hl] + push af + ld [hl], $ff + push hl + call DisplayWildLocations + call GetMonName + coord hl, 1, 0 + call PlaceString + ld h, b + ld l, c + ld de, MonsNestText + call PlaceString + call WaitForTextScrollButtonPress + call ExitTownMap + pop hl + pop af + ld [hl], a + ret + +MonsNestText: + db "'s NEST@" + +LoadTownMap_Fly:: + call ClearSprites + call LoadTownMap + call LoadPlayerSpriteGraphics + call LoadFontTilePatterns + ld de, BirdSprite + ld hl, vSprites + $40 + lb bc, BANK(BirdSprite), $c + call CopyVideoData + ld de, TownMapUpArrow + ld hl, vChars1 + $6d0 + lb bc, BANK(TownMapUpArrow), (TownMapUpArrowEnd - TownMapUpArrow) / $8 + call CopyVideoDataDouble + call BuildFlyLocationsList + ld hl, wUpdateSpritesEnabled + ld a, [hl] + push af + ld [hl], $ff + push hl + coord hl, 0, 0 + ld de, ToText + call PlaceString + ld a, [wCurMap] + ld b, $0 + call DrawPlayerOrBirdSprite + ld hl, wFlyLocationsList + coord de, 18, 0 +.townMapFlyLoop + ld a, " " + ld [de], a + push hl + push hl + coord hl, 3, 0 + lb bc, 1, 15 + call ClearScreenArea + pop hl + ld a, [hl] + ld b, $4 + call DrawPlayerOrBirdSprite ; draw bird sprite + coord hl, 3, 0 + ld de, wcd6d + call PlaceString + ld c, 15 + call DelayFrames + coord hl, 18, 0 + ld [hl], "▲" + coord hl, 19, 0 + ld [hl], "▼" + pop hl +.inputLoop + push hl + call DelayFrame + call JoypadLowSensitivity + ld a, [hJoy5] + ld b, a + pop hl + and A_BUTTON | B_BUTTON | D_UP | D_DOWN + jr z, .inputLoop + bit 0, b + jr nz, .pressedA + ld a, SFX_TINK + call PlaySound + bit 6, b + jr nz, .pressedUp + bit 7, b + jr nz, .pressedDown + jr .pressedB +.pressedA + ld a, SFX_HEAL_AILMENT + call PlaySound + ld a, [hl] + ld [wDestinationMap], a + ld hl, wd732 + set 3, [hl] + inc hl + set 7, [hl] +.pressedB + xor a + ld [wTownMapSpriteBlinkingEnabled], a + call GBPalWhiteOutWithDelay3 + pop hl + pop af + ld [hl], a + ret +.pressedUp + coord de, 18, 0 + inc hl + ld a, [hl] + cp $ff + jr z, .wrapToStartOfList + cp $fe + jr z, .pressedUp ; skip past unvisited towns + jp .townMapFlyLoop +.wrapToStartOfList + ld hl, wFlyLocationsList + jp .townMapFlyLoop +.pressedDown + coord de, 19, 0 + dec hl + ld a, [hl] + cp $ff + jr z, .wrapToEndOfList + cp $fe + jr z, .pressedDown ; skip past unvisited towns + jp .townMapFlyLoop +.wrapToEndOfList + ld hl, wFlyLocationsList + 11 + jr .pressedDown + +ToText: + db "To@" + +BuildFlyLocationsList: + ld hl, wFlyLocationsList - 1 + ld [hl], $ff + inc hl + ld a, [wTownVisitedFlag] + ld e, a + ld a, [wTownVisitedFlag + 1] + ld d, a + ld bc, SAFFRON_CITY + 1 +.loop + srl d + rr e + ld a, $fe ; store $fe if the town hasn't been visited + jr nc, .notVisited + ld a, b ; store the map number of the town if it has been visited +.notVisited + ld [hl], a + inc hl + inc b + dec c + jr nz, .loop + ld [hl], $ff + ret + +TownMapUpArrow: + INCBIN "gfx/town_map/up_arrow.1bpp" +TownMapUpArrowEnd: + +LoadTownMap: + call GBPalWhiteOutWithDelay3 + call ClearScreen + call UpdateSprites + coord hl, 0, 0 + ld b, $12 + ld c, $12 + call TextBoxBorder + call DisableLCD + ld hl, WorldMapTileGraphics + ld de, vChars2 + $600 + ld bc, WorldMapTileGraphicsEnd - WorldMapTileGraphics + ld a, BANK(WorldMapTileGraphics) + call FarCopyData2 + ld hl, MonNestIcon + ld de, vSprites + $40 + ld bc, MonNestIconEnd - MonNestIcon + ld a, BANK(MonNestIcon) + call FarCopyDataDouble + coord hl, 0, 0 + ld de, CompressedMap +.nextTile + ld a, [de] + and a + jr z, .done + ld b, a + and $f + ld c, a + ld a, b + swap a + and $f + add $60 +.writeRunLoop + ld [hli], a + dec c + jr nz, .writeRunLoop + inc de + jr .nextTile +.done + call EnableLCD + ld b, SET_PAL_TOWN_MAP + call RunPaletteCommand + call Delay3 + call GBPalNormal + xor a + ld [wAnimCounter], a + inc a + ld [wTownMapSpriteBlinkingEnabled], a + ret + +CompressedMap: + INCBIN "gfx/town_map/town_map.rle" + +ExitTownMap: +; clear town map graphics data and load usual graphics data + xor a + ld [wTownMapSpriteBlinkingEnabled], a + call GBPalWhiteOut + call ClearScreen + call ClearSprites + call LoadPlayerSpriteGraphics + call LoadFontTilePatterns + call UpdateSprites + jp RunDefaultPaletteCommand + +DrawPlayerOrBirdSprite: +; a = map number +; b = OAM base tile + push af + ld a, b + ld [wOAMBaseTile], a + pop af + ld de, wTownMapCoords + call LoadTownMapEntry + ld a, [de] + push hl + call TownMapCoordsToOAMCoords + call WritePlayerOrBirdSpriteOAM + pop hl + ld de, wcd6d +.loop + ld a, [hli] + ld [de], a + inc de + cp "@" + jr nz, .loop + ld hl, wOAMBuffer + ld de, wTileMapBackup + ld bc, $a0 + jp CopyData + +DisplayWildLocations: + callba FindWildLocationsOfMon + call ZeroOutDuplicatesInList + ld hl, wOAMBuffer + ld de, wTownMapCoords +.loop + ld a, [de] + cp $ff + jr z, .exitLoop + and a + jr z, .nextEntry + push hl + call LoadTownMapEntry + pop hl + ld a, [de] + cp $19 ; Cerulean Cave's coordinates + jr z, .nextEntry ; skip Cerulean Cave + call TownMapCoordsToOAMCoords + ld a, $4 ; nest icon tile no. + ld [hli], a + xor a + ld [hli], a +.nextEntry + inc de + jr .loop +.exitLoop + ld a, l + and a ; were any OAM entries written? + jr nz, .drawPlayerSprite +; if no OAM entries were written, print area unknown text + coord hl, 1, 7 + ld b, 2 + ld c, 15 + call TextBoxBorder + coord hl, 2, 9 + ld de, AreaUnknownText + call PlaceString + jr .done +.drawPlayerSprite + ld a, [wCurMap] + ld b, $0 + call DrawPlayerOrBirdSprite +.done + ld hl, wOAMBuffer + ld de, wTileMapBackup + ld bc, $a0 + jp CopyData + +AreaUnknownText: + db " AREA UNKNOWN@" + +TownMapCoordsToOAMCoords: +; in: lower nybble of a = x, upper nybble of a = y +; out: b and [hl] = (y * 8) + 24, c and [hl+1] = (x * 8) + 24 + push af + and $f0 + srl a + add 24 + ld b, a + ld [hli], a + pop af + and $f + swap a + srl a + add 24 + ld c, a + ld [hli], a + ret + +WritePlayerOrBirdSpriteOAM: + ld a, [wOAMBaseTile] + and a + ld hl, wOAMBuffer + $90 ; for player sprite + jr z, WriteTownMapSpriteOAM + ld hl, wOAMBuffer + $80 ; for bird sprite + +WriteTownMapSpriteOAM: + push hl + +; Subtract 4 from c (X coord) and 4 from b (Y coord). However, the carry from c +; is added to b, so the net result is that only 3 is subtracted from b. + lb hl, -4, -4 + add hl, bc + + ld b, h + ld c, l + pop hl + +WriteAsymmetricMonPartySpriteOAM: +; Writes 4 OAM blocks for a helix mon party sprite, since it does not have +; a vertical line of symmetry. + lb de, 2, 2 +.loop + push de + push bc +.innerLoop + ld a, b + ld [hli], a + ld a, c + ld [hli], a + ld a, [wOAMBaseTile] + ld [hli], a + inc a + ld [wOAMBaseTile], a + xor a + ld [hli], a + inc d + ld a, 8 + add c + ld c, a + dec e + jr nz, .innerLoop + pop bc + pop de + ld a, 8 + add b + ld b, a + dec d + jr nz, .loop + ret + +WriteSymmetricMonPartySpriteOAM: +; Writes 4 OAM blocks for a mon party sprite other than a helix. All the +; sprites other than the helix one have a vertical line of symmetry which allows +; the X-flip OAM bit to be used so that only 2 rather than 4 tile patterns are +; needed. + xor a + ld [wSymmetricSpriteOAMAttributes], a + lb de, 2, 2 +.loop + push de + push bc +.innerLoop + ld a, b + ld [hli], a ; Y + ld a, c + ld [hli], a ; X + ld a, [wOAMBaseTile] + ld [hli], a ; tile + ld a, [wSymmetricSpriteOAMAttributes] + ld [hli], a ; attributes + xor (1 << OAM_X_FLIP) + ld [wSymmetricSpriteOAMAttributes], a + inc d + ld a, 8 + add c + ld c, a + dec e + jr nz, .innerLoop + pop bc + pop de + push hl + ld hl, wOAMBaseTile + inc [hl] + inc [hl] + pop hl + ld a, 8 + add b + ld b, a + dec d + jr nz, .loop + ret + +ZeroOutDuplicatesInList: +; replace duplicate bytes in the list of wild pokemon locations with 0 + ld de, wBuffer +.loop + ld a, [de] + inc de + cp $ff + ret z + ld c, a + ld l, e + ld h, d +.zeroDuplicatesLoop + ld a, [hl] + cp $ff + jr z, .loop + cp c + jr nz, .skipZeroing + xor a + ld [hl], a +.skipZeroing + inc hl + jr .zeroDuplicatesLoop + +LoadTownMapEntry: +; in: a = map number +; out: lower nybble of [de] = x, upper nybble of [de] = y, hl = address of name + cp REDS_HOUSE_1F + jr c, .external + ld bc, 4 + ld hl, InternalMapEntries +.loop + cp [hl] + jr c, .foundEntry + add hl, bc + jr .loop +.foundEntry + inc hl + jr .readEntry +.external + ld hl, ExternalMapEntries + ld c, a + ld b, 0 + add hl, bc + add hl, bc + add hl, bc +.readEntry + ld a, [hli] + ld [de], a + ld a, [hli] + ld h, [hl] + ld l, a + ret + +INCLUDE "data/town_map_entries.asm" + +INCLUDE "text/map_names.asm" + +MonNestIcon: + INCBIN "gfx/town_map/mon_nest_icon.1bpp" +MonNestIconEnd: + +TownMapSpriteBlinkingAnimation:: + ld a, [wAnimCounter] + inc a + cp 25 + jr z, .hideSprites + cp 50 + jr nz, .done +; show sprites when the counter reaches 50 + ld hl, wTileMapBackup + ld de, wOAMBuffer + ld bc, $90 + call CopyData + xor a + jr .done +.hideSprites + ld hl, wOAMBuffer + ld b, $24 + ld de, $4 +.hideSpritesLoop + ld [hl], $a0 + add hl, de + dec b + jr nz, .hideSpritesLoop + ld a, 25 +.done + ld [wAnimCounter], a + jp DelayFrame diff --git a/engine/learn_move.asm b/engine/learn_move.asm deleted file mode 100755 index 53c7f87e..00000000 --- a/engine/learn_move.asm +++ /dev/null @@ -1,226 +0,0 @@ -LearnMove: - call SaveScreenTilesToBuffer1 - ld a, [wWhichPokemon] - ld hl, wPartyMonNicks - call GetPartyMonName - ld hl, wcd6d - ld de, wLearnMoveMonName - ld bc, NAME_LENGTH - call CopyData - -DontAbandonLearning: - ld hl, wPartyMon1Moves - ld bc, wPartyMon2Moves - wPartyMon1Moves - ld a, [wWhichPokemon] - call AddNTimes - ld d, h - ld e, l - ld b, NUM_MOVES -.findEmptyMoveSlotLoop - ld a, [hl] - and a - jr z, .next - inc hl - dec b - jr nz, .findEmptyMoveSlotLoop - push de - call TryingToLearn - pop de - jp c, AbandonLearning - push hl - push de - ld [wd11e], a - call GetMoveName - ld hl, OneTwoAndText - call PrintText - pop de - pop hl -.next - ld a, [wMoveNum] - ld [hl], a - ld bc, wPartyMon1PP - wPartyMon1Moves - add hl, bc - push hl - push de - dec a - ld hl, Moves - ld bc, MoveEnd - Moves - call AddNTimes - ld de, wBuffer - ld a, BANK(Moves) - call FarCopyData - ld a, [wBuffer + 5] ; a = move's max PP - pop de - pop hl - ld [hl], a - ld a, [wIsInBattle] - and a - jp z, PrintLearnedMove - ld a, [wWhichPokemon] - ld b, a - ld a, [wPlayerMonNumber] - cp b - jp nz, PrintLearnedMove - ld h, d - ld l, e - ld de, wBattleMonMoves - ld bc, NUM_MOVES - call CopyData - ld bc, wPartyMon1PP - wPartyMon1OTID - add hl, bc - ld de, wBattleMonPP - ld bc, NUM_MOVES - call CopyData - jp PrintLearnedMove - -AbandonLearning: - ld hl, AbandonLearningText - call PrintText - coord hl, 14, 7 - lb bc, 8, 15 - ld a, TWO_OPTION_MENU - ld [wTextBoxID], a - call DisplayTextBoxID ; yes/no menu - ld a, [wCurrentMenuItem] - and a - jp nz, DontAbandonLearning - ld hl, DidNotLearnText - call PrintText - ld b, 0 - ret - -PrintLearnedMove: - ld hl, LearnedMove1Text - call PrintText - ld b, 1 - ret - -TryingToLearn: - push hl - ld hl, TryingToLearnText - call PrintText - coord hl, 14, 7 - lb bc, 8, 15 - ld a, TWO_OPTION_MENU - ld [wTextBoxID], a - call DisplayTextBoxID ; yes/no menu - pop hl - ld a, [wCurrentMenuItem] - rra - ret c - ld bc, -NUM_MOVES - add hl, bc - push hl - ld de, wMoves - ld bc, NUM_MOVES - call CopyData - callab FormatMovesString - pop hl -.loop - push hl - ld hl, WhichMoveToForgetText - call PrintText - coord hl, 4, 7 - ld b, 4 - ld c, 14 - call TextBoxBorder - coord hl, 6, 8 - ld de, wMovesString - ld a, [hFlags_0xFFF6] - set 2, a - ld [hFlags_0xFFF6], a - call PlaceString - ld a, [hFlags_0xFFF6] - res 2, a - ld [hFlags_0xFFF6], a - ld hl, wTopMenuItemY - ld a, 8 - ld [hli], a ; wTopMenuItemY - ld a, 5 - ld [hli], a ; wTopMenuItemX - xor a - ld [hli], a ; wCurrentMenuItem - inc hl - ld a, [wNumMovesMinusOne] - ld [hli], a ; wMaxMenuItem - ld a, A_BUTTON | B_BUTTON - ld [hli], a ; wMenuWatchedKeys - ld [hl], 0 ; wLastMenuItem - ld hl, hFlags_0xFFF6 - set 1, [hl] - call HandleMenuInput - ld hl, hFlags_0xFFF6 - res 1, [hl] - push af - call LoadScreenTilesFromBuffer1 - pop af - pop hl - bit 1, a ; pressed b - jr nz, .cancel - push hl - ld a, [wCurrentMenuItem] - ld c, a - ld b, 0 - add hl, bc - ld a, [hl] - push af - push bc - call IsMoveHM - pop bc - pop de - ld a, d - jr c, .hm - pop hl - add hl, bc - and a - ret -.hm - ld hl, HMCantDeleteText - call PrintText - pop hl - jr .loop -.cancel - scf - ret - -LearnedMove1Text: - TX_FAR _LearnedMove1Text - TX_SFX_ITEM_1 ; plays SFX_GET_ITEM_1 in the party menu (rare candy) and plays SFX_LEVEL_UP in battle - TX_BLINK - db "@" - -WhichMoveToForgetText: - TX_FAR _WhichMoveToForgetText - db "@" - -AbandonLearningText: - TX_FAR _AbandonLearningText - db "@" - -DidNotLearnText: - TX_FAR _DidNotLearnText - db "@" - -TryingToLearnText: - TX_FAR _TryingToLearnText - db "@" - -OneTwoAndText: - TX_FAR _OneTwoAndText - TX_DELAY - TX_ASM - ld a, SFX_SWAP - call PlaySoundWaitForCurrent - ld hl, PoofText - ret - -PoofText: - TX_FAR _PoofText - TX_DELAY -ForgotAndText: - TX_FAR _ForgotAndText - db "@" - -HMCantDeleteText: - TX_FAR _HMCantDeleteText - db "@" diff --git a/engine/link/cable_club.asm b/engine/link/cable_club.asm new file mode 100755 index 00000000..141ed396 --- /dev/null +++ b/engine/link/cable_club.asm @@ -0,0 +1,977 @@ +; performs the appropriate action when the player uses the gameboy on the table in the Colosseum or Trade Center +; In the Colosseum, it starts a battle. In the Trade Center, it displays the trade selection screen. +; Before doing either action, it swaps random numbers, trainer names and party data with the other gameboy. +CableClub_DoBattleOrTrade: + ld c, 80 + call DelayFrames + call ClearScreen + call UpdateSprites + call LoadFontTilePatterns + call LoadHpBarAndStatusTilePatterns + call LoadTrainerInfoTextBoxTiles + coord hl, 3, 8 + ld b, 2 + ld c, 12 + call CableClub_TextBoxBorder + coord hl, 4, 10 + ld de, PleaseWaitString + call PlaceString + ld hl, wPlayerNumHits + xor a + ld [hli], a + ld [hl], $50 + ; fall through + +; This is called after completing a trade. +CableClub_DoBattleOrTradeAgain: + ld hl, wSerialPlayerDataBlock + ld a, SERIAL_PREAMBLE_BYTE + ld b, 6 +.writePlayerDataBlockPreambleLoop + ld [hli], a + dec b + jr nz, .writePlayerDataBlockPreambleLoop + ld hl, wSerialRandomNumberListBlock + ld a, SERIAL_PREAMBLE_BYTE + ld b, 7 +.writeRandomNumberListPreambleLoop + ld [hli], a + dec b + jr nz, .writeRandomNumberListPreambleLoop + ld b, 10 +.generateRandomNumberListLoop + call Random + cp SERIAL_PREAMBLE_BYTE ; all the random numbers have to be less than the preamble byte + jr nc, .generateRandomNumberListLoop + ld [hli], a + dec b + jr nz, .generateRandomNumberListLoop + ld hl, wSerialPartyMonsPatchList + ld a, SERIAL_PREAMBLE_BYTE + ld [hli], a + ld [hli], a + ld [hli], a + ld b, $c8 + xor a +.zeroPlayerDataPatchListLoop + ld [hli], a + dec b + jr nz, .zeroPlayerDataPatchListLoop + ld hl, wGrassRate + ld bc, wTrainerHeaderPtr - wGrassRate +.zeroEnemyPartyLoop + xor a + ld [hli], a + dec bc + ld a, b + or c + jr nz, .zeroEnemyPartyLoop + ld hl, wPartyMons - 1 + ld de, wSerialPartyMonsPatchList + 10 + ld bc, 0 +.patchPartyMonsLoop + inc c + ld a, c + cp SERIAL_PREAMBLE_BYTE + jr z, .startPatchListPart2 + ld a, b + dec a ; are we in part 2 of the patch list? + jr nz, .checkPlayerDataByte ; jump if in part 1 +; if we're in part 2 + ld a, c + cp (wPartyMonOT - (wPartyMons - 1)) - (SERIAL_PREAMBLE_BYTE - 1) + jr z, .finishedPatchingPlayerData +.checkPlayerDataByte + inc hl + ld a, [hl] + cp SERIAL_NO_DATA_BYTE + jr nz, .patchPartyMonsLoop +; if the player data byte matches SERIAL_NO_DATA_BYTE, patch it with $FF and record the offset in the patch list + ld a, c + ld [de], a + inc de + ld [hl], $ff + jr .patchPartyMonsLoop +.startPatchListPart2 + ld a, SERIAL_PATCH_LIST_PART_TERMINATOR + ld [de], a ; end of part 1 + inc de + lb bc, 1, 0 + jr .patchPartyMonsLoop +.finishedPatchingPlayerData + ld a, SERIAL_PATCH_LIST_PART_TERMINATOR + ld [de], a ; end of part 2 + call Serial_SyncAndExchangeNybble + ld a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + jr nz, .skipSendingTwoZeroBytes +; if using internal clock +; send two zero bytes for syncing purposes? + call Delay3 + xor a + ld [hSerialSendData], a + ld a, START_TRANSFER_INTERNAL_CLOCK + ld [rSC], a + call DelayFrame + xor a + ld [hSerialSendData], a + ld a, START_TRANSFER_INTERNAL_CLOCK + ld [rSC], a +.skipSendingTwoZeroBytes + call Delay3 + ld a, (1 << SERIAL) + ld [rIE], a + ld hl, wSerialRandomNumberListBlock + ld de, wSerialOtherGameboyRandomNumberListBlock + ld bc, $11 + call Serial_ExchangeBytes + ld a, SERIAL_NO_DATA_BYTE + ld [de], a + ld hl, wSerialPlayerDataBlock + ld de, wSerialEnemyDataBlock + ld bc, $1a8 + call Serial_ExchangeBytes + ld a, SERIAL_NO_DATA_BYTE + ld [de], a + ld hl, wSerialPartyMonsPatchList + ld de, wSerialEnemyMonsPatchList + ld bc, $c8 + call Serial_ExchangeBytes + ld a, (1 << SERIAL) | (1 << TIMER) | (1 << VBLANK) + ld [rIE], a + ld a, $ff + call PlaySound + ld a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + jr z, .skipCopyingRandomNumberList ; the list generated by the gameboy clocking the connection is used by both gameboys + ld hl, wSerialOtherGameboyRandomNumberListBlock +.findStartOfRandomNumberListLoop + ld a, [hli] + and a + jr z, .findStartOfRandomNumberListLoop + cp SERIAL_PREAMBLE_BYTE + jr z, .findStartOfRandomNumberListLoop + cp SERIAL_NO_DATA_BYTE + jr z, .findStartOfRandomNumberListLoop + dec hl + ld de, wLinkBattleRandomNumberList + ld c, 10 +.copyRandomNumberListLoop + ld a, [hli] + cp SERIAL_NO_DATA_BYTE + jr z, .copyRandomNumberListLoop + ld [de], a + inc de + dec c + jr nz, .copyRandomNumberListLoop +.skipCopyingRandomNumberList + ld hl, wSerialEnemyDataBlock + 3 +.findStartOfEnemyNameLoop + ld a, [hli] + and a + jr z, .findStartOfEnemyNameLoop + cp SERIAL_PREAMBLE_BYTE + jr z, .findStartOfEnemyNameLoop + cp SERIAL_NO_DATA_BYTE + jr z, .findStartOfEnemyNameLoop + dec hl + ld de, wLinkEnemyTrainerName + ld c, NAME_LENGTH +.copyEnemyNameLoop + ld a, [hli] + cp SERIAL_NO_DATA_BYTE + jr z, .copyEnemyNameLoop + ld [de], a + inc de + dec c + jr nz, .copyEnemyNameLoop + ld de, wEnemyPartyCount + ld bc, wTrainerHeaderPtr - wEnemyPartyCount +.copyEnemyPartyLoop + ld a, [hli] + cp SERIAL_NO_DATA_BYTE + jr z, .copyEnemyPartyLoop + ld [de], a + inc de + dec bc + ld a, b + or c + jr nz, .copyEnemyPartyLoop + ld de, wSerialPartyMonsPatchList + ld hl, wPartyMons + ld c, 2 ; patch list has 2 parts +.unpatchPartyMonsLoop + ld a, [de] + inc de + and a + jr z, .unpatchPartyMonsLoop + cp SERIAL_PREAMBLE_BYTE + jr z, .unpatchPartyMonsLoop + cp SERIAL_NO_DATA_BYTE + jr z, .unpatchPartyMonsLoop + cp SERIAL_PATCH_LIST_PART_TERMINATOR + jr z, .finishedPartyMonsPatchListPart + push hl + push bc + ld b, 0 + dec a + ld c, a + add hl, bc + ld a, SERIAL_NO_DATA_BYTE + ld [hl], a + pop bc + pop hl + jr .unpatchPartyMonsLoop +.finishedPartyMonsPatchListPart + ld hl, wPartyMons + (SERIAL_PREAMBLE_BYTE - 1) + dec c ; is there another part? + jr nz, .unpatchPartyMonsLoop + ld de, wSerialEnemyMonsPatchList + ld hl, wEnemyMons + ld c, 2 ; patch list has 2 parts +.unpatchEnemyMonsLoop + ld a, [de] + inc de + and a + jr z, .unpatchEnemyMonsLoop + cp SERIAL_PREAMBLE_BYTE + jr z, .unpatchEnemyMonsLoop + cp SERIAL_NO_DATA_BYTE + jr z, .unpatchEnemyMonsLoop + cp SERIAL_PATCH_LIST_PART_TERMINATOR + jr z, .finishedEnemyMonsPatchListPart + push hl + push bc + ld b, 0 + dec a + ld c, a + add hl, bc + ld a, SERIAL_NO_DATA_BYTE + ld [hl], a + pop bc + pop hl + jr .unpatchEnemyMonsLoop +.finishedEnemyMonsPatchListPart + ld hl, wEnemyMons + (SERIAL_PREAMBLE_BYTE - 1) + dec c + jr nz, .unpatchEnemyMonsLoop + ld a, wEnemyMonOT % $100 + ld [wUnusedCF8D], a + ld a, wEnemyMonOT / $100 + ld [wUnusedCF8D + 1], a + xor a + ld [wTradeCenterPointerTableIndex], a + ld a, $ff + call PlaySound + ld a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + ld c, 66 + call z, DelayFrames ; delay if using internal clock + ld a, [wLinkState] + cp LINK_STATE_START_BATTLE + ld a, LINK_STATE_TRADING + ld [wLinkState], a + jr nz, .trading + ld a, LINK_STATE_BATTLING + ld [wLinkState], a + ld a, OPP_SONY1 + ld [wCurOpponent], a + call ClearScreen + call Delay3 + ld hl, wOptions + res 7, [hl] + predef InitOpponent + predef HealParty + jp ReturnToCableClubRoom +.trading + ld c, BANK(Music_GameCorner) + ld a, MUSIC_GAME_CORNER + call PlayMusic + jr CallCurrentTradeCenterFunction + +PleaseWaitString: + db "PLEASE WAIT!@" + +CallCurrentTradeCenterFunction: + ld hl, TradeCenterPointerTable + ld b, 0 + ld a, [wTradeCenterPointerTableIndex] + cp $ff + jp z, DisplayTitleScreen + add a + ld c, a + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + jp hl + +TradeCenter_SelectMon: + call ClearScreen + call LoadTrainerInfoTextBoxTiles + call TradeCenter_DrawPartyLists + call TradeCenter_DrawCancelBox + xor a + ld hl, wSerialSyncAndExchangeNybbleReceiveData + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a + ld [wMenuWatchMovingOutOfBounds], a + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + ld [wMenuJoypadPollCount], a + inc a + ld [wSerialExchangeNybbleSendData], a + jp .playerMonMenu +.enemyMonMenu + xor a + ld [wMenuWatchMovingOutOfBounds], a + inc a + ld [wWhichTradeMonSelectionMenu], a + ld a, D_DOWN | D_LEFT | A_BUTTON + ld [wMenuWatchedKeys], a + ld a, [wEnemyPartyCount] + ld [wMaxMenuItem], a + ld a, 9 + ld [wTopMenuItemY], a + ld a, 1 + ld [wTopMenuItemX], a +.enemyMonMenu_HandleInput + ld hl, hFlags_0xFFF6 + set 1, [hl] + call HandleMenuInput + ld hl, hFlags_0xFFF6 + res 1, [hl] + and a + jp z, .getNewInput + bit 0, a ; A button pressed? + jr z, .enemyMonMenu_ANotPressed +; if A button pressed + ld a, [wMaxMenuItem] + ld c, a + ld a, [wCurrentMenuItem] + cp c + jr c, .displayEnemyMonStats + ld a, [wMaxMenuItem] + dec a + ld [wCurrentMenuItem], a +.displayEnemyMonStats + ld a, INIT_ENEMYOT_LIST + ld [wInitListType], a + callab InitList ; the list isn't used + ld hl, wEnemyMons + call TradeCenter_DisplayStats + jp .getNewInput +.enemyMonMenu_ANotPressed + bit 5, a ; Left pressed? + jr z, .enemyMonMenu_LeftNotPressed +; if Left pressed, switch back to the player mon menu + xor a ; player mon menu + ld [wWhichTradeMonSelectionMenu], a + ld a, [wMenuCursorLocation] + ld l, a + ld a, [wMenuCursorLocation + 1] + ld h, a + ld a, [wTileBehindCursor] + ld [hl], a + ld a, [wCurrentMenuItem] + ld b, a + ld a, [wPartyCount] + dec a + cp b + jr nc, .playerMonMenu + ld [wCurrentMenuItem], a + jr .playerMonMenu +.enemyMonMenu_LeftNotPressed + bit 7, a ; Down pressed? + jp z, .getNewInput + jp .selectedCancelMenuItem ; jump if Down pressed +.playerMonMenu + xor a ; player mon menu + ld [wWhichTradeMonSelectionMenu], a + ld [wMenuWatchMovingOutOfBounds], a + ld a, D_DOWN | D_RIGHT | A_BUTTON + ld [wMenuWatchedKeys], a + ld a, [wPartyCount] + ld [wMaxMenuItem], a + ld a, 1 + ld [wTopMenuItemY], a + ld a, 1 + ld [wTopMenuItemX], a + coord hl, 1, 1 + lb bc, 6, 1 + call ClearScreenArea +.playerMonMenu_HandleInput + ld hl, hFlags_0xFFF6 + set 1, [hl] + call HandleMenuInput + ld hl, hFlags_0xFFF6 + res 1, [hl] + and a ; was anything pressed? + jr nz, .playerMonMenu_SomethingPressed + jp .getNewInput +.playerMonMenu_SomethingPressed + bit 0, a ; A button pressed? + jr z, .playerMonMenu_ANotPressed + jp .chosePlayerMon ; jump if A button pressed +; unreachable code + ld a, INIT_PLAYEROT_LIST + ld [wInitListType], a + callab InitList ; the list isn't used + call TradeCenter_DisplayStats + jp .getNewInput +.playerMonMenu_ANotPressed + bit 4, a ; Right pressed? + jr z, .playerMonMenu_RightNotPressed +; if Right pressed, switch to the enemy mon menu + ld a, $1 ; enemy mon menu + ld [wWhichTradeMonSelectionMenu], a + ld a, [wMenuCursorLocation] + ld l, a + ld a, [wMenuCursorLocation + 1] + ld h, a + ld a, [wTileBehindCursor] + ld [hl], a + ld a, [wCurrentMenuItem] + ld b, a + ld a, [wEnemyPartyCount] + dec a + cp b + jr nc, .notPastLastEnemyMon +; when switching to the enemy mon menu, if the menu selection would be past the last enemy mon, select the last enemy mon + ld [wCurrentMenuItem], a +.notPastLastEnemyMon + jp .enemyMonMenu +.playerMonMenu_RightNotPressed + bit 7, a ; Down pressed? + jr z, .getNewInput + jp .selectedCancelMenuItem ; jump if Down pressed +.getNewInput + ld a, [wWhichTradeMonSelectionMenu] + and a + jp z, .playerMonMenu_HandleInput + jp .enemyMonMenu_HandleInput +.chosePlayerMon + call SaveScreenTilesToBuffer1 + call PlaceUnfilledArrowMenuCursor + ld a, [wMaxMenuItem] + ld c, a + ld a, [wCurrentMenuItem] + cp c + jr c, .displayStatsTradeMenu + ld a, [wMaxMenuItem] + dec a +.displayStatsTradeMenu + push af + coord hl, 0, 14 + ld b, 2 + ld c, 18 + call CableClub_TextBoxBorder + coord hl, 2, 16 + ld de, .statsTrade + call PlaceString + xor a + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + ld [wMenuJoypadPollCount], a + ld [wMaxMenuItem], a + ld a, 16 + ld [wTopMenuItemY], a +.selectStatsMenuItem + ld a, " " + Coorda 11, 16 + ld a, D_RIGHT | B_BUTTON | A_BUTTON + ld [wMenuWatchedKeys], a + ld a, 1 + ld [wTopMenuItemX], a + call HandleMenuInput + bit 4, a ; Right pressed? + jr nz, .selectTradeMenuItem + bit 1, a ; B button pressed? + jr z, .displayPlayerMonStats +.cancelPlayerMonChoice + pop af + ld [wCurrentMenuItem], a + call LoadScreenTilesFromBuffer1 + jp .playerMonMenu +.selectTradeMenuItem + ld a, " " + Coorda 1, 16 + ld a, D_LEFT | B_BUTTON | A_BUTTON + ld [wMenuWatchedKeys], a + ld a, 11 + ld [wTopMenuItemX], a + call HandleMenuInput + bit 5, a ; Left pressed? + jr nz, .selectStatsMenuItem + bit 1, a ; B button pressed? + jr nz, .cancelPlayerMonChoice + jr .choseTrade +.displayPlayerMonStats + pop af + ld [wCurrentMenuItem], a + ld a, INIT_PLAYEROT_LIST + ld [wInitListType], a + callab InitList ; the list isn't used + call TradeCenter_DisplayStats + call LoadScreenTilesFromBuffer1 + jp .playerMonMenu +.choseTrade + call PlaceUnfilledArrowMenuCursor + pop af + ld [wCurrentMenuItem], a + ld [wTradingWhichPlayerMon], a + ld [wSerialExchangeNybbleSendData], a + call Serial_PrintWaitingTextAndSyncAndExchangeNybble + ld a, [wSerialSyncAndExchangeNybbleReceiveData] + cp $f + jp z, CallCurrentTradeCenterFunction ; go back to the beginning of the trade selection menu if the other person cancelled + ld [wTradingWhichEnemyMon], a + call TradeCenter_PlaceSelectedEnemyMonMenuCursor + ld a, $1 ; TradeCenter_Trade + ld [wTradeCenterPointerTableIndex], a + jp CallCurrentTradeCenterFunction +.statsTrade + db "STATS TRADE@" +.selectedCancelMenuItem + ld a, [wCurrentMenuItem] + ld b, a + ld a, [wMaxMenuItem] + cp b + jp nz, .getNewInput + ld a, [wMenuCursorLocation] + ld l, a + ld a, [wMenuCursorLocation + 1] + ld h, a + ld a, " " + ld [hl], a +.cancelMenuItem_Loop + ld a, "▶" ; filled arrow cursor + Coorda 1, 16 +.cancelMenuItem_JoypadLoop + call JoypadLowSensitivity + ld a, [hJoy5] + and a ; pressed anything? + jr z, .cancelMenuItem_JoypadLoop + bit 0, a ; A button pressed? + jr nz, .cancelMenuItem_APressed + bit 6, a ; Up pressed? + jr z, .cancelMenuItem_JoypadLoop +; if Up pressed + ld a, " " + Coorda 1, 16 + ld a, [wPartyCount] + dec a + ld [wCurrentMenuItem], a + jp .playerMonMenu +.cancelMenuItem_APressed + ld a, "▷" ; unfilled arrow cursor + Coorda 1, 16 + ld a, $f + ld [wSerialExchangeNybbleSendData], a + call Serial_PrintWaitingTextAndSyncAndExchangeNybble + ld a, [wSerialSyncAndExchangeNybbleReceiveData] + cp $f ; did the other person choose Cancel too? + jr nz, .cancelMenuItem_Loop + ; fall through + +ReturnToCableClubRoom: + call GBPalWhiteOutWithDelay3 + ld hl, wFontLoaded + ld a, [hl] + push af + push hl + res 0, [hl] + xor a + ld [wd72d], a + dec a + ld [wDestinationWarpID], a + call LoadMapData + callba ClearVariablesOnEnterMap + pop hl + pop af + ld [hl], a + call GBFadeInFromWhite + ret + +TradeCenter_DrawCancelBox: + coord hl, 11, 15 + ld a, $7e + ld bc, 2 * SCREEN_WIDTH + 9 + call FillMemory + coord hl, 0, 15 + ld b, 1 + ld c, 9 + call CableClub_TextBoxBorder + coord hl, 2, 16 + ld de, CancelTextString + jp PlaceString + +CancelTextString: + db "CANCEL@" + +TradeCenter_PlaceSelectedEnemyMonMenuCursor: + ld a, [wSerialSyncAndExchangeNybbleReceiveData] + coord hl, 1, 9 + ld bc, SCREEN_WIDTH + call AddNTimes + ld [hl], "▷" ; cursor + ret + +TradeCenter_DisplayStats: + ld a, [wCurrentMenuItem] + ld [wWhichPokemon], a + predef StatusScreen + predef StatusScreen2 + call GBPalNormal + call LoadTrainerInfoTextBoxTiles + call TradeCenter_DrawPartyLists + jp TradeCenter_DrawCancelBox + +TradeCenter_DrawPartyLists: + coord hl, 0, 0 + ld b, 6 + ld c, 18 + call CableClub_TextBoxBorder + coord hl, 0, 8 + ld b, 6 + ld c, 18 + call CableClub_TextBoxBorder + coord hl, 5, 0 + ld de, wPlayerName + call PlaceString + coord hl, 5, 8 + ld de, wLinkEnemyTrainerName + call PlaceString + coord hl, 2, 1 + ld de, wPartySpecies + call TradeCenter_PrintPartyListNames + coord hl, 2, 9 + ld de, wEnemyPartyMons + ; fall through + +TradeCenter_PrintPartyListNames: + ld c, $0 +.loop + ld a, [de] + cp $ff + ret z + ld [wd11e], a + push bc + push hl + push de + push hl + ld a, c + ld [$ff95], a + call GetMonName + pop hl + call PlaceString + pop de + inc de + pop hl + ld bc, 20 + add hl, bc + pop bc + inc c + jr .loop + +TradeCenter_Trade: + ld c, 100 + call DelayFrames + xor a + ld [wSerialExchangeNybbleSendData + 1], a ; unnecessary + ld [wSerialExchangeNybbleReceiveData], a + ld [wMenuWatchMovingOutOfBounds], a + ld [wMenuJoypadPollCount], a + coord hl, 0, 12 + ld b, 4 + ld c, 18 + call CableClub_TextBoxBorder + ld a, [wTradingWhichPlayerMon] + ld hl, wPartySpecies + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [wd11e], a + call GetMonName + ld hl, wcd6d + ld de, wNameOfPlayerMonToBeTraded + ld bc, NAME_LENGTH + call CopyData + ld a, [wTradingWhichEnemyMon] + ld hl, wEnemyPartyMons + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ld [wd11e], a + call GetMonName + ld hl, WillBeTradedText + coord bc, 1, 14 + call TextCommandProcessor + call SaveScreenTilesToBuffer1 + coord hl, 10, 7 + lb bc, 8, 11 + ld a, TRADE_CANCEL_MENU + ld [wTwoOptionMenuID], a + ld a, TWO_OPTION_MENU + ld [wTextBoxID], a + call DisplayTextBoxID + call LoadScreenTilesFromBuffer1 + ld a, [wCurrentMenuItem] + and a + jr z, .tradeConfirmed +; if trade cancelled + ld a, $1 + ld [wSerialExchangeNybbleSendData], a + coord hl, 0, 12 + ld b, 4 + ld c, 18 + call CableClub_TextBoxBorder + coord hl, 1, 14 + ld de, TradeCanceled + call PlaceString + call Serial_PrintWaitingTextAndSyncAndExchangeNybble + jp .tradeCancelled +.tradeConfirmed + ld a, $2 + ld [wSerialExchangeNybbleSendData], a + call Serial_PrintWaitingTextAndSyncAndExchangeNybble + ld a, [wSerialSyncAndExchangeNybbleReceiveData] + dec a ; did the other person cancel? + jr nz, .doTrade +; if the other person cancelled + coord hl, 0, 12 + ld b, 4 + ld c, 18 + call CableClub_TextBoxBorder + coord hl, 1, 14 + ld de, TradeCanceled + call PlaceString + jp .tradeCancelled +.doTrade + ld a, [wTradingWhichPlayerMon] + ld hl, wPartyMonOT + call SkipFixedLengthTextEntries + ld de, wTradedPlayerMonOT + ld bc, NAME_LENGTH + call CopyData + ld hl, wPartyMon1Species + ld a, [wTradingWhichPlayerMon] + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld bc, wPartyMon1OTID - wPartyMon1 + add hl, bc + ld a, [hli] + ld [wTradedPlayerMonOTID], a + ld a, [hl] + ld [wTradedPlayerMonOTID + 1], a + ld a, [wTradingWhichEnemyMon] + ld hl, wEnemyMonOT + call SkipFixedLengthTextEntries + ld de, wTradedEnemyMonOT + ld bc, NAME_LENGTH + call CopyData + ld hl, wEnemyMons + ld a, [wTradingWhichEnemyMon] + ld bc, wEnemyMon2 - wEnemyMon1 + call AddNTimes + ld bc, wEnemyMon1OTID - wEnemyMon1 + add hl, bc + ld a, [hli] + ld [wTradedEnemyMonOTID], a + ld a, [hl] + ld [wTradedEnemyMonOTID + 1], a + ld a, [wTradingWhichPlayerMon] + ld [wWhichPokemon], a + ld hl, wPartySpecies + ld b, 0 + ld c, a + add hl, bc + ld a, [hl] + ld [wTradedPlayerMonSpecies], a + xor a + ld [wRemoveMonFromBox], a + call RemovePokemon + ld a, [wTradingWhichEnemyMon] + ld c, a + ld [wWhichPokemon], a + ld hl, wEnemyPartyMons + ld d, 0 + ld e, a + add hl, de + ld a, [hl] + ld [wcf91], a + ld hl, wEnemyMons + ld a, c + ld bc, wEnemyMon2 - wEnemyMon1 + call AddNTimes + ld de, wLoadedMon + ld bc, wEnemyMon2 - wEnemyMon1 + call CopyData + call AddEnemyMonToPlayerParty + ld a, [wPartyCount] + dec a + ld [wWhichPokemon], a + ld a, $1 + ld [wForceEvolution], a + ld a, [wTradingWhichEnemyMon] + ld hl, wEnemyPartyMons + ld b, 0 + ld c, a + add hl, bc + ld a, [hl] + ld [wTradedEnemyMonSpecies], a + ld a, 10 + ld [wAudioFadeOutControl], a + ld a, BANK(Music_SafariZone) + ld [wAudioSavedROMBank], a + ld a, MUSIC_SAFARI_ZONE + ld [wNewSoundID], a + call PlaySound + ld c, 100 + call DelayFrames + call ClearScreen + call LoadHpBarAndStatusTilePatterns + xor a + ld [wUnusedCC5B], a + ld a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + jr z, .usingExternalClock + predef InternalClockTradeAnim + jr .tradeCompleted +.usingExternalClock + predef ExternalClockTradeAnim +.tradeCompleted + callab TryEvolvingMon + call ClearScreen + call LoadTrainerInfoTextBoxTiles + call Serial_PrintWaitingTextAndSyncAndExchangeNybble + ld c, 40 + call DelayFrames + coord hl, 0, 12 + ld b, 4 + ld c, 18 + call CableClub_TextBoxBorder + coord hl, 1, 14 + ld de, TradeCompleted + call PlaceString + predef SaveSAVtoSRAM2 + ld c, 50 + call DelayFrames + xor a + ld [wTradeCenterPointerTableIndex], a + jp CableClub_DoBattleOrTradeAgain +.tradeCancelled + ld c, 100 + call DelayFrames + xor a ; TradeCenter_SelectMon + ld [wTradeCenterPointerTableIndex], a + jp CallCurrentTradeCenterFunction + +WillBeTradedText: + TX_FAR _WillBeTradedText + db "@" + +TradeCompleted: + db "Trade completed!@" + +TradeCanceled: + db "Too bad! The trade" + next "was canceled!@" + +TradeCenterPointerTable: + dw TradeCenter_SelectMon + dw TradeCenter_Trade + +CableClub_Run: + ld a, [wLinkState] + cp LINK_STATE_START_TRADE + jr z, .doBattleOrTrade + cp LINK_STATE_START_BATTLE + jr z, .doBattleOrTrade + cp LINK_STATE_RESET ; this is never used + ret nz + predef EmptyFunc3 + jp Init +.doBattleOrTrade + call CableClub_DoBattleOrTrade + ld hl, Club_GFX + ld a, h + ld [wTilesetGfxPtr + 1], a + ld a, l + ld [wTilesetGfxPtr], a + ld a, Bank(Club_GFX) + ld [wTilesetBank], a + ld hl, Club_Coll + ld a, h + ld [wTilesetCollisionPtr + 1], a + ld a, l + ld [wTilesetCollisionPtr], a + xor a + ld [wGrassRate], a + inc a ; LINK_STATE_IN_CABLE_CLUB + ld [wLinkState], a + ld [hJoy5], a + ld a, 10 + ld [wAudioFadeOutControl], a + ld a, BANK(Music_Celadon) + ld [wAudioSavedROMBank], a + ld a, MUSIC_CELADON + ld [wNewSoundID], a + jp PlaySound + +EmptyFunc3: + ret + +Diploma_TextBoxBorder: + call GetPredefRegisters + +; b = height +; c = width +CableClub_TextBoxBorder: + push hl + ld a, $78 ; border upper left corner tile + ld [hli], a + inc a ; border top horizontal line tile + call CableClub_DrawHorizontalLine + inc a ; border upper right corner tile + ld [hl], a + pop hl + ld de, 20 + add hl, de +.loop + push hl + ld a, $7b ; border left vertical line tile + ld [hli], a + ld a, " " + call CableClub_DrawHorizontalLine + ld [hl], $77 ; border right vertical line tile + pop hl + ld de, 20 + add hl, de + dec b + jr nz, .loop + ld a, $7c ; border lower left corner tile + ld [hli], a + ld a, $76 ; border bottom horizontal line tile + call CableClub_DrawHorizontalLine + ld [hl], $7d ; border lower right corner tile + ret + +; c = width +CableClub_DrawHorizontalLine: + ld d, c +.loop + ld [hli], a + dec d + jr nz, .loop + ret + +LoadTrainerInfoTextBoxTiles: + ld de, TrainerInfoTextBoxTileGraphics + ld hl, vChars2 + $760 + lb bc, BANK(TrainerInfoTextBoxTileGraphics), (TrainerInfoTextBoxTileGraphicsEnd - TrainerInfoTextBoxTileGraphics) / $10 + jp CopyVideoData diff --git a/engine/link/cable_club_npc.asm b/engine/link/cable_club_npc.asm new file mode 100755 index 00000000..bb0f7680 --- /dev/null +++ b/engine/link/cable_club_npc.asm @@ -0,0 +1,151 @@ +CableClubNPC:: + ld hl, CableClubNPCWelcomeText + call PrintText + CheckEvent EVENT_GOT_POKEDEX + jp nz, .receivedPokedex +; if the player hasn't received the pokedex + ld c, 60 + call DelayFrames + ld hl, CableClubNPCMakingPreparationsText + call PrintText + jp .didNotConnect +.receivedPokedex + ld a, $1 + ld [wMenuJoypadPollCount], a + ld a, 90 + ld [wLinkTimeoutCounter], a +.establishConnectionLoop + ld a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + jr z, .establishedConnection + cp USING_EXTERNAL_CLOCK + jr z, .establishedConnection + ld a, CONNECTION_NOT_ESTABLISHED + ld [hSerialConnectionStatus], a + ld a, ESTABLISH_CONNECTION_WITH_EXTERNAL_CLOCK + ld [rSB], a + xor a + ld [hSerialReceiveData], a + ld a, START_TRANSFER_EXTERNAL_CLOCK + ld [rSC], a + ld a, [wLinkTimeoutCounter] + dec a + ld [wLinkTimeoutCounter], a + jr z, .failedToEstablishConnection + ld a, ESTABLISH_CONNECTION_WITH_INTERNAL_CLOCK + ld [rSB], a + ld a, START_TRANSFER_INTERNAL_CLOCK + ld [rSC], a + call DelayFrame + jr .establishConnectionLoop +.establishedConnection + call Serial_SendZeroByte + call DelayFrame + call Serial_SendZeroByte + ld c, 50 + call DelayFrames + ld hl, CableClubNPCPleaseApplyHereHaveToSaveText + call PrintText + xor a + ld [wMenuJoypadPollCount], a + call YesNoChoice + ld a, $1 + ld [wMenuJoypadPollCount], a + ld a, [wCurrentMenuItem] + and a + jr nz, .choseNo + callab SaveSAVtoSRAM + call WaitForSoundToFinish + ld a, SFX_SAVE + call PlaySoundWaitForCurrent + ld hl, CableClubNPCPleaseWaitText + call PrintText + ld hl, wUnknownSerialCounter + ld a, $3 + ld [hli], a + xor a + ld [hl], a + ld [hSerialReceivedNewData], a + ld [wSerialExchangeNybbleSendData], a + call Serial_SyncAndExchangeNybble + ld hl, wUnknownSerialCounter + ld a, [hli] + inc a + jr nz, .connected + ld a, [hl] + inc a + jr nz, .connected + ld b, 10 +.syncLoop + call DelayFrame + call Serial_SendZeroByte + dec b + jr nz, .syncLoop + call CloseLinkConnection + ld hl, CableClubNPCLinkClosedBecauseOfInactivityText + call PrintText + jr .didNotConnect +.failedToEstablishConnection + ld hl, CableClubNPCAreaReservedFor2FriendsLinkedByCableText + call PrintText + jr .didNotConnect +.choseNo + call CloseLinkConnection + ld hl, CableClubNPCPleaseComeAgainText + call PrintText +.didNotConnect + xor a + ld hl, wUnknownSerialCounter + ld [hli], a + ld [hl], a + ld hl, wd72e + res 6, [hl] + xor a + ld [wMenuJoypadPollCount], a + ret +.connected + xor a + ld [hld], a + ld [hl], a + jpab LinkMenu + +CableClubNPCAreaReservedFor2FriendsLinkedByCableText: + TX_FAR _CableClubNPCAreaReservedFor2FriendsLinkedByCableText + db "@" + +CableClubNPCWelcomeText: + TX_FAR _CableClubNPCWelcomeText + db "@" + +CableClubNPCPleaseApplyHereHaveToSaveText: + TX_FAR _CableClubNPCPleaseApplyHereHaveToSaveText + db "@" + +CableClubNPCPleaseWaitText: + TX_FAR _CableClubNPCPleaseWaitText + TX_DELAY + db "@" + +CableClubNPCLinkClosedBecauseOfInactivityText: + TX_FAR _CableClubNPCLinkClosedBecauseOfInactivityText + db "@" + +CableClubNPCPleaseComeAgainText: + TX_FAR _CableClubNPCPleaseComeAgainText + db "@" + +CableClubNPCMakingPreparationsText: + TX_FAR _CableClubNPCMakingPreparationsText + db "@" + +CloseLinkConnection: + call Delay3 + ld a, CONNECTION_NOT_ESTABLISHED + ld [hSerialConnectionStatus], a + ld a, ESTABLISH_CONNECTION_WITH_EXTERNAL_CLOCK + ld [rSB], a + xor a + ld [hSerialReceiveData], a + ld a, START_TRANSFER_EXTERNAL_CLOCK + ld [rSC], a + ret diff --git a/engine/link/print_waiting_text.asm b/engine/link/print_waiting_text.asm new file mode 100644 index 00000000..c48459d3 --- /dev/null +++ b/engine/link/print_waiting_text.asm @@ -0,0 +1,20 @@ +PrintWaitingText:: + coord hl, 3, 10 + ld b, $1 + ld c, $b + ld a, [wIsInBattle] + and a + jr z, .asm_4c17 + call TextBoxBorder + jr .asm_4c1a +.asm_4c17 + call CableClub_TextBoxBorder +.asm_4c1a + coord hl, 4, 11 + ld de, WaitingText + call PlaceString + ld c, 50 + jp DelayFrames + +WaitingText: + db "Waiting...!@" diff --git a/engine/load_mon_data.asm b/engine/load_mon_data.asm deleted file mode 100644 index 480ab1ca..00000000 --- a/engine/load_mon_data.asm +++ /dev/null @@ -1,49 +0,0 @@ -LoadMonData_:: -; Load monster [wWhichPokemon] from list [wMonDataLocation]: -; 0: partymon -; 1: enemymon -; 2: boxmon -; 3: daycaremon -; Return monster id at wcf91 and its data at wLoadedMon. -; Also load base stats at wMonHeader for convenience. - - ld a, [wDayCareMonSpecies] - ld [wcf91], a - ld a, [wMonDataLocation] - cp DAYCARE_DATA - jr z, .GetMonHeader - - ld a, [wWhichPokemon] - ld e, a - callab GetMonSpecies - -.GetMonHeader - ld a, [wcf91] - ld [wd0b5], a ; input for GetMonHeader - call GetMonHeader - - ld hl, wPartyMons - ld bc, wPartyMon2 - wPartyMon1 - ld a, [wMonDataLocation] - cp ENEMY_PARTY_DATA - jr c, .getMonEntry - - ld hl, wEnemyMons - jr z, .getMonEntry - - cp 2 - ld hl, wBoxMons - ld bc, wBoxMon2 - wBoxMon1 - jr z, .getMonEntry - - ld hl, wDayCareMon - jr .copyMonData - -.getMonEntry - ld a, [wWhichPokemon] - call AddNTimes - -.copyMonData - ld de, wLoadedMon - ld bc, wPartyMon2 - wPartyMon1 - jp CopyData diff --git a/engine/load_pokedex_tiles.asm b/engine/load_pokedex_tiles.asm deleted file mode 100755 index 70bcf04d..00000000 --- a/engine/load_pokedex_tiles.asm +++ /dev/null @@ -1,11 +0,0 @@ -; Loads tile patterns for tiles used in the pokedex. -LoadPokedexTilePatterns: - call LoadHpBarAndStatusTilePatterns - ld de, PokedexTileGraphics - ld hl, vChars2 + $600 - lb bc, BANK(PokedexTileGraphics), (PokedexTileGraphicsEnd - PokedexTileGraphics) / $10 - call CopyVideoData - ld de, PokeballTileGraphics - ld hl, vChars2 + $720 - lb bc, BANK(PokeballTileGraphics), $01 - jp CopyVideoData ; load pokeball tile for marking caught mons diff --git a/engine/math/bcd.asm b/engine/math/bcd.asm new file mode 100644 index 00000000..2d0b43df --- /dev/null +++ b/engine/math/bcd.asm @@ -0,0 +1,214 @@ +DivideBCDPredef:: +DivideBCDPredef2:: +DivideBCDPredef3:: +DivideBCDPredef4:: + call GetPredefRegisters + +DivideBCD:: + xor a + ld [hDivideBCDBuffer], a + ld [hDivideBCDBuffer+1], a + ld [hDivideBCDBuffer+2], a + ld d, $1 +.mulBy10Loop +; multiply the divisor by 10 until the leading digit is nonzero +; to set up the standard long division algorithm + ld a, [hDivideBCDDivisor] + and $f0 + jr nz, .next + inc d + ld a, [hDivideBCDDivisor] + swap a + and $f0 + ld b, a + ld a, [hDivideBCDDivisor+1] + swap a + ld [hDivideBCDDivisor+1], a + and $f + or b + ld [hDivideBCDDivisor], a + ld a, [hDivideBCDDivisor+1] + and $f0 + ld b, a + ld a, [hDivideBCDDivisor+2] + swap a + ld [hDivideBCDDivisor+2], a + and $f + or b + ld [hDivideBCDDivisor+1], a + ld a, [hDivideBCDDivisor+2] + and $f0 + ld [hDivideBCDDivisor+2], a + jr .mulBy10Loop +.next + push de + push de + call DivideBCD_getNextDigit + pop de + ld a, b + swap a + and $f0 + ld [hDivideBCDBuffer], a + dec d + jr z, .next2 + push de + call DivideBCD_divDivisorBy10 + call DivideBCD_getNextDigit + pop de + ld a, [hDivideBCDBuffer] + or b + ld [hDivideBCDBuffer], a + dec d + jr z, .next2 + push de + call DivideBCD_divDivisorBy10 + call DivideBCD_getNextDigit + pop de + ld a, b + swap a + and $f0 + ld [hDivideBCDBuffer+1], a + dec d + jr z, .next2 + push de + call DivideBCD_divDivisorBy10 + call DivideBCD_getNextDigit + pop de + ld a, [hDivideBCDBuffer+1] + or b + ld [hDivideBCDBuffer+1], a + dec d + jr z, .next2 + push de + call DivideBCD_divDivisorBy10 + call DivideBCD_getNextDigit + pop de + ld a, b + swap a + and $f0 + ld [hDivideBCDBuffer+2], a + dec d + jr z, .next2 + push de + call DivideBCD_divDivisorBy10 + call DivideBCD_getNextDigit + pop de + ld a, [hDivideBCDBuffer+2] + or b + ld [hDivideBCDBuffer+2], a +.next2 + ld a, [hDivideBCDBuffer] + ld [hDivideBCDQuotient], a ; the same memory location as hDivideBCDDivisor + ld a, [hDivideBCDBuffer+1] + ld [hDivideBCDQuotient+1], a + ld a, [hDivideBCDBuffer+2] + ld [hDivideBCDQuotient+2], a + pop de + ld a, $6 + sub d + and a + ret z +.divResultBy10loop + push af + call DivideBCD_divDivisorBy10 + pop af + dec a + jr nz, .divResultBy10loop + ret + +DivideBCD_divDivisorBy10: + ld a, [hDivideBCDDivisor+2] + swap a + and $f + ld b, a + ld a, [hDivideBCDDivisor+1] + swap a + ld [hDivideBCDDivisor+1], a + and $f0 + or b + ld [hDivideBCDDivisor+2], a + ld a, [hDivideBCDDivisor+1] + and $f + ld b, a + ld a, [hDivideBCDDivisor] + swap a + ld [hDivideBCDDivisor], a + and $f0 + or b + ld [hDivideBCDDivisor+1], a + ld a, [hDivideBCDDivisor] + and $f + ld [hDivideBCDDivisor], a + ret + +DivideBCD_getNextDigit: + ld bc, $3 +.loop + ld de, hMoney ; the dividend + ld hl, hDivideBCDDivisor + push bc + call StringCmp + pop bc + ret c + inc b + ld de, hMoney+2 ; since SubBCD works starting from the least significant digit + ld hl, hDivideBCDDivisor+2 + push bc + call SubBCD + pop bc + jr .loop + + +AddBCDPredef:: + call GetPredefRegisters + +AddBCD:: + and a + ld b, c +.add + ld a, [de] + adc [hl] + daa + ld [de], a + dec de + dec hl + dec c + jr nz, .add + jr nc, .done + ld a, $99 + inc de +.fill + ld [de], a + inc de + dec b + jr nz, .fill +.done + ret + + +SubBCDPredef:: + call GetPredefRegisters + +SubBCD:: + and a + ld b, c +.sub + ld a, [de] + sbc [hl] + daa + ld [de], a + dec de + dec hl + dec c + jr nz, .sub + jr nc, .done + ld a, $00 + inc de +.fill + ld [de], a + inc de + dec b + jr nz, .fill + scf +.done + ret diff --git a/engine/math/multiply_divide.asm b/engine/math/multiply_divide.asm new file mode 100755 index 00000000..6cdc6c87 --- /dev/null +++ b/engine/math/multiply_divide.asm @@ -0,0 +1,143 @@ +_Multiply:: + ld a, $8 + ld b, a + xor a + ld [H_PRODUCT], a + ld [H_MULTIPLYBUFFER], a + ld [H_MULTIPLYBUFFER+1], a + ld [H_MULTIPLYBUFFER+2], a + ld [H_MULTIPLYBUFFER+3], a +.loop + ld a, [H_MULTIPLIER] + srl a + ld [H_MULTIPLIER], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN) + jr nc, .smallMultiplier + ld a, [H_MULTIPLYBUFFER+3] + ld c, a + ld a, [H_MULTIPLICAND+2] + add c + ld [H_MULTIPLYBUFFER+3], a + ld a, [H_MULTIPLYBUFFER+2] + ld c, a + ld a, [H_MULTIPLICAND+1] + adc c + ld [H_MULTIPLYBUFFER+2], a + ld a, [H_MULTIPLYBUFFER+1] + ld c, a + ld a, [H_MULTIPLICAND] ; (aliases: H_MULTIPLICAND) + adc c + ld [H_MULTIPLYBUFFER+1], a + ld a, [H_MULTIPLYBUFFER] + ld c, a + ld a, [H_PRODUCT] ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT) + adc c + ld [H_MULTIPLYBUFFER], a +.smallMultiplier + dec b + jr z, .done + ld a, [H_MULTIPLICAND+2] + sla a + ld [H_MULTIPLICAND+2], a + ld a, [H_MULTIPLICAND+1] + rl a + ld [H_MULTIPLICAND+1], a + ld a, [H_MULTIPLICAND] + rl a + ld [H_MULTIPLICAND], a + ld a, [H_PRODUCT] + rl a + ld [H_PRODUCT], a + jr .loop +.done + ld a, [H_MULTIPLYBUFFER+3] + ld [H_PRODUCT+3], a + ld a, [H_MULTIPLYBUFFER+2] + ld [H_PRODUCT+2], a + ld a, [H_MULTIPLYBUFFER+1] + ld [H_PRODUCT+1], a + ld a, [H_MULTIPLYBUFFER] + ld [H_PRODUCT], a + ret + +_Divide:: + xor a + ld [H_DIVIDEBUFFER], a + ld [H_DIVIDEBUFFER+1], a + ld [H_DIVIDEBUFFER+2], a + ld [H_DIVIDEBUFFER+3], a + ld [H_DIVIDEBUFFER+4], a + ld a, $9 + ld e, a +.asm_37db3 + ld a, [H_DIVIDEBUFFER] + ld c, a + ld a, [H_DIVIDEND+1] ; (aliases: H_MULTIPLICAND) + sub c + ld d, a + ld a, [H_DIVISOR] ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN) + ld c, a + ld a, [H_DIVIDEND] ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT) + sbc c + jr c, .asm_37dce + ld [H_DIVIDEND], a ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT) + ld a, d + ld [H_DIVIDEND+1], a ; (aliases: H_MULTIPLICAND) + ld a, [H_DIVIDEBUFFER+4] + inc a + ld [H_DIVIDEBUFFER+4], a + jr .asm_37db3 +.asm_37dce + ld a, b + cp $1 + jr z, .asm_37e18 + ld a, [H_DIVIDEBUFFER+4] + sla a + ld [H_DIVIDEBUFFER+4], a + ld a, [H_DIVIDEBUFFER+3] + rl a + ld [H_DIVIDEBUFFER+3], a + ld a, [H_DIVIDEBUFFER+2] + rl a + ld [H_DIVIDEBUFFER+2], a + ld a, [H_DIVIDEBUFFER+1] + rl a + ld [H_DIVIDEBUFFER+1], a + dec e + jr nz, .asm_37e04 + ld a, $8 + ld e, a + ld a, [H_DIVIDEBUFFER] + ld [H_DIVISOR], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN) + xor a + ld [H_DIVIDEBUFFER], a + ld a, [H_DIVIDEND+1] ; (aliases: H_MULTIPLICAND) + ld [H_DIVIDEND], a ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT) + ld a, [H_DIVIDEND+2] + ld [H_DIVIDEND+1], a ; (aliases: H_MULTIPLICAND) + ld a, [H_DIVIDEND+3] + ld [H_DIVIDEND+2], a +.asm_37e04 + ld a, e + cp $1 + jr nz, .asm_37e0a + dec b +.asm_37e0a + ld a, [H_DIVISOR] ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN) + srl a + ld [H_DIVISOR], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN) + ld a, [H_DIVIDEBUFFER] + rr a + ld [H_DIVIDEBUFFER], a + jr .asm_37db3 +.asm_37e18 + ld a, [H_DIVIDEND+1] ; (aliases: H_MULTIPLICAND) + ld [H_REMAINDER], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN) + ld a, [H_DIVIDEBUFFER+4] + ld [H_QUOTIENT+3], a + ld a, [H_DIVIDEBUFFER+3] + ld [H_QUOTIENT+2], a + ld a, [H_DIVIDEBUFFER+2] + ld [H_QUOTIENT+1], a ; (aliases: H_MULTIPLICAND) + ld a, [H_DIVIDEBUFFER+1] + ld [H_DIVIDEND], a ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT) + ret diff --git a/engine/math/random.asm b/engine/math/random.asm new file mode 100755 index 00000000..2fc83f6f --- /dev/null +++ b/engine/math/random.asm @@ -0,0 +1,13 @@ +Random_:: +; Generate a random 16-bit value. + ld a, [rDIV] + ld b, a + ld a, [hRandomAdd] + adc b + ld [hRandomAdd], a + ld a, [rDIV] + ld b, a + ld a, [hRandomSub] + sbc b + ld [hRandomSub], a + ret diff --git a/engine/menu/bills_pc.asm b/engine/menu/bills_pc.asm deleted file mode 100644 index 6f643228..00000000 --- a/engine/menu/bills_pc.asm +++ /dev/null @@ -1,554 +0,0 @@ -DisplayPCMainMenu:: - xor a - ld [H_AUTOBGTRANSFERENABLED], a - call SaveScreenTilesToBuffer2 - ld a, [wNumHoFTeams] - and a - jr nz, .leaguePCAvailable - CheckEvent EVENT_GOT_POKEDEX - jr z, .noOaksPC - ld a, [wNumHoFTeams] - and a - jr nz, .leaguePCAvailable - coord hl, 0, 0 - ld b, 8 - ld c, 14 - jr .next -.noOaksPC - coord hl, 0, 0 - ld b, 6 - ld c, 14 - jr .next -.leaguePCAvailable - coord hl, 0, 0 - ld b, 10 - ld c, 14 -.next - call TextBoxBorder - call UpdateSprites - ld a, 3 - ld [wMaxMenuItem], a - CheckEvent EVENT_MET_BILL - jr nz, .metBill - coord hl, 2, 2 - ld de, SomeonesPCText - jr .next2 -.metBill - coord hl, 2, 2 - ld de, BillsPCText -.next2 - call PlaceString - coord hl, 2, 4 - ld de, wPlayerName - call PlaceString - ld l, c - ld h, b - ld de, PlayersPCText - call PlaceString - CheckEvent EVENT_GOT_POKEDEX - jr z, .noOaksPC2 - coord hl, 2, 6 - ld de, OaksPCText - call PlaceString - ld a, [wNumHoFTeams] - and a - jr z, .noLeaguePC - ld a, 4 - ld [wMaxMenuItem], a - coord hl, 2, 8 - ld de, PKMNLeaguePCText - call PlaceString - coord hl, 2, 10 - ld de, LogOffPCText - jr .next3 -.noLeaguePC - coord hl, 2, 8 - ld de, LogOffPCText - jr .next3 -.noOaksPC2 - ld a, $2 - ld [wMaxMenuItem], a - coord hl, 2, 6 - ld de, LogOffPCText -.next3 - call PlaceString - ld a, A_BUTTON | B_BUTTON - ld [wMenuWatchedKeys], a - ld a, 2 - ld [wTopMenuItemY], a - ld a, 1 - ld [wTopMenuItemX], a - xor a - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - ld a, 1 - ld [H_AUTOBGTRANSFERENABLED], a - ret - -SomeonesPCText: db "SOMEONE's PC@" -BillsPCText: db "BILL's PC@" -PlayersPCText: db "'s PC@" -OaksPCText: db "PROF.OAK's PC@" -PKMNLeaguePCText: db "LEAGUE@" -LogOffPCText: db "LOG OFF@" - -BillsPC_:: - ld hl, wd730 - set 6, [hl] - xor a - ld [wParentMenuItem], a - inc a ; MONSTER_NAME - ld [wNameListType], a - call LoadHpBarAndStatusTilePatterns - ld a, [wListScrollOffset] - push af - ld a, [wFlags_0xcd60] - bit 3, a ; accessing Bill's PC through another PC? - jr nz, BillsPCMenu -; accessing it directly - ld a, SFX_TURN_ON_PC - call PlaySound - ld hl, SwitchOnText - call PrintText - -BillsPCMenu: - ld a, [wParentMenuItem] - ld [wCurrentMenuItem], a - ld hl, vChars2 + $780 - ld de, PokeballTileGraphics - lb bc, BANK(PokeballTileGraphics), $01 - call CopyVideoData - call LoadScreenTilesFromBuffer2DisableBGTransfer - coord hl, 0, 0 - ld b, 10 - ld c, 12 - call TextBoxBorder - coord hl, 2, 2 - ld de, BillsPCMenuText - call PlaceString - ld hl, wTopMenuItemY - ld a, 2 - ld [hli], a ; wTopMenuItemY - dec a - ld [hli], a ; wTopMenuItemX - inc hl - inc hl - ld a, 4 - ld [hli], a ; wMaxMenuItem - ld a, A_BUTTON | B_BUTTON - ld [hli], a ; wMenuWatchedKeys - xor a - ld [hli], a ; wLastMenuItem - ld [hli], a ; wPartyAndBillsPCSavedMenuItem - ld hl, wListScrollOffset - ld [hli], a ; wListScrollOffset - ld [hl], a ; wMenuWatchMovingOutOfBounds - ld [wPlayerMonNumber], a - ld hl, WhatText - call PrintText - coord hl, 9, 14 - ld b, 2 - ld c, 9 - call TextBoxBorder - ld a, [wCurrentBoxNum] - and $7f - cp 9 - jr c, .singleDigitBoxNum -; two digit box num - sub 9 - coord hl, 17, 16 - ld [hl], "1" - add "0" - jr .next -.singleDigitBoxNum - add "1" -.next - Coorda 18, 16 - coord hl, 10, 16 - ld de, BoxNoPCText - call PlaceString - ld a, 1 - ld [H_AUTOBGTRANSFERENABLED], a - call Delay3 - call HandleMenuInput - bit 1, a - jp nz, ExitBillsPC ; b button - call PlaceUnfilledArrowMenuCursor - ld a, [wCurrentMenuItem] - ld [wParentMenuItem], a - and a - jp z, BillsPCWithdraw ; withdraw - cp $1 - jp z, BillsPCDeposit ; deposit - cp $2 - jp z, BillsPCRelease ; release - cp $3 - jp z, BillsPCChangeBox ; change box - -ExitBillsPC: - ld a, [wFlags_0xcd60] - bit 3, a ; accessing Bill's PC through another PC? - jr nz, .next -; accessing it directly - call LoadTextBoxTilePatterns - ld a, SFX_TURN_OFF_PC - call PlaySound - call WaitForSoundToFinish -.next - ld hl, wFlags_0xcd60 - res 5, [hl] - call LoadScreenTilesFromBuffer2 - pop af - ld [wListScrollOffset], a - ld hl, wd730 - res 6, [hl] - ret - -BillsPCDeposit: - ld a, [wPartyCount] - dec a - jr nz, .partyLargeEnough - ld hl, CantDepositLastMonText - call PrintText - jp BillsPCMenu -.partyLargeEnough - ld a, [wNumInBox] - cp MONS_PER_BOX - jr nz, .boxNotFull - ld hl, BoxFullText - call PrintText - jp BillsPCMenu -.boxNotFull - ld hl, wPartyCount - call DisplayMonListMenu - jp c, BillsPCMenu - call DisplayDepositWithdrawMenu - jp nc, BillsPCMenu - ld a, [wcf91] - call GetCryData - call PlaySoundWaitForCurrent - ld a, PARTY_TO_BOX - ld [wMoveMonType], a - call MoveMon - xor a - ld [wRemoveMonFromBox], a - call RemovePokemon - call WaitForSoundToFinish - ld hl, wBoxNumString - ld a, [wCurrentBoxNum] - and $7f - cp 9 - jr c, .singleDigitBoxNum - sub 9 - ld [hl], "1" - inc hl - add "0" - jr .next -.singleDigitBoxNum - add "1" -.next - ld [hli], a - ld [hl], "@" - ld hl, MonWasStoredText - call PrintText - jp BillsPCMenu - -BillsPCWithdraw: - ld a, [wNumInBox] - and a - jr nz, .boxNotEmpty - ld hl, NoMonText - call PrintText - jp BillsPCMenu -.boxNotEmpty - ld a, [wPartyCount] - cp PARTY_LENGTH - jr nz, .partyNotFull - ld hl, CantTakeMonText - call PrintText - jp BillsPCMenu -.partyNotFull - ld hl, wNumInBox - call DisplayMonListMenu - jp c, BillsPCMenu - call DisplayDepositWithdrawMenu - jp nc, BillsPCMenu - ld a, [wWhichPokemon] - ld hl, wBoxMonNicks - call GetPartyMonName - ld a, [wcf91] - call GetCryData - call PlaySoundWaitForCurrent - xor a ; BOX_TO_PARTY - ld [wMoveMonType], a - call MoveMon - ld a, 1 - ld [wRemoveMonFromBox], a - call RemovePokemon - call WaitForSoundToFinish - ld hl, MonIsTakenOutText - call PrintText - jp BillsPCMenu - -BillsPCRelease: - ld a, [wNumInBox] - and a - jr nz, .loop - ld hl, NoMonText - call PrintText - jp BillsPCMenu -.loop - ld hl, wNumInBox - call DisplayMonListMenu - jp c, BillsPCMenu - ld hl, OnceReleasedText - call PrintText - call YesNoChoice - ld a, [wCurrentMenuItem] - and a - jr nz, .loop - inc a - ld [wRemoveMonFromBox], a - call RemovePokemon - call WaitForSoundToFinish - ld a, [wcf91] - call PlayCry - ld hl, MonWasReleasedText - call PrintText - jp BillsPCMenu - -BillsPCChangeBox: - callba ChangeBox - jp BillsPCMenu - -DisplayMonListMenu: - ld a, l - ld [wListPointer], a - ld a, h - ld [wListPointer + 1], a - xor a - ld [wPrintItemPrices], a - ld [wListMenuID], a - inc a ; MONSTER_NAME - ld [wNameListType], a - ld a, [wPartyAndBillsPCSavedMenuItem] - ld [wCurrentMenuItem], a - call DisplayListMenuID - ld a, [wCurrentMenuItem] - ld [wPartyAndBillsPCSavedMenuItem], a - ret - -BillsPCMenuText: - db "WITHDRAW " - next "DEPOSIT " - next "RELEASE " - next "CHANGE BOX" - next "SEE YA!" - db "@" - -BoxNoPCText: - db "BOX No.@" - -KnowsHMMove:: -; returns whether mon with party index [wWhichPokemon] knows an HM move - ld hl, wPartyMon1Moves - ld bc, wPartyMon2 - wPartyMon1 - jr .next -; unreachable - ld hl, wBoxMon1Moves - ld bc, wBoxMon2 - wBoxMon1 -.next - ld a, [wWhichPokemon] - call AddNTimes - ld b, NUM_MOVES -.loop - ld a, [hli] - push hl - push bc - ld hl, HMMoveArray - ld de, 1 - call IsInArray - pop bc - pop hl - ret c - dec b - jr nz, .loop - and a - ret - -HMMoveArray: - db CUT - db FLY - db SURF - db STRENGTH - db FLASH - db -1 - -DisplayDepositWithdrawMenu: - coord hl, 9, 10 - ld b, 6 - ld c, 9 - call TextBoxBorder - ld a, [wParentMenuItem] - and a ; was the Deposit or Withdraw item selected in the parent menu? - ld de, DepositPCText - jr nz, .next - ld de, WithdrawPCText -.next - coord hl, 11, 12 - call PlaceString - coord hl, 11, 14 - ld de, StatsCancelPCText - call PlaceString - ld hl, wTopMenuItemY - ld a, 12 - ld [hli], a ; wTopMenuItemY - ld a, 10 - ld [hli], a ; wTopMenuItemX - xor a - ld [hli], a ; wCurrentMenuItem - inc hl - ld a, 2 - ld [hli], a ; wMaxMenuItem - ld a, A_BUTTON | B_BUTTON - ld [hli], a ; wMenuWatchedKeys - xor a - ld [hl], a ; wLastMenuItem - ld hl, wListScrollOffset - ld [hli], a ; wListScrollOffset - ld [hl], a ; wMenuWatchMovingOutOfBounds - ld [wPlayerMonNumber], a - ld [wPartyAndBillsPCSavedMenuItem], a -.loop - call HandleMenuInput - bit 1, a ; pressed B? - jr nz, .exit - ld a, [wCurrentMenuItem] - and a - jr z, .choseDepositWithdraw - dec a - jr z, .viewStats -.exit - and a - ret -.choseDepositWithdraw - scf - ret -.viewStats - call SaveScreenTilesToBuffer1 - ld a, [wParentMenuItem] - and a - ld a, PLAYER_PARTY_DATA - jr nz, .next2 - ld a, BOX_DATA -.next2 - ld [wMonDataLocation], a - predef StatusScreen - predef StatusScreen2 - call LoadScreenTilesFromBuffer1 - call ReloadTilesetTilePatterns - call RunDefaultPaletteCommand - call LoadGBPal - jr .loop - -DepositPCText: db "DEPOSIT@" -WithdrawPCText: db "WITHDRAW@" -StatsCancelPCText: - db "STATS" - next "CANCEL@" - -SwitchOnText: - TX_FAR _SwitchOnText - db "@" - -WhatText: - TX_FAR _WhatText - db "@" - -DepositWhichMonText: - TX_FAR _DepositWhichMonText - db "@" - -MonWasStoredText: - TX_FAR _MonWasStoredText - db "@" - -CantDepositLastMonText: - TX_FAR _CantDepositLastMonText - db "@" - -BoxFullText: - TX_FAR _BoxFullText - db "@" - -MonIsTakenOutText: - TX_FAR _MonIsTakenOutText - db "@" - -NoMonText: - TX_FAR _NoMonText - db "@" - -CantTakeMonText: - TX_FAR _CantTakeMonText - db "@" - -ReleaseWhichMonText: - TX_FAR _ReleaseWhichMonText - db "@" - -OnceReleasedText: - TX_FAR _OnceReleasedText - db "@" - -MonWasReleasedText: - TX_FAR _MonWasReleasedText - db "@" - -CableClubLeftGameboy:: - ld a, [hSerialConnectionStatus] - cp USING_EXTERNAL_CLOCK - ret z - ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction - cp SPRITE_FACING_RIGHT - ret nz - ld a, [wCurMap] - cp TRADE_CENTER - ld a, LINK_STATE_START_TRADE - jr z, .next - inc a ; LINK_STATE_START_BATTLE -.next - ld [wLinkState], a - call EnableAutoTextBoxDrawing - tx_pre_jump JustAMomentText - -CableClubRightGameboy:: - ld a, [hSerialConnectionStatus] - cp USING_INTERNAL_CLOCK - ret z - ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction - cp SPRITE_FACING_LEFT - ret nz - ld a, [wCurMap] - cp TRADE_CENTER - ld a, LINK_STATE_START_TRADE - jr z, .next - inc a ; LINK_STATE_START_BATTLE -.next - ld [wLinkState], a - call EnableAutoTextBoxDrawing - tx_pre_jump JustAMomentText - -JustAMomentText:: - TX_FAR _JustAMomentText - db "@" - - ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction - cp SPRITE_FACING_UP - ret nz - call EnableAutoTextBoxDrawing - tx_pre_jump OpenBillsPCText - -OpenBillsPCText:: - TX_BILLS_PC - diff --git a/engine/menu/diploma.asm b/engine/menu/diploma.asm deleted file mode 100755 index e53ef58f..00000000 --- a/engine/menu/diploma.asm +++ /dev/null @@ -1,113 +0,0 @@ -DisplayDiploma:: - call SaveScreenTilesToBuffer2 - call GBPalWhiteOutWithDelay3 - call ClearScreen - xor a - ld [wUpdateSpritesEnabled], a - ld hl, wd730 - set 6, [hl] - call DisableLCD - ld hl, CircleTile - ld de, vChars2 + $700 - ld bc, $0010 - ld a, BANK(CircleTile) - call FarCopyData2 - coord hl, 0, 0 - lb bc, 16, 18 - predef Diploma_TextBoxBorder - ld hl, DiplomaTextPointersAndCoords - ld c, $5 -.asm_56715 - push bc - ld a, [hli] - ld e, a - ld a, [hli] - ld d, a - ld a, [hli] - push hl - ld h, [hl] - ld l, a - call PlaceString - pop hl - inc hl - pop bc - dec c - jr nz, .asm_56715 - coord hl, 10, 4 - ld de, wPlayerName - call PlaceString - callba DrawPlayerCharacter - -; Move the player 33 pixels right and set the priority bit so he appears -; behind the background layer. - ld hl, wOAMBuffer + $01 - lb bc, $80, $28 -.adjustPlayerGfxLoop - ld a, [hl] ; X - add 33 - ld [hli], a - inc hl - ld a, b - ld [hli], a ; attributes - inc hl - dec c - jr nz, .adjustPlayerGfxLoop - - call EnableLCD - callba LoadTrainerInfoTextBoxTiles - ld b, SET_PAL_GENERIC - call RunPaletteCommand - call Delay3 - call GBPalNormal - ld a, $90 - ld [rOBP0], a - call WaitForTextScrollButtonPress - ld hl, wd730 - res 6, [hl] - call GBPalWhiteOutWithDelay3 - call RestoreScreenTilesAndReloadTilePatterns - call Delay3 - jp GBPalNormal - -UnusedPlayerNameLengthFunc: -; Unused function that does a calculation involving the length of the player's -; name. - ld hl, wPlayerName - ld bc, $ff00 -.loop - ld a, [hli] - cp "@" - ret z - dec c - jr .loop - -DiplomaTextPointersAndCoords: - dw DiplomaText - dwCoord 5, 2 - dw DiplomaPlayer - dwCoord 3, 4 - dw DiplomaEmptyText - dwCoord 15, 4 - dw DiplomaCongrats - dwCoord 2, 6 - dw DiplomaGameFreak - dwCoord 9, 16 - -DiplomaText: - db $70,"Diploma",$70,"@" - -DiplomaPlayer: - db "Player@" - -DiplomaEmptyText: - db "@" - -DiplomaCongrats: - db "Congrats! This" - next "diploma certifies" - next "that you have" - next "completed your" - next "#DEX.@" - -DiplomaGameFreak: - db "GAME FREAK@" diff --git a/engine/menu/draw_badges.asm b/engine/menu/draw_badges.asm deleted file mode 100644 index 1888e32f..00000000 --- a/engine/menu/draw_badges.asm +++ /dev/null @@ -1,120 +0,0 @@ -DrawBadges: -; Draw 4x2 gym leader faces, with the faces replaced by -; badges if they are owned. Used in the player status screen. - -; In Japanese versions, names are displayed above faces. -; Instead of removing relevant code, the name graphics were erased. - -; Tile ids for face/badge graphics. - ld de, wBadgeOrFaceTiles - ld hl, .FaceBadgeTiles - ld bc, 8 - call CopyData - -; Booleans for each badge. - ld hl, wTempObtainedBadgesBooleans - ld bc, 8 - xor a - call FillMemory - -; Alter these based on owned badges. - ld de, wTempObtainedBadgesBooleans - ld hl, wBadgeOrFaceTiles - ld a, [wObtainedBadges] - ld b, a - ld c, 8 -.CheckBadge - srl b - jr nc, .NextBadge - ld a, [hl] - add 4 ; Badge graphics are after each face - ld [hl], a - ld a, 1 - ld [de], a -.NextBadge - inc hl - inc de - dec c - jr nz, .CheckBadge - -; Draw two rows of badges. - ld hl, wBadgeNumberTile - ld a, $d8 ; [1] - ld [hli], a - ld [hl], $60 ; First name - - coord hl, 2, 11 - ld de, wTempObtainedBadgesBooleans - call .DrawBadgeRow - - coord hl, 2, 14 - ld de, wTempObtainedBadgesBooleans + 4 -; call .DrawBadgeRow -; ret - -.DrawBadgeRow -; Draw 4 badges. - - ld c, 4 -.DrawBadge - push de - push hl - -; Badge no. - ld a, [wBadgeNumberTile] - ld [hli], a - inc a - ld [wBadgeNumberTile], a - -; Names aren't printed if the badge is owned. - ld a, [de] - and a - ld a, [wBadgeNameTile] - jr nz, .SkipName - call .PlaceTiles - jr .PlaceBadge - -.SkipName - inc a - inc a - inc hl - -.PlaceBadge - ld [wBadgeNameTile], a - ld de, SCREEN_WIDTH - 1 - add hl, de - ld a, [wBadgeOrFaceTiles] - call .PlaceTiles - add hl, de - call .PlaceTiles - -; Shift badge array back one byte. - push bc - ld hl, wBadgeOrFaceTiles + 1 - ld de, wBadgeOrFaceTiles - ld bc, 8 - call CopyData - pop bc - - pop hl - ld de, 4 - add hl, de - - pop de - inc de - dec c - jr nz, .DrawBadge - ret - -.PlaceTiles - ld [hli], a - inc a - ld [hl], a - inc a - ret - -.FaceBadgeTiles - db $20, $28, $30, $38, $40, $48, $50, $58 - -GymLeaderFaceAndBadgeTileGraphics: - INCBIN "gfx/trainer_card/badges.2bpp" diff --git a/engine/menu/draw_start_menu.asm b/engine/menu/draw_start_menu.asm deleted file mode 100644 index 21e444e9..00000000 --- a/engine/menu/draw_start_menu.asm +++ /dev/null @@ -1,89 +0,0 @@ -; function that displays the start menu -DrawStartMenu:: - CheckEvent EVENT_GOT_POKEDEX -; menu with pokedex - coord hl, 10, 0 - ld b, $0e - ld c, $08 - jr nz, .drawTextBoxBorder -; shorter menu if the player doesn't have the pokedex - coord hl, 10, 0 - ld b, $0c - ld c, $08 -.drawTextBoxBorder - call TextBoxBorder - ld a, D_DOWN | D_UP | START | B_BUTTON | A_BUTTON - ld [wMenuWatchedKeys], a - ld a, $02 - ld [wTopMenuItemY], a ; Y position of first menu choice - ld a, $0b - ld [wTopMenuItemX], a ; X position of first menu choice - ld a, [wBattleAndStartSavedMenuItem] ; remembered menu selection from last time - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - xor a - ld [wMenuWatchMovingOutOfBounds], a - ld hl, wd730 - set 6, [hl] ; no pauses between printing each letter - coord hl, 12, 2 - CheckEvent EVENT_GOT_POKEDEX -; case for not having pokedex - ld a, $06 - jr z, .storeMenuItemCount -; case for having pokedex - ld de, StartMenuPokedexText - call PrintStartMenuItem - ld a, $07 -.storeMenuItemCount - ld [wMaxMenuItem], a ; number of menu items - ld de, StartMenuPokemonText - call PrintStartMenuItem - ld de, StartMenuItemText - call PrintStartMenuItem - ld de, wPlayerName ; player's name - call PrintStartMenuItem - ld a, [wd72e] - bit 6, a ; is the player using the link feature? -; case for not using link feature - ld de, StartMenuSaveText - jr z, .printSaveOrResetText -; case for using link feature - ld de, StartMenuResetText -.printSaveOrResetText - call PrintStartMenuItem - ld de, StartMenuOptionText - call PrintStartMenuItem - ld de, StartMenuExitText - call PlaceString - ld hl, wd730 - res 6, [hl] ; turn pauses between printing letters back on - ret - -StartMenuPokedexText: - db "POKéDEX@" - -StartMenuPokemonText: - db "POKéMON@" - -StartMenuItemText: - db "ITEM@" - -StartMenuSaveText: - db "SAVE@" - -StartMenuResetText: - db "RESET@" - -StartMenuExitText: - db "EXIT@" - -StartMenuOptionText: - db "OPTION@" - -PrintStartMenuItem: - push hl - call PlaceString - pop hl - ld de, SCREEN_WIDTH * 2 - add hl, de - ret diff --git a/engine/menu/league_pc.asm b/engine/menu/league_pc.asm deleted file mode 100755 index 170c0ef3..00000000 --- a/engine/menu/league_pc.asm +++ /dev/null @@ -1,120 +0,0 @@ -PKMNLeaguePC: - ld hl, AccessedHoFPCText - call PrintText - ld hl, wd730 - set 6, [hl] - push hl - ld a, [wUpdateSpritesEnabled] - push af - ld a, [hTilesetType] - push af - xor a - ld [hTilesetType], a - ld [wSpriteFlipped], a - ld [wUpdateSpritesEnabled], a - ld [wHoFTeamIndex2], a - ld [wHoFTeamNo], a - ld a, [wNumHoFTeams] - ld b, a - cp HOF_TEAM_CAPACITY + 1 - jr c, .loop -; If the total number of hall of fame teams is greater than the storage -; capacity, then calculate the number of the first team that is still recorded. - ld b, HOF_TEAM_CAPACITY - sub b - ld [wHoFTeamNo], a -.loop - ld hl, wHoFTeamNo - inc [hl] - push bc - ld a, [wHoFTeamIndex2] - ld [wHoFTeamIndex], a - callba LoadHallOfFameTeams - call LeaguePCShowTeam - pop bc - jr c, .doneShowingTeams - ld hl, wHoFTeamIndex2 - inc [hl] - ld a, [hl] - cp b - jr nz, .loop -.doneShowingTeams - pop af - ld [hTilesetType], a - pop af - ld [wUpdateSpritesEnabled], a - pop hl - res 6, [hl] - call GBPalWhiteOutWithDelay3 - call ClearScreen - call RunDefaultPaletteCommand - jp GBPalNormal - -LeaguePCShowTeam: - ld c, PARTY_LENGTH -.loop - push bc - call LeaguePCShowMon - call WaitForTextScrollButtonPress - ld a, [hJoyHeld] - bit 1, a - jr nz, .exit - ld hl, wHallOfFame + HOF_MON - ld de, wHallOfFame - ld bc, HOF_TEAM - HOF_MON - call CopyData - pop bc - ld a, [wHallOfFame + 0] - cp $ff - jr z, .done - dec c - jr nz, .loop -.done - and a - ret -.exit - pop bc - scf - ret - -LeaguePCShowMon: - call GBPalWhiteOutWithDelay3 - call ClearScreen - ld hl, wHallOfFame - ld a, [hli] - ld [wHoFMonSpecies], a - ld [wcf91], a - ld [wd0b5], a - ld [wBattleMonSpecies2], a - ld [wWholeScreenPaletteMonSpecies], a - ld a, [hli] - ld [wHoFMonLevel], a - ld de, wcd6d - ld bc, NAME_LENGTH - call CopyData - ld b, SET_PAL_POKEMON_WHOLE_SCREEN - ld c, 0 - call RunPaletteCommand - coord hl, 12, 5 - call GetMonHeader - call LoadFrontSpriteByMonIndex - call GBPalNormal - coord hl, 0, 13 - ld b, 2 - ld c, $12 - call TextBoxBorder - coord hl, 1, 15 - ld de, HallOfFameNoText - call PlaceString - coord hl, 16, 15 - ld de, wHoFTeamNo - lb bc, 1, 3 - call PrintNumber - jpba HoFDisplayMonInfo - -HallOfFameNoText: - db "HALL OF FAME No @" - -AccessedHoFPCText: - TX_FAR _AccessedHoFPCText - db "@" diff --git a/engine/menu/main_menu.asm b/engine/menu/main_menu.asm deleted file mode 100755 index 8eda6744..00000000 --- a/engine/menu/main_menu.asm +++ /dev/null @@ -1,712 +0,0 @@ -MainMenu: -; Check save file - call InitOptions - xor a - ld [wOptionsInitialized], a - inc a - ld [wSaveFileStatus], a - call CheckForPlayerNameInSRAM - jr nc, .mainMenuLoop - - predef LoadSAV - -.mainMenuLoop - ld c, 20 - call DelayFrames - xor a ; LINK_STATE_NONE - ld [wLinkState], a - ld hl, wPartyAndBillsPCSavedMenuItem - ld [hli], a - ld [hli], a - ld [hli], a - ld [hl], a - ld [wDefaultMap], a - ld hl, wd72e - res 6, [hl] - call ClearScreen - call RunDefaultPaletteCommand - call LoadTextBoxTilePatterns - call LoadFontTilePatterns - ld hl, wd730 - set 6, [hl] - ld a, [wSaveFileStatus] - cp 1 - jr z, .noSaveFile -; there's a save file - coord hl, 0, 0 - ld b, 6 - ld c, 13 - call TextBoxBorder - coord hl, 2, 2 - ld de, ContinueText - call PlaceString - jr .next2 -.noSaveFile - coord hl, 0, 0 - ld b, 4 - ld c, 13 - call TextBoxBorder - coord hl, 2, 2 - ld de, NewGameText - call PlaceString -.next2 - ld hl, wd730 - res 6, [hl] - call UpdateSprites - xor a - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - ld [wMenuJoypadPollCount], a - inc a - ld [wTopMenuItemX], a - inc a - ld [wTopMenuItemY], a - ld a, A_BUTTON | B_BUTTON | START - ld [wMenuWatchedKeys], a - ld a, [wSaveFileStatus] - ld [wMaxMenuItem], a - call HandleMenuInput - bit 1, a ; pressed B? - jp nz, DisplayTitleScreen ; if so, go back to the title screen - ld c, 20 - call DelayFrames - ld a, [wCurrentMenuItem] - ld b, a - ld a, [wSaveFileStatus] - cp 2 - jp z, .skipInc -; If there's no save file, increment the current menu item so that the numbers -; are the same whether or not there's a save file. - inc b -.skipInc - ld a, b - and a - jr z, .choseContinue - cp 1 - jp z, StartNewGame - call DisplayOptionMenu - ld a, 1 - ld [wOptionsInitialized], a - jp .mainMenuLoop -.choseContinue - call DisplayContinueGameInfo - ld hl, wCurrentMapScriptFlags - set 5, [hl] -.inputLoop - xor a - ld [hJoyPressed], a - ld [hJoyReleased], a - ld [hJoyHeld], a - call Joypad - ld a, [hJoyHeld] - bit 0, a - jr nz, .pressedA - bit 1, a - jp nz, .mainMenuLoop ; pressed B - jr .inputLoop -.pressedA - call GBPalWhiteOutWithDelay3 - call ClearScreen - ld a, PLAYER_DIR_DOWN - ld [wPlayerDirection], a - ld c, 10 - call DelayFrames - ld a, [wNumHoFTeams] - and a - jp z, SpecialEnterMap - ld a, [wCurMap] ; map ID - cp HALL_OF_FAME - jp nz, SpecialEnterMap - xor a - ld [wDestinationMap], a - ld hl, wd732 - set 2, [hl] ; fly warp or dungeon warp - call SpecialWarpIn - jp SpecialEnterMap - -InitOptions: - ld a, 1 ; no delay - ld [wLetterPrintingDelayFlags], a - ld a, 3 ; medium speed - ld [wOptions], a - ret - -LinkMenu: - xor a - ld [wLetterPrintingDelayFlags], a - ld hl, wd72e - set 6, [hl] - ld hl, TextTerminator_6b20 - call PrintText - call SaveScreenTilesToBuffer1 - ld hl, WhereWouldYouLikeText - call PrintText - coord hl, 5, 5 - ld b, $6 - ld c, $d - call TextBoxBorder - call UpdateSprites - coord hl, 7, 7 - ld de, CableClubOptionsText - call PlaceString - xor a - ld [wUnusedCD37], a - ld [wd72d], a - ld hl, wTopMenuItemY - ld a, $7 - ld [hli], a - ld a, $6 - ld [hli], a - xor a - ld [hli], a - inc hl - ld a, $2 - ld [hli], a - inc a - ; ld a, A_BUTTON | B_BUTTON - ld [hli], a ; wMenuWatchedKeys - xor a - ld [hl], a -.waitForInputLoop - call HandleMenuInput - and A_BUTTON | B_BUTTON - add a - add a - ld b, a - ld a, [wCurrentMenuItem] - add b - add $d0 - ld [wLinkMenuSelectionSendBuffer], a - ld [wLinkMenuSelectionSendBuffer + 1], a -.exchangeMenuSelectionLoop - call Serial_ExchangeLinkMenuSelection - ld a, [wLinkMenuSelectionReceiveBuffer] - ld b, a - and $f0 - cp $d0 - jr z, .asm_5c7d - ld a, [wLinkMenuSelectionReceiveBuffer + 1] - ld b, a - and $f0 - cp $d0 - jr nz, .exchangeMenuSelectionLoop -.asm_5c7d - ld a, b - and $c ; did the enemy press A or B? - jr nz, .enemyPressedAOrB -; the enemy didn't press A or B - ld a, [wLinkMenuSelectionSendBuffer] - and $c ; did the player press A or B? - jr z, .waitForInputLoop ; if neither the player nor the enemy pressed A or B, try again - jr .doneChoosingMenuSelection ; if the player pressed A or B but the enemy didn't, use the player's selection -.enemyPressedAOrB - ld a, [wLinkMenuSelectionSendBuffer] - and $c ; did the player press A or B? - jr z, .useEnemyMenuSelection ; if the enemy pressed A or B but the player didn't, use the enemy's selection -; the enemy and the player both pressed A or B -; The gameboy that is clocking the connection wins. - ld a, [hSerialConnectionStatus] - cp USING_INTERNAL_CLOCK - jr z, .doneChoosingMenuSelection -.useEnemyMenuSelection - ld a, b - ld [wLinkMenuSelectionSendBuffer], a - and $3 - ld [wCurrentMenuItem], a -.doneChoosingMenuSelection - ld a, [hSerialConnectionStatus] - cp USING_INTERNAL_CLOCK - jr nz, .skipStartingTransfer - call DelayFrame - call DelayFrame - ld a, START_TRANSFER_INTERNAL_CLOCK - ld [rSC], a -.skipStartingTransfer - ld b, $7f - ld c, $7f - ld d, $ec - ld a, [wLinkMenuSelectionSendBuffer] - and (B_BUTTON << 2) ; was B button pressed? - jr nz, .updateCursorPosition -; A button was pressed - ld a, [wCurrentMenuItem] - cp $2 - jr z, .updateCursorPosition - ld c, d - ld d, b - dec a - jr z, .updateCursorPosition - ld b, c - ld c, d -.updateCursorPosition - ld a, b - Coorda 6, 7 - ld a, c - Coorda 6, 9 - ld a, d - Coorda 6, 11 - ld c, 40 - call DelayFrames - call LoadScreenTilesFromBuffer1 - ld a, [wLinkMenuSelectionSendBuffer] - and (B_BUTTON << 2) ; was B button pressed? - jr nz, .choseCancel ; cancel if B pressed - ld a, [wCurrentMenuItem] - cp $2 - jr z, .choseCancel - xor a - ld [wWalkBikeSurfState], a ; start walking - ld a, [wCurrentMenuItem] - and a - ld a, COLOSSEUM - jr nz, .next - ld a, TRADE_CENTER -.next - ld [wd72d], a - ld hl, PleaseWaitText - call PrintText - ld c, 50 - call DelayFrames - ld hl, wd732 - res 1, [hl] - ld a, [wDefaultMap] - ld [wDestinationMap], a - call SpecialWarpIn - ld c, 20 - call DelayFrames - xor a - ld [wMenuJoypadPollCount], a - ld [wSerialExchangeNybbleSendData], a - inc a ; LINK_STATE_IN_CABLE_CLUB - ld [wLinkState], a - ld [wEnteringCableClub], a - jr SpecialEnterMap -.choseCancel - xor a - ld [wMenuJoypadPollCount], a - call Delay3 - call CloseLinkConnection - ld hl, LinkCanceledText - call PrintText - ld hl, wd72e - res 6, [hl] - ret - -WhereWouldYouLikeText: - TX_FAR _WhereWouldYouLikeText - db "@" - -PleaseWaitText: - TX_FAR _PleaseWaitText - db "@" - -LinkCanceledText: - TX_FAR _LinkCanceledText - db "@" - -StartNewGame: - ld hl, wd732 - res 1, [hl] - call OakSpeech - ld c, 20 - call DelayFrames - -; enter map after using a special warp or loading the game from the main menu -SpecialEnterMap:: - xor a - ld [hJoyPressed], a - ld [hJoyHeld], a - ld [hJoy5], a - ld [wd72d], a - ld hl, wd732 - set 0, [hl] ; count play time - call ResetPlayerSpriteData - ld c, 20 - call DelayFrames - ld a, [wEnteringCableClub] - and a - ret nz - jp EnterMap - -ContinueText: - db "CONTINUE", $4e - -NewGameText: - db "NEW GAME" - next "OPTION@" - -CableClubOptionsText: - db "TRADE CENTER" - next "COLOSSEUM" - next "CANCEL@" - -DisplayContinueGameInfo: - xor a - ld [H_AUTOBGTRANSFERENABLED], a - coord hl, 4, 7 - ld b, 8 - ld c, 14 - call TextBoxBorder - coord hl, 5, 9 - ld de, SaveScreenInfoText - call PlaceString - coord hl, 12, 9 - ld de, wPlayerName - call PlaceString - coord hl, 17, 11 - call PrintNumBadges - coord hl, 16, 13 - call PrintNumOwnedMons - coord hl, 13, 15 - call PrintPlayTime - ld a, 1 - ld [H_AUTOBGTRANSFERENABLED], a - ld c, 30 - jp DelayFrames - -PrintSaveScreenText: - xor a - ld [H_AUTOBGTRANSFERENABLED], a - coord hl, 4, 0 - ld b, $8 - ld c, $e - call TextBoxBorder - call LoadTextBoxTilePatterns - call UpdateSprites - coord hl, 5, 2 - ld de, SaveScreenInfoText - call PlaceString - coord hl, 12, 2 - ld de, wPlayerName - call PlaceString - coord hl, 17, 4 - call PrintNumBadges - coord hl, 16, 6 - call PrintNumOwnedMons - coord hl, 13, 8 - call PrintPlayTime - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a - ld c, 30 - jp DelayFrames - -PrintNumBadges: - push hl - ld hl, wObtainedBadges - ld b, $1 - call CountSetBits - pop hl - ld de, wNumSetBits - lb bc, 1, 2 - jp PrintNumber - -PrintNumOwnedMons: - push hl - ld hl, wPokedexOwned - ld b, wPokedexOwnedEnd - wPokedexOwned - call CountSetBits - pop hl - ld de, wNumSetBits - lb bc, 1, 3 - jp PrintNumber - -PrintPlayTime: - ld de, wPlayTimeHours - lb bc, 1, 3 - call PrintNumber - ld [hl], $6d - inc hl - ld de, wPlayTimeMinutes - lb bc, LEADING_ZEROES | 1, 2 - jp PrintNumber - -SaveScreenInfoText: - db "PLAYER" - next "BADGES " - next "#DEX " - next "TIME@" - -DisplayOptionMenu: - coord hl, 0, 0 - ld b, 3 - ld c, 18 - call TextBoxBorder - coord hl, 0, 5 - ld b, 3 - ld c, 18 - call TextBoxBorder - coord hl, 0, 10 - ld b, 3 - ld c, 18 - call TextBoxBorder - coord hl, 1, 1 - ld de, TextSpeedOptionText - call PlaceString - coord hl, 1, 6 - ld de, BattleAnimationOptionText - call PlaceString - coord hl, 1, 11 - ld de, BattleStyleOptionText - call PlaceString - coord hl, 2, 16 - ld de, OptionMenuCancelText - call PlaceString - xor a - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - inc a - ld [wLetterPrintingDelayFlags], a - ld [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 - ld [H_AUTOBGTRANSFERENABLED], a ; enable auto background transfer - call Delay3 -.loop - call PlaceMenuCursor - call SetOptionsFromCursorPositions -.getJoypadStateLoop - call JoypadLowSensitivity - ld a, [hJoy5] - ld b, a - and A_BUTTON | B_BUTTON | START | D_RIGHT | D_LEFT | D_UP | D_DOWN ; any key besides select pressed? - jr z, .getJoypadStateLoop - bit 1, b ; B button pressed? - jr nz, .exitMenu - bit 3, b ; Start button pressed? - jr nz, .exitMenu - bit 0, b ; A button pressed? - jr z, .checkDirectionKeys - ld a, [wTopMenuItemY] - cp 16 ; is the cursor on Cancel? - jr nz, .loop -.exitMenu - ld a, SFX_PRESS_AB - call PlaySound - ret -.eraseOldMenuCursor - ld [wTopMenuItemX], a - call EraseMenuCursor - jp .loop -.checkDirectionKeys - ld a, [wTopMenuItemY] - bit 7, b ; Down pressed? - jr nz, .downPressed - bit 6, b ; Up pressed? - jr nz, .upPressed - cp 8 ; cursor in Battle Animation section? - jr z, .cursorInBattleAnimation - cp 13 ; cursor in Battle Style section? - jr z, .cursorInBattleStyle - cp 16 ; cursor on Cancel? - jr z, .loop -.cursorInTextSpeed - bit 5, b ; Left pressed? - jp nz, .pressedLeftInTextSpeed - jp .pressedRightInTextSpeed -.downPressed - cp 16 - ld b, -13 - ld hl, wOptionsTextSpeedCursorX - jr z, .updateMenuVariables - ld b, 5 - cp 3 - inc hl - jr z, .updateMenuVariables - cp 8 - inc hl - jr z, .updateMenuVariables - ld b, 3 - inc hl - jr .updateMenuVariables -.upPressed - cp 8 - ld b, -5 - ld hl, wOptionsTextSpeedCursorX - jr z, .updateMenuVariables - cp 13 - inc hl - jr z, .updateMenuVariables - cp 16 - ld b, -3 - inc hl - jr z, .updateMenuVariables - ld b, 13 - inc hl -.updateMenuVariables - add b - ld [wTopMenuItemY], a - ld a, [hl] - ld [wTopMenuItemX], a - call PlaceUnfilledArrowMenuCursor - jp .loop -.cursorInBattleAnimation - ld a, [wOptionsBattleAnimCursorX] ; battle animation cursor X coordinate - xor $0b ; toggle between 1 and 10 - ld [wOptionsBattleAnimCursorX], a - jp .eraseOldMenuCursor -.cursorInBattleStyle - ld a, [wOptionsBattleStyleCursorX] ; battle style cursor X coordinate - xor $0b ; toggle between 1 and 10 - ld [wOptionsBattleStyleCursorX], a - jp .eraseOldMenuCursor -.pressedLeftInTextSpeed - ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate - cp 1 - jr z, .updateTextSpeedXCoord - cp 7 - jr nz, .fromSlowToMedium - sub 6 - jr .updateTextSpeedXCoord -.fromSlowToMedium - sub 7 - jr .updateTextSpeedXCoord -.pressedRightInTextSpeed - ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate - cp 14 - jr z, .updateTextSpeedXCoord - cp 7 - jr nz, .fromFastToMedium - add 7 - jr .updateTextSpeedXCoord -.fromFastToMedium - add 6 -.updateTextSpeedXCoord - ld [wOptionsTextSpeedCursorX], a ; text speed cursor X coordinate - jp .eraseOldMenuCursor - -TextSpeedOptionText: - db "TEXT SPEED" - next " FAST MEDIUM SLOW@" - -BattleAnimationOptionText: - db "BATTLE ANIMATION" - next " ON OFF@" - -BattleStyleOptionText: - db "BATTLE STYLE" - next " SHIFT SET@" - -OptionMenuCancelText: - db "CANCEL@" - -; sets the options variable according to the current placement of the menu cursors in the options menu -SetOptionsFromCursorPositions: - ld hl, TextSpeedOptionData - ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate - ld c, a -.loop - ld a, [hli] - cp c - jr z, .textSpeedMatchFound - inc hl - jr .loop -.textSpeedMatchFound - ld a, [hl] - ld d, a - ld a, [wOptionsBattleAnimCursorX] ; battle animation cursor X coordinate - dec a - jr z, .battleAnimationOn -.battleAnimationOff - set 7, d - jr .checkBattleStyle -.battleAnimationOn - res 7, d -.checkBattleStyle - ld a, [wOptionsBattleStyleCursorX] ; battle style cursor X coordinate - dec a - jr z, .battleStyleShift -.battleStyleSet - set 6, d - jr .storeOptions -.battleStyleShift - res 6, d -.storeOptions - ld a, d - ld [wOptions], a - ret - -; reads the options variable and places menu cursors in the correct positions within the options menu -SetCursorPositionsFromOptions: - ld hl, TextSpeedOptionData + 1 - ld a, [wOptions] - ld c, a - and $3f - push bc - ld de, 2 - call IsInArray - pop bc - dec hl - ld a, [hl] - ld [wOptionsTextSpeedCursorX], a ; text speed cursor X coordinate - coord hl, 0, 3 - call .placeUnfilledRightArrow - sla c - ld a, 1 ; On - jr nc, .storeBattleAnimationCursorX - ld a, 10 ; Off -.storeBattleAnimationCursorX - ld [wOptionsBattleAnimCursorX], a ; battle animation cursor X coordinate - coord hl, 0, 8 - call .placeUnfilledRightArrow - sla c - ld a, 1 - jr nc, .storeBattleStyleCursorX - ld a, 10 -.storeBattleStyleCursorX - ld [wOptionsBattleStyleCursorX], a ; battle style cursor X coordinate - coord hl, 0, 13 - call .placeUnfilledRightArrow -; cursor in front of Cancel - coord hl, 0, 16 - ld a, 1 -.placeUnfilledRightArrow - ld e, a - ld d, 0 - add hl, de - ld [hl], $ec ; unfilled right arrow menu cursor - ret - -; table that indicates how the 3 text speed options affect frame delays -; Format: -; 00: X coordinate of menu cursor -; 01: delay after printing a letter (in frames) -TextSpeedOptionData: - db 14,5 ; Slow - db 7,3 ; Medium - db 1,1 ; Fast - db 7 ; default X coordinate (Medium) - db $ff ; terminator - -CheckForPlayerNameInSRAM: -; Check if the player name data in SRAM has a string terminator character -; (indicating that a name may have been saved there) and return whether it does -; in carry. - ld a, SRAM_ENABLE - ld [MBC1SRamEnable], a - ld a, $1 - ld [MBC1SRamBankingMode], a - ld [MBC1SRamBank], a - ld b, NAME_LENGTH - ld hl, sPlayerName -.loop - ld a, [hli] - cp "@" - jr z, .found - dec b - jr nz, .loop -; not found - xor a - ld [MBC1SRamEnable], a - ld [MBC1SRamBankingMode], a - and a - ret -.found - xor a - ld [MBC1SRamEnable], a - ld [MBC1SRamBankingMode], a - scf - ret diff --git a/engine/menu/naming_screen.asm b/engine/menu/naming_screen.asm deleted file mode 100755 index 2b86d6f4..00000000 --- a/engine/menu/naming_screen.asm +++ /dev/null @@ -1,494 +0,0 @@ -AskName: - call SaveScreenTilesToBuffer1 - call GetPredefRegisters - push hl - ld a, [wIsInBattle] - dec a - coord hl, 0, 0 - ld b, 4 - ld c, 11 - call z, ClearScreenArea ; only if in wild battle - ld a, [wcf91] - ld [wd11e], a - call GetMonName - ld hl, DoYouWantToNicknameText - call PrintText - coord hl, 14, 7 - lb bc, 8, 15 - ld a, TWO_OPTION_MENU - ld [wTextBoxID], a - call DisplayTextBoxID - pop hl - ld a, [wCurrentMenuItem] - and a - jr nz, .declinedNickname - ld a, [wUpdateSpritesEnabled] - push af - xor a - ld [wUpdateSpritesEnabled], a - push hl - ld a, NAME_MON_SCREEN - ld [wNamingScreenType], a - call DisplayNamingScreen - ld a, [wIsInBattle] - and a - jr nz, .inBattle - call ReloadMapSpriteTilePatterns -.inBattle - call LoadScreenTilesFromBuffer1 - pop hl - pop af - ld [wUpdateSpritesEnabled], a - ld a, [wcf4b] - cp "@" - ret nz -.declinedNickname - ld d, h - ld e, l - ld hl, wcd6d - ld bc, NAME_LENGTH - jp CopyData - -DoYouWantToNicknameText: - TX_FAR _DoYouWantToNicknameText - db "@" - -DisplayNameRaterScreen:: - ld hl, wBuffer - xor a - ld [wUpdateSpritesEnabled], a - ld a, NAME_MON_SCREEN - ld [wNamingScreenType], a - call DisplayNamingScreen - call GBPalWhiteOutWithDelay3 - call RestoreScreenTilesAndReloadTilePatterns - call LoadGBPal - ld a, [wcf4b] - cp "@" - jr z, .playerCancelled - ld hl, wPartyMonNicks - ld bc, NAME_LENGTH - ld a, [wWhichPokemon] - call AddNTimes - ld e, l - ld d, h - ld hl, wBuffer - ld bc, NAME_LENGTH - call CopyData - and a - ret -.playerCancelled - scf - ret - -DisplayNamingScreen: - push hl - ld hl, wd730 - set 6, [hl] - call GBPalWhiteOutWithDelay3 - call ClearScreen - call UpdateSprites - ld b, SET_PAL_GENERIC - call RunPaletteCommand - call LoadHpBarAndStatusTilePatterns - call LoadEDTile - callba LoadMonPartySpriteGfx - coord hl, 0, 4 - ld b, 9 - ld c, 18 - call TextBoxBorder - call PrintNamingText - ld a, 3 - ld [wTopMenuItemY], a - ld a, 1 - ld [wTopMenuItemX], a - ld [wLastMenuItem], a - ld [wCurrentMenuItem], a - ld a, $ff - ld [wMenuWatchedKeys], a - ld a, 7 - ld [wMaxMenuItem], a - ld a, "@" - ld [wcf4b], a - xor a - ld hl, wNamingScreenSubmitName - ld [hli], a - ld [hli], a - ld [wAnimCounter], a -.selectReturnPoint - call PrintAlphabet - call GBPalNormal -.ABStartReturnPoint - ld a, [wNamingScreenSubmitName] - and a - jr nz, .submitNickname - call PrintNicknameAndUnderscores -.dPadReturnPoint - call PlaceMenuCursor -.inputLoop - ld a, [wCurrentMenuItem] - push af - callba AnimatePartyMon_ForceSpeed1 - pop af - ld [wCurrentMenuItem], a - call JoypadLowSensitivity - ld a, [hJoyPressed] - and a - jr z, .inputLoop - ld hl, .namingScreenButtonFunctions -.checkForPressedButton - sla a - jr c, .foundPressedButton - inc hl - inc hl - inc hl - inc hl - jr .checkForPressedButton -.foundPressedButton - ld a, [hli] - ld e, a - ld a, [hli] - ld d, a - ld a, [hli] - ld h, [hl] - ld l, a - push de - jp hl - -.submitNickname - pop de - ld hl, wcf4b - ld bc, NAME_LENGTH - call CopyData - call GBPalWhiteOutWithDelay3 - call ClearScreen - call ClearSprites - call RunDefaultPaletteCommand - call GBPalNormal - xor a - ld [wAnimCounter], a - ld hl, wd730 - res 6, [hl] - ld a, [wIsInBattle] - and a - jp z, LoadTextBoxTilePatterns - jpab LoadHudTilePatterns - -.namingScreenButtonFunctions - dw .dPadReturnPoint - dw .pressedDown - dw .dPadReturnPoint - dw .pressedUp - dw .dPadReturnPoint - dw .pressedLeft - dw .dPadReturnPoint - dw .pressedRight - dw .ABStartReturnPoint - dw .pressedStart - dw .selectReturnPoint - dw .pressedSelect - dw .ABStartReturnPoint - dw .pressedB - dw .ABStartReturnPoint - dw .pressedA - -.pressedA_changedCase - pop de - ld de, .selectReturnPoint - push de -.pressedSelect - ld a, [wAlphabetCase] - xor $1 - ld [wAlphabetCase], a - ret - -.pressedStart - ld a, 1 - ld [wNamingScreenSubmitName], a - ret - -.pressedA - ld a, [wCurrentMenuItem] - cp $5 ; "ED" row - jr nz, .didNotPressED - ld a, [wTopMenuItemX] - cp $11 ; "ED" column - jr z, .pressedStart -.didNotPressED - ld a, [wCurrentMenuItem] - cp $6 ; case switch row - jr nz, .didNotPressCaseSwtich - ld a, [wTopMenuItemX] - cp $1 ; case switch column - jr z, .pressedA_changedCase -.didNotPressCaseSwtich - ld hl, wMenuCursorLocation - ld a, [hli] - ld h, [hl] - ld l, a - inc hl - ld a, [hl] - ld [wNamingScreenLetter], a - call CalcStringLength - ld a, [wNamingScreenLetter] - cp $e5 - ld de, Dakutens - jr z, .dakutensAndHandakutens - cp $e4 - ld de, Handakutens - jr z, .dakutensAndHandakutens - ld a, [wNamingScreenType] - cp NAME_MON_SCREEN - jr nc, .checkMonNameLength - ld a, [wNamingScreenNameLength] - cp $7 ; max length of player/rival names - jr .checkNameLength -.checkMonNameLength - ld a, [wNamingScreenNameLength] - cp $a ; max length of pokemon nicknames -.checkNameLength - jr c, .addLetter - ret - -.dakutensAndHandakutens - push hl - call DakutensAndHandakutens - pop hl - ret nc - dec hl -.addLetter - ld a, [wNamingScreenLetter] - ld [hli], a - ld [hl], "@" - ld a, SFX_PRESS_AB - call PlaySound - ret -.pressedB - ld a, [wNamingScreenNameLength] - and a - ret z - call CalcStringLength - dec hl - ld [hl], "@" - ret -.pressedRight - ld a, [wCurrentMenuItem] - cp $6 - ret z ; can't scroll right on bottom row - ld a, [wTopMenuItemX] - cp $11 ; max - jp z, .wrapToFirstColumn - inc a - inc a - jr .done -.wrapToFirstColumn - ld a, $1 - jr .done -.pressedLeft - ld a, [wCurrentMenuItem] - cp $6 - ret z ; can't scroll right on bottom row - ld a, [wTopMenuItemX] - dec a - jp z, .wrapToLastColumn - dec a - jr .done -.wrapToLastColumn - ld a, $11 ; max - jr .done -.pressedUp - ld a, [wCurrentMenuItem] - dec a - ld [wCurrentMenuItem], a - and a - ret nz - ld a, $6 ; wrap to bottom row - ld [wCurrentMenuItem], a - ld a, $1 ; force left column - jr .done -.pressedDown - ld a, [wCurrentMenuItem] - inc a - ld [wCurrentMenuItem], a - cp $7 - jr nz, .wrapToTopRow - ld a, $1 - ld [wCurrentMenuItem], a - jr .done -.wrapToTopRow - cp $6 - ret nz - ld a, $1 -.done - ld [wTopMenuItemX], a - jp EraseMenuCursor - -LoadEDTile: - ld de, ED_Tile - ld hl, vFont + $700 - ld bc, (ED_TileEnd - ED_Tile) / $8 - ; to fix the graphical bug on poor emulators - ;lb bc, BANK(ED_Tile), (ED_TileEnd - ED_Tile) / $8 - jp CopyVideoDataDouble - -ED_Tile: - INCBIN "gfx/font/ED.1bpp" -ED_TileEnd: - -PrintAlphabet: - xor a - ld [H_AUTOBGTRANSFERENABLED], a - ld a, [wAlphabetCase] - and a - ld de, LowerCaseAlphabet - jr nz, .lowercase - ld de, UpperCaseAlphabet -.lowercase - coord hl, 2, 5 - lb bc, 5, 9 ; 5 rows, 9 columns -.outerLoop - push bc -.innerLoop - ld a, [de] - ld [hli], a - inc hl - inc de - dec c - jr nz, .innerLoop - ld bc, SCREEN_WIDTH + 2 - add hl, bc - pop bc - dec b - jr nz, .outerLoop - call PlaceString - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a - jp Delay3 - -INCLUDE "text/alphabets.asm" - -PrintNicknameAndUnderscores: - call CalcStringLength - ld a, c - ld [wNamingScreenNameLength], a - coord hl, 10, 2 - lb bc, 1, 10 - call ClearScreenArea - coord hl, 10, 2 - ld de, wcf4b - call PlaceString - coord hl, 10, 3 - ld a, [wNamingScreenType] - cp NAME_MON_SCREEN - jr nc, .pokemon1 - ld b, 7 ; player or rival max name length - jr .playerOrRival1 -.pokemon1 - ld b, 10 ; pokemon max name length -.playerOrRival1 - ld a, $76 ; underscore tile id -.placeUnderscoreLoop - ld [hli], a - dec b - jr nz, .placeUnderscoreLoop - ld a, [wNamingScreenType] - cp NAME_MON_SCREEN - ld a, [wNamingScreenNameLength] - jr nc, .pokemon2 - cp 7 ; player or rival max name length - jr .playerOrRival2 -.pokemon2 - cp 10 ; pokemon max name length -.playerOrRival2 - jr nz, .emptySpacesRemaining - ; when all spaces are filled, force the cursor onto the ED tile - call EraseMenuCursor - ld a, $11 ; "ED" x coord - ld [wTopMenuItemX], a - ld a, $5 ; "ED" y coord - ld [wCurrentMenuItem], a - ld a, [wNamingScreenType] - cp NAME_MON_SCREEN - ld a, 9 ; keep the last underscore raised - jr nc, .pokemon3 - ld a, 6 ; keep the last underscore raised -.pokemon3 -.emptySpacesRemaining - ld c, a - ld b, $0 - coord hl, 10, 3 - add hl, bc - ld [hl], $77 ; raised underscore tile id - ret - -DakutensAndHandakutens: - push de - call CalcStringLength - dec hl - ld a, [hl] - pop hl - ld de, $2 - call IsInArray - ret nc - inc hl - ld a, [hl] - ld [wNamingScreenLetter], a - ret - -INCLUDE "text/dakutens.asm" - -; calculates the length of the string at wcf4b and stores it in c -CalcStringLength: - ld hl, wcf4b - ld c, $0 -.loop - ld a, [hl] - cp "@" - ret z - inc hl - inc c - jr .loop - -PrintNamingText: - coord hl, 0, 1 - ld a, [wNamingScreenType] - ld de, YourTextString - and a - jr z, .notNickname - ld de, RivalsTextString - dec a - jr z, .notNickname - ld a, [wcf91] - ld [wMonPartySpriteSpecies], a - push af - callba WriteMonPartySpriteOAMBySpecies - pop af - ld [wd11e], a - call GetMonName - coord hl, 4, 1 - call PlaceString - ld hl, $1 - add hl, bc - ld [hl], $c9 - coord hl, 1, 3 - ld de, NicknameTextString - jr .placeString -.notNickname - call PlaceString - ld l, c - ld h, b - ld de, NameTextString -.placeString - jp PlaceString - -YourTextString: - db "YOUR @" - -RivalsTextString: - db "RIVAL's @" - -NameTextString: - db "NAME?@" - -NicknameTextString: - db "NICKNAME?@" diff --git a/engine/menu/oaks_pc.asm b/engine/menu/oaks_pc.asm deleted file mode 100755 index 03c9b8f1..00000000 --- a/engine/menu/oaks_pc.asm +++ /dev/null @@ -1,28 +0,0 @@ -OpenOaksPC: - call SaveScreenTilesToBuffer2 - ld hl, AccessedOaksPCText - call PrintText - ld hl, GetDexRatedText - call PrintText - call YesNoChoice - ld a, [wCurrentMenuItem] - and a - jr nz, .closePC - predef DisplayDexRating -.closePC - ld hl, ClosedOaksPCText - call PrintText - jp LoadScreenTilesFromBuffer2 - -GetDexRatedText: - TX_FAR _GetDexRatedText - db "@" - -ClosedOaksPCText: - TX_FAR _ClosedOaksPCText - TX_WAIT - db "@" - -AccessedOaksPCText: - TX_FAR _AccessedOaksPCText - db "@" diff --git a/engine/menu/party_menu.asm b/engine/menu/party_menu.asm deleted file mode 100755 index 41b6074b..00000000 --- a/engine/menu/party_menu.asm +++ /dev/null @@ -1,325 +0,0 @@ -; [wPartyMenuTypeOrMessageID] = menu type / message ID -; if less than $F0, it is a menu type -; menu types: -; 00: normal pokemon menu (e.g. Start menu) -; 01: use healing item on pokemon menu -; 02: in-battle switch pokemon menu -; 03: learn TM/HM menu -; 04: swap pokemon positions menu -; 05: use evolution stone on pokemon menu -; otherwise, it is a message ID -; f0: poison healed -; f1: burn healed -; f2: freeze healed -; f3: sleep healed -; f4: paralysis healed -; f5: HP healed -; f6: health returned -; f7: revitalized -; f8: leveled up -DrawPartyMenu_:: - xor a - ld [H_AUTOBGTRANSFERENABLED], a - call ClearScreen - call UpdateSprites - callba LoadMonPartySpriteGfxWithLCDDisabled ; load pokemon icon graphics - -RedrawPartyMenu_:: - ld a, [wPartyMenuTypeOrMessageID] - cp SWAP_MONS_PARTY_MENU - jp z, .printMessage - call ErasePartyMenuCursors - callba InitPartyMenuBlkPacket - coord hl, 3, 0 - ld de, wPartySpecies - xor a - ld c, a - ld [hPartyMonIndex], a - ld [wWhichPartyMenuHPBar], a -.loop - ld a, [de] - cp $FF ; reached the terminator? - jp z, .afterDrawingMonEntries - push bc - push de - push hl - ld a, c - push hl - ld hl, wPartyMonNicks - call GetPartyMonName - pop hl - call PlaceString ; print the pokemon's name - callba WriteMonPartySpriteOAMByPartyIndex ; place the appropriate pokemon icon - ld a, [hPartyMonIndex] - ld [wWhichPokemon], a - inc a - ld [hPartyMonIndex], a - call LoadMonData - pop hl - push hl - ld a, [wMenuItemToSwap] - and a ; is the player swapping pokemon positions? - jr z, .skipUnfilledRightArrow -; if the player is swapping pokemon positions - dec a - ld b, a - ld a, [wWhichPokemon] - cp b ; is the player swapping the current pokemon in the list? - jr nz, .skipUnfilledRightArrow -; the player is swapping the current pokemon in the list - dec hl - dec hl - dec hl - ld a, "▷" ; unfilled right arrow menu cursor - ld [hli], a ; place the cursor - inc hl - inc hl -.skipUnfilledRightArrow - ld a, [wPartyMenuTypeOrMessageID] ; menu type - cp TMHM_PARTY_MENU - jr z, .teachMoveMenu - cp EVO_STONE_PARTY_MENU - jr z, .evolutionStoneMenu - push hl - ld bc, 14 ; 14 columns to the right - add hl, bc - ld de, wLoadedMonStatus - call PrintStatusCondition - pop hl - push hl - ld bc, SCREEN_WIDTH + 1 ; down 1 row and right 1 column - ld a, [hFlags_0xFFF6] - set 0, a - ld [hFlags_0xFFF6], a - add hl, bc - predef DrawHP2 ; draw HP bar and prints current / max HP - ld a, [hFlags_0xFFF6] - res 0, a - ld [hFlags_0xFFF6], a - call SetPartyMenuHPBarColor ; color the HP bar (on SGB) - pop hl - jr .printLevel -.teachMoveMenu - push hl - predef CanLearnTM ; check if the pokemon can learn the move - pop hl - ld de, .ableToLearnMoveText - ld a, c - and a - jr nz, .placeMoveLearnabilityString - ld de, .notAbleToLearnMoveText -.placeMoveLearnabilityString - ld bc, 20 + 9 ; down 1 row and right 9 columns - push hl - add hl, bc - call PlaceString - pop hl -.printLevel - ld bc, 10 ; move 10 columns to the right - add hl, bc - call PrintLevel - pop hl - pop de - inc de - ld bc, 2 * 20 - add hl, bc - pop bc - inc c - jp .loop -.ableToLearnMoveText - db "ABLE@" -.notAbleToLearnMoveText - db "NOT ABLE@" -.evolutionStoneMenu - push hl - ld hl, EvosMovesPointerTable - ld b, 0 - ld a, [wLoadedMonSpecies] - dec a - add a - rl b - ld c, a - add hl, bc - ld de, wEvosMoves - ld a, BANK(EvosMovesPointerTable) - ld bc, 2 - call FarCopyData - ld hl, wEvosMoves - ld a, [hli] - ld h, [hl] - ld l, a - ld de, wEvosMoves - ld a, BANK(EvosMovesPointerTable) - ld bc, wEvosMoves.end - wEvosMoves - call FarCopyData - ld hl, wEvosMoves - ld de, .notAbleToEvolveText -; loop through the pokemon's evolution entries -.checkEvolutionsLoop - ld a, [hli] - and a ; reached terminator? - jr z, .placeEvolutionStoneString ; if so, place the "NOT ABLE" string - inc hl - inc hl - cp EV_ITEM - jr nz, .checkEvolutionsLoop -; if it's a stone evolution entry - dec hl - dec hl - ld b, [hl] - ld a, [wEvoStoneItemID] ; the stone the player used - inc hl - inc hl - inc hl - cp b ; does the player's stone match this evolution entry's stone? - jr nz, .checkEvolutionsLoop -; if it does match - ld de, .ableToEvolveText -.placeEvolutionStoneString - ld bc, 20 + 9 ; down 1 row and right 9 columns - pop hl - push hl - add hl, bc - call PlaceString - pop hl - jr .printLevel -.ableToEvolveText - db "ABLE@" -.notAbleToEvolveText - db "NOT ABLE@" -.afterDrawingMonEntries - ld b, SET_PAL_PARTY_MENU - call RunPaletteCommand -.printMessage - ld hl, wd730 - ld a, [hl] - push af - push hl - set 6, [hl] ; turn off letter printing delay - ld a, [wPartyMenuTypeOrMessageID] ; message ID - cp $F0 - jr nc, .printItemUseMessage - add a - ld hl, PartyMenuMessagePointers - ld b, 0 - ld c, a - add hl, bc - ld a, [hli] - ld h, [hl] - ld l, a - call PrintText -.done - pop hl - pop af - ld [hl], a - ld a, 1 - ld [H_AUTOBGTRANSFERENABLED], a - call Delay3 - jp GBPalNormal -.printItemUseMessage - and $0F - ld hl, PartyMenuItemUseMessagePointers - add a - ld c, a - ld b, 0 - add hl, bc - ld a, [hli] - ld h, [hl] - ld l, a - push hl - ld a, [wUsedItemOnWhichPokemon] - ld hl, wPartyMonNicks - call GetPartyMonName - pop hl - call PrintText - jr .done - -PartyMenuItemUseMessagePointers: - dw AntidoteText - dw BurnHealText - dw IceHealText - dw AwakeningText - dw ParlyzHealText - dw PotionText - dw FullHealText - dw ReviveText - dw RareCandyText - -PartyMenuMessagePointers: - dw PartyMenuNormalText - dw PartyMenuItemUseText - dw PartyMenuBattleText - dw PartyMenuUseTMText - dw PartyMenuSwapMonText - dw PartyMenuItemUseText - -PartyMenuNormalText: - TX_FAR _PartyMenuNormalText - db "@" - -PartyMenuItemUseText: - TX_FAR _PartyMenuItemUseText - db "@" - -PartyMenuBattleText: - TX_FAR _PartyMenuBattleText - db "@" - -PartyMenuUseTMText: - TX_FAR _PartyMenuUseTMText - db "@" - -PartyMenuSwapMonText: - TX_FAR _PartyMenuSwapMonText - db "@" - -PotionText: - TX_FAR _PotionText - db "@" - -AntidoteText: - TX_FAR _AntidoteText - db "@" - -ParlyzHealText: - TX_FAR _ParlyzHealText - db "@" - -BurnHealText: - TX_FAR _BurnHealText - db "@" - -IceHealText: - TX_FAR _IceHealText - db "@" - -AwakeningText: - TX_FAR _AwakeningText - db "@" - -FullHealText: - TX_FAR _FullHealText - db "@" - -ReviveText: - TX_FAR _ReviveText - db "@" - -RareCandyText: - TX_FAR _RareCandyText - TX_SFX_ITEM_1 ; probably supposed to play SFX_LEVEL_UP but the wrong music bank is loaded - TX_BLINK - db "@" - -SetPartyMenuHPBarColor: - ld hl, wPartyMenuHPBarColors - ld a, [wWhichPartyMenuHPBar] - ld c, a - ld b, 0 - add hl, bc - call GetHealthBarColor - ld b, UPDATE_PARTY_MENU_BLK_PACKET - call RunPaletteCommand - ld hl, wWhichPartyMenuHPBar - inc [hl] - ret diff --git a/engine/menu/pc.asm b/engine/menu/pc.asm deleted file mode 100755 index 6ec45f2e..00000000 --- a/engine/menu/pc.asm +++ /dev/null @@ -1,141 +0,0 @@ -ActivatePC:: - call SaveScreenTilesToBuffer2 - ld a, SFX_TURN_ON_PC - call PlaySound - ld hl, TurnedOnPC1Text - call PrintText - call WaitForSoundToFinish - ld hl, wFlags_0xcd60 - set 3, [hl] - call LoadScreenTilesFromBuffer2 - call Delay3 -PCMainMenu: - callba DisplayPCMainMenu - ld hl, wFlags_0xcd60 - set 5, [hl] - call HandleMenuInput - bit 1, a ;if player pressed B - jp nz, LogOff - ld a, [wMaxMenuItem] - cp 2 - jr nz, .next ;if not 2 menu items (not counting log off) (2 occurs before you get the pokedex) - ld a, [wCurrentMenuItem] - and a - jp z, BillsPC ;if current menu item id is 0, it's bills pc - cp 1 - jr z, .playersPC ;if current menu item id is 1, it's players pc - jp LogOff ;otherwise, it's 2, and you're logging off -.next - cp 3 - jr nz, .next2 ;if not 3 menu items (not counting log off) (3 occurs after you get the pokedex, before you beat the pokemon league) - ld a, [wCurrentMenuItem] - and a - jp z, BillsPC ;if current menu item id is 0, it's bills pc - cp 1 - jr z, .playersPC ;if current menu item id is 1, it's players pc - cp 2 - jp z, OaksPC ;if current menu item id is 2, it's oaks pc - jp LogOff ;otherwise, it's 3, and you're logging off -.next2 - ld a, [wCurrentMenuItem] - and a - jp z, BillsPC ;if current menu item id is 0, it's bills pc - cp 1 - jr z, .playersPC ;if current menu item id is 1, it's players pc - cp 2 - jp z, OaksPC ;if current menu item id is 2, it's oaks pc - cp 3 - jp z, PKMNLeague ;if current menu item id is 3, it's pkmnleague - jp LogOff ;otherwise, it's 4, and you're logging off -.playersPC - ld hl, wFlags_0xcd60 - res 5, [hl] - set 3, [hl] - ld a, SFX_ENTER_PC - call PlaySound - call WaitForSoundToFinish - ld hl, AccessedMyPCText - call PrintText - callba PlayerPC - jr ReloadMainMenu -OaksPC: - ld a, SFX_ENTER_PC - call PlaySound - call WaitForSoundToFinish - callba OpenOaksPC - jr ReloadMainMenu -PKMNLeague: - ld a, SFX_ENTER_PC - call PlaySound - call WaitForSoundToFinish - callba PKMNLeaguePC - jr ReloadMainMenu -BillsPC: - ld a, SFX_ENTER_PC - call PlaySound - call WaitForSoundToFinish - CheckEvent EVENT_MET_BILL - jr nz, .billsPC ;if you've met bill, use that bill's instead of someone's - ld hl, AccessedSomeonesPCText - jr .printText -.billsPC - ld hl, AccessedBillsPCText -.printText - call PrintText - callba BillsPC_ -ReloadMainMenu: - xor a - ld [wDoNotWaitForButtonPressAfterDisplayingText], a - call ReloadMapData - call UpdateSprites - jp PCMainMenu -LogOff: - ld a, SFX_TURN_OFF_PC - call PlaySound - call WaitForSoundToFinish - ld hl, wFlags_0xcd60 - res 3, [hl] - res 5, [hl] - ret - -TurnedOnPC1Text: - TX_FAR _TurnedOnPC1Text - db "@" - -AccessedBillsPCText: - TX_FAR _AccessedBillsPCText - db "@" - -AccessedSomeonesPCText: - TX_FAR _AccessedSomeonesPCText - db "@" - -AccessedMyPCText: - TX_FAR _AccessedMyPCText - db "@" - -; removes one of the specified item ID [hItemToRemoveID] from bag (if existent) -RemoveItemByID:: - ld hl, wBagItems - ld a, [hItemToRemoveID] - ld b, a - xor a - ld [hItemToRemoveIndex], a -.loop - ld a, [hli] - cp -1 ; reached terminator? - ret z - cp b - jr z, .foundItem - inc hl - ld a, [hItemToRemoveIndex] - inc a - ld [hItemToRemoveIndex], a - jr .loop -.foundItem - ld a, $1 - ld [wItemQuantity], a - ld a, [hItemToRemoveIndex] - ld [wWhichPokemon], a - ld hl, wNumBagItems - jp RemoveItemFromInventory diff --git a/engine/menu/players_pc.asm b/engine/menu/players_pc.asm deleted file mode 100755 index 403632fa..00000000 --- a/engine/menu/players_pc.asm +++ /dev/null @@ -1,303 +0,0 @@ -PlayerPC:: - ld hl, wd730 - set 6, [hl] - ld a, ITEM_NAME - ld [wNameListType], a - call SaveScreenTilesToBuffer1 - xor a - ld [wBagSavedMenuItem], a - ld [wParentMenuItem], a - ld a, [wFlags_0xcd60] - bit 3, a ; accessing player's PC through another PC? - jr nz, PlayerPCMenu -; accessing it directly - ld a, SFX_TURN_ON_PC - call PlaySound - ld hl, TurnedOnPC2Text - call PrintText - -PlayerPCMenu: - ld a, [wParentMenuItem] - ld [wCurrentMenuItem], a - ld hl, wFlags_0xcd60 - set 5, [hl] - call LoadScreenTilesFromBuffer2 - coord hl, 0, 0 - ld b, $8 - ld c, $e - call TextBoxBorder - call UpdateSprites - coord hl, 2, 2 - ld de, PlayersPCMenuEntries - call PlaceString - ld hl, wTopMenuItemY - ld a, 2 - ld [hli], a ; wTopMenuItemY - dec a - ld [hli], a ; wTopMenuItemX - inc hl - inc hl - ld a, 3 - ld [hli], a ; wMaxMenuItem - ld a, A_BUTTON | B_BUTTON - ld [hli], a ; wMenuWatchedKeys - xor a - ld [hl], a - ld hl, wListScrollOffset - ld [hli], a ; wListScrollOffset - ld [hl], a ; wMenuWatchMovingOutOfBounds - ld [wPlayerMonNumber], a - ld hl, WhatDoYouWantText - call PrintText - call HandleMenuInput - bit 1, a - jp nz, ExitPlayerPC - call PlaceUnfilledArrowMenuCursor - ld a, [wCurrentMenuItem] - ld [wParentMenuItem], a - and a - jp z, PlayerPCWithdraw - dec a - jp z, PlayerPCDeposit - dec a - jp z, PlayerPCToss - -ExitPlayerPC: - ld a, [wFlags_0xcd60] - bit 3, a ; accessing player's PC through another PC? - jr nz, .next -; accessing it directly - ld a, SFX_TURN_OFF_PC - call PlaySound - call WaitForSoundToFinish -.next - ld hl, wFlags_0xcd60 - res 5, [hl] - call LoadScreenTilesFromBuffer2 - xor a - ld [wListScrollOffset], a - ld [wBagSavedMenuItem], a - ld hl, wd730 - res 6, [hl] - xor a - ld [wDoNotWaitForButtonPressAfterDisplayingText], a - ret - -PlayerPCDeposit: - xor a - ld [wCurrentMenuItem], a - ld [wListScrollOffset], a - ld a, [wNumBagItems] - and a - jr nz, .loop - ld hl, NothingToDepositText - call PrintText - jp PlayerPCMenu -.loop - ld hl, WhatToDepositText - call PrintText - ld hl, wNumBagItems - ld a, l - ld [wListPointer], a - ld a, h - ld [wListPointer + 1], a - xor a - ld [wPrintItemPrices], a - ld a, ITEMLISTMENU - ld [wListMenuID], a - call DisplayListMenuID - jp c, PlayerPCMenu - call IsKeyItem - ld a, 1 - ld [wItemQuantity], a - ld a, [wIsKeyItem] - and a - jr nz, .next -; if it's not a key item, there can be more than one of the item - ld hl, DepositHowManyText - call PrintText - call DisplayChooseQuantityMenu - cp $ff - jp z, .loop -.next - ld hl, wNumBoxItems - call AddItemToInventory - jr c, .roomAvailable - ld hl, NoRoomToStoreText - call PrintText - jp .loop -.roomAvailable - ld hl, wNumBagItems - call RemoveItemFromInventory - call WaitForSoundToFinish - ld a, SFX_WITHDRAW_DEPOSIT - call PlaySound - call WaitForSoundToFinish - ld hl, ItemWasStoredText - call PrintText - jp .loop - -PlayerPCWithdraw: - xor a - ld [wCurrentMenuItem], a - ld [wListScrollOffset], a - ld a, [wNumBoxItems] - and a - jr nz, .loop - ld hl, NothingStoredText - call PrintText - jp PlayerPCMenu -.loop - ld hl, WhatToWithdrawText - call PrintText - ld hl, wNumBoxItems - ld a, l - ld [wListPointer], a - ld a, h - ld [wListPointer + 1], a - xor a - ld [wPrintItemPrices], a - ld a, ITEMLISTMENU - ld [wListMenuID], a - call DisplayListMenuID - jp c, PlayerPCMenu - call IsKeyItem - ld a, 1 - ld [wItemQuantity], a - ld a, [wIsKeyItem] - and a - jr nz, .next -; if it's not a key item, there can be more than one of the item - ld hl, WithdrawHowManyText - call PrintText - call DisplayChooseQuantityMenu - cp $ff - jp z, .loop -.next - ld hl, wNumBagItems - call AddItemToInventory - jr c, .roomAvailable - ld hl, CantCarryMoreText - call PrintText - jp .loop -.roomAvailable - ld hl, wNumBoxItems - call RemoveItemFromInventory - call WaitForSoundToFinish - ld a, SFX_WITHDRAW_DEPOSIT - call PlaySound - call WaitForSoundToFinish - ld hl, WithdrewItemText - call PrintText - jp .loop - -PlayerPCToss: - xor a - ld [wCurrentMenuItem], a - ld [wListScrollOffset], a - ld a, [wNumBoxItems] - and a - jr nz, .loop - ld hl, NothingStoredText - call PrintText - jp PlayerPCMenu -.loop - ld hl, WhatToTossText - call PrintText - ld hl, wNumBoxItems - ld a, l - ld [wListPointer], a - ld a, h - ld [wListPointer + 1], a - xor a - ld [wPrintItemPrices], a - ld a, ITEMLISTMENU - ld [wListMenuID], a - push hl - call DisplayListMenuID - pop hl - jp c, PlayerPCMenu - push hl - call IsKeyItem - pop hl - ld a, 1 - ld [wItemQuantity], a - ld a, [wIsKeyItem] - and a - jr nz, .next - ld a, [wcf91] - call IsItemHM - jr c, .next -; if it's not a key item, there can be more than one of the item - push hl - ld hl, TossHowManyText - call PrintText - call DisplayChooseQuantityMenu - pop hl - cp $ff - jp z, .loop -.next - call TossItem ; disallows tossing key items - jp .loop - -PlayersPCMenuEntries: - db "WITHDRAW ITEM" - next "DEPOSIT ITEM" - next "TOSS ITEM" - next "LOG OFF@" - -TurnedOnPC2Text: - TX_FAR _TurnedOnPC2Text - db "@" - -WhatDoYouWantText: - TX_FAR _WhatDoYouWantText - db "@" - -WhatToDepositText: - TX_FAR _WhatToDepositText - db "@" - -DepositHowManyText: - TX_FAR _DepositHowManyText - db "@" - -ItemWasStoredText: - TX_FAR _ItemWasStoredText - db "@" - -NothingToDepositText: - TX_FAR _NothingToDepositText - db "@" - -NoRoomToStoreText: - TX_FAR _NoRoomToStoreText - db "@" - -WhatToWithdrawText: - TX_FAR _WhatToWithdrawText - db "@" - -WithdrawHowManyText: - TX_FAR _WithdrawHowManyText - db "@" - -WithdrewItemText: - TX_FAR _WithdrewItemText - db "@" - -NothingStoredText: - TX_FAR _NothingStoredText - db "@" - -CantCarryMoreText: - TX_FAR _CantCarryMoreText - db "@" - -WhatToTossText: - TX_FAR _WhatToTossText - db "@" - -TossHowManyText: - TX_FAR _TossHowManyText - db "@" diff --git a/engine/menu/pokedex.asm b/engine/menu/pokedex.asm deleted file mode 100755 index 8e1fd480..00000000 --- a/engine/menu/pokedex.asm +++ /dev/null @@ -1,665 +0,0 @@ -ShowPokedexMenu: - call GBPalWhiteOut - call ClearScreen - call UpdateSprites - ld a, [wListScrollOffset] - push af - xor a - ld [wCurrentMenuItem], a - ld [wListScrollOffset], a - ld [wLastMenuItem], a - inc a - ld [wd11e], a - ld [hJoy7], a -.setUpGraphics - ld b, SET_PAL_GENERIC - call RunPaletteCommand - callab LoadPokedexTilePatterns -.doPokemonListMenu - ld hl, wTopMenuItemY - ld a, 3 - ld [hli], a ; top menu item Y - xor a - ld [hli], a ; top menu item X - inc a - ld [wMenuWatchMovingOutOfBounds], a - inc hl - inc hl - ld a, 6 - ld [hli], a ; max menu item ID - ld [hl], D_LEFT | D_RIGHT | B_BUTTON | A_BUTTON - call HandlePokedexListMenu - jr c, .goToSideMenu ; if the player chose a pokemon from the list -.exitPokedex - xor a - ld [wMenuWatchMovingOutOfBounds], a - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - ld [hJoy7], a - ld [wWastedByteCD3A], a - ld [wOverrideSimulatedJoypadStatesMask], a - pop af - ld [wListScrollOffset], a - 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 - jp .setUpGraphics ; if pokemon data or area was shown - -; handles the menu on the lower right in the pokedex screen -; OUTPUT: -; b = reason for exiting menu -; 00: showed pokemon data or area -; 01: the player chose Quit -; 02: the pokemon has not been seen yet or the player pressed the B button -HandlePokedexSideMenu: - call PlaceUnfilledArrowMenuCursor - ld a, [wCurrentMenuItem] - push af - ld b, a - ld a, [wLastMenuItem] - push af - ld a, [wListScrollOffset] - push af - add b - inc a - ld [wd11e], a - ld a, [wd11e] - push af - ld a, [wDexMaxSeenMon] - push af ; this doesn't need to be preserved - ld hl, wPokedexSeen - call IsPokemonBitSet - ld b, 2 - jr z, .exitSideMenu - call PokedexToIndex - ld hl, wTopMenuItemY - ld a, 10 - 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 [hli], a ; max menu item ID - ;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 -.handleMenuInput - call HandleMenuInput - bit 1, a ; was the B button pressed? - ld b, 2 - jr nz, .buttonBPressed - ld a, [wCurrentMenuItem] - and a - jr z, .choseData - dec a - jr z, .choseCry - dec a - jr z, .choseArea -.choseQuit - ld b, 1 -.exitSideMenu - pop af - ld [wDexMaxSeenMon], a - pop af - ld [wd11e], a - pop af - ld [wListScrollOffset], a - pop af - ld [wLastMenuItem], a - pop af - ld [wCurrentMenuItem], a - push bc - coord hl, 0, 3 - ld de, 20 - lb bc, " ", 13 - call DrawTileLine ; cover up the menu cursor in the pokemon list - pop bc - ret - -.buttonBPressed - push bc - coord hl, 15, 10 - ld de, 20 - lb bc, " ", 7 - call DrawTileLine ; cover up the menu cursor in the side menu - pop bc - jr .exitSideMenu - -.choseData - call ShowPokedexDataInternal - ld b, 0 - jr .exitSideMenu - -; play pokemon cry -.choseCry - ld a, [wd11e] - call GetCryData - call PlaySound - jr .handleMenuInput - -.choseArea - predef LoadTownMap_Nest ; display pokemon areas - ld b, 0 - 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: - xor a - ld [H_AUTOBGTRANSFERENABLED], a -; draw the horizontal line separating the seen and owned amounts from the menu - coord hl, 15, 8 - ld a, "─" - ld [hli], a - ld [hli], a - ld [hli], a - ld [hli], a - ld [hli], a - coord hl, 14, 0 - ld [hl], $71 ; vertical line tile - coord hl, 14, 1 - call DrawPokedexVerticalLine - coord hl, 14, 9 - call DrawPokedexVerticalLine - ld hl, wPokedexSeen - ld b, wPokedexSeenEnd - wPokedexSeen - call CountSetBits - ld de, wNumSetBits - coord hl, 16, 3 - lb bc, 1, 3 - call PrintNumber ; print number of seen pokemon - ld hl, wPokedexOwned - ld b, wPokedexOwnedEnd - wPokedexOwned - call CountSetBits - ld de, wNumSetBits - coord hl, 16, 6 - lb bc, 1, 3 - call PrintNumber ; print number of owned pokemon - coord hl, 16, 2 - ld de, PokedexSeenText - call PlaceString - coord hl, 16, 5 - ld de, PokedexOwnText - call PlaceString - coord hl, 1, 1 - ld de, PokedexContentsText - call PlaceString - coord hl, 16, 10 - ld de, PokedexMenuItemsText - call PlaceString -; find the highest pokedex number among the pokemon the player has seen - ld hl, wPokedexSeenEnd - 1 - ld b, (wPokedexSeenEnd - wPokedexSeen) * 8 + 1 -.maxSeenPokemonLoop - ld a, [hld] - ld c, 8 -.maxSeenPokemonInnerLoop - dec b - sla a - jr c, .storeMaxSeenPokemon - dec c - jr nz, .maxSeenPokemonInnerLoop - jr .maxSeenPokemonLoop - -.storeMaxSeenPokemon - ld a, b - ld [wDexMaxSeenMon], a -.loop - xor a - ld [H_AUTOBGTRANSFERENABLED], a - coord hl, 4, 2 - lb bc, 14, 10 - call ClearScreenArea - coord hl, 1, 3 - ld a, [wListScrollOffset] - ld [wd11e], a - ld d, 7 - ld a, [wDexMaxSeenMon] - cp 7 - jr nc, .printPokemonLoop - ld d, a - dec a - ld [wMaxMenuItem], a -; loop to print pokemon pokedex numbers and names -; if the player has owned the pokemon, it puts a pokeball beside the name -.printPokemonLoop - ld a, [wd11e] - inc a - ld [wd11e], a - push af - push de - push hl - ld de, -SCREEN_WIDTH - add hl, de - ld de, wd11e - lb bc, LEADING_ZEROES | 1, 3 - call PrintNumber ; print the pokedex number - ld de, SCREEN_WIDTH - add hl, de - dec hl - push hl - ld hl, wPokedexOwned - call IsPokemonBitSet - pop hl - ld a, " " - jr z, .writeTile - ld a, $72 ; pokeball tile -.writeTile - ld [hl], a ; put a pokeball next to pokemon that the player has owned - push hl - ld hl, wPokedexSeen - call IsPokemonBitSet - jr nz, .getPokemonName ; if the player has seen the pokemon - ld de, .dashedLine ; print a dashed line in place of the name if the player hasn't seen the pokemon - jr .skipGettingName -.dashedLine ; for unseen pokemon in the list - db "----------@" -.getPokemonName - call PokedexToIndex - call GetMonName -.skipGettingName - pop hl - inc hl - call PlaceString - pop hl - ld bc, 2 * SCREEN_WIDTH - add hl, bc - pop de - pop af - ld [wd11e], a - dec d - jr nz, .printPokemonLoop - ld a, 01 - ld [H_AUTOBGTRANSFERENABLED], a - call Delay3 - call GBPalNormal - call HandleMenuInput - bit 1, a ; was the B button pressed? - jp nz, .buttonBPressed -.checkIfUpPressed - bit 6, a ; was Up pressed? - jr z, .checkIfDownPressed -.upPressed ; scroll up one row - ld a, [wListScrollOffset] - and a - jp z, .loop - dec a - ld [wListScrollOffset], a - jp .loop -.checkIfDownPressed - bit 7, a ; was Down pressed? - jr z, .checkIfRightPressed -.downPressed ; scroll down one row - ld a, [wDexMaxSeenMon] - cp 7 - jp c, .loop ; can't if the list is shorter than 7 - sub 7 - ld b, a - ld a, [wListScrollOffset] - cp b - jp z, .loop - inc a - ld [wListScrollOffset], a - jp .loop -.checkIfRightPressed - bit 4, a ; was Right pressed? - jr z, .checkIfLeftPressed -.rightPressed ; scroll down 7 rows - ld a, [wDexMaxSeenMon] - cp 7 - jp c, .loop ; can't if the list is shorter than 7 - sub 6 - ld b, a - ld a, [wListScrollOffset] - add 7 - ld [wListScrollOffset], a - cp b - jp c, .loop - dec b - ld a, b - ld [wListScrollOffset], a - jp .loop -.checkIfLeftPressed ; scroll up 7 rows - bit 5, a ; was Left pressed? - jr z, .buttonAPressed -.leftPressed - ld a, [wListScrollOffset] - sub 7 - ld [wListScrollOffset], a - jp nc, .loop - xor a - ld [wListScrollOffset], a - jp .loop -.buttonAPressed - scf - ret -.buttonBPressed - and a - ret - -DrawPokedexVerticalLine: - ld c, 9 ; height of line - ld de, SCREEN_WIDTH - ld a, $71 ; vertical line tile -.loop - ld [hl], a - add hl, de - xor 1 ; toggle between vertical line tile and box tile - dec c - jr nz, .loop - ret - -PokedexSeenText: - db "SEEN@" - -PokedexOwnText: - db "OWN@" - -PokedexContentsText: - db "CONTENTS@" - -PokedexMenuItemsText: - db "DATA" - next "CRY" - next "AREA" - next "QUIT@" - -; tests if a pokemon's bit is set in the seen or owned pokemon bit fields -; INPUT: -; [wd11e] = pokedex number -; hl = address of bit field -IsPokemonBitSet: - ld a, [wd11e] - dec a - ld c, a - ld b, FLAG_TEST - predef FlagActionPredef - ld a, c - and a - ret - -; function to display pokedex data from outside the pokedex -ShowPokedexData: - call GBPalWhiteOutWithDelay3 - call ClearScreen - call UpdateSprites - callab LoadPokedexTilePatterns ; load pokedex tiles - -; function to display pokedex data from inside the pokedex -ShowPokedexDataInternal: - ld hl, wd72c - set 1, [hl] - ld a, $33 ; 3/7 volume - ld [rNR50], a - call GBPalWhiteOut ; zero all palettes - call ClearScreen - ld a, [wd11e] ; pokemon ID - ld [wcf91], a - push af - ld b, SET_PAL_POKEDEX - call RunPaletteCommand - pop af - ld [wd11e], a - ld a, [hTilesetType] - push af - xor a - ld [hTilesetType], a - - coord hl, 0, 0 - ld de, 1 - lb bc, $64, SCREEN_WIDTH - call DrawTileLine ; draw top border - - coord hl, 0, 17 - ld b, $6f - call DrawTileLine ; draw bottom border - - coord hl, 0, 1 - ld de, 20 - lb bc, $66, $10 - call DrawTileLine ; draw left border - - coord hl, 19, 1 - ld b, $67 - call DrawTileLine ; draw right border - - ld a, $63 ; upper left corner tile - Coorda 0, 0 - ld a, $65 ; upper right corner tile - Coorda 19, 0 - ld a, $6c ; lower left corner tile - Coorda 0, 17 - ld a, $6e ; lower right corner tile - Coorda 19, 17 - - coord hl, 0, 9 - ld de, PokedexDataDividerLine - call PlaceString ; draw horizontal divider line - - coord hl, 9, 6 - ld de, HeightWeightText - call PlaceString - - call GetMonName - coord hl, 9, 2 - call PlaceString - - ld hl, PokedexEntryPointers - ld a, [wd11e] - dec a - ld e, a - ld d, 0 - add hl, de - add hl, de - ld a, [hli] - ld e, a - ld d, [hl] ; de = address of pokedex entry - - coord hl, 9, 4 - call PlaceString ; print species name - - ld h, b - ld l, c - push de - ld a, [wd11e] - push af - call IndexToPokedex - - coord hl, 2, 8 - ld a, "№" - ld [hli], a - ld a, "⠄" - ld [hli], a - ld de, wd11e - lb bc, LEADING_ZEROES | 1, 3 - call PrintNumber ; print pokedex number - - ld hl, wPokedexOwned - call IsPokemonBitSet - pop af - ld [wd11e], a - ld a, [wcf91] - ld [wd0b5], a - pop de - - push af - push bc - push de - push hl - - call Delay3 - call GBPalNormal - call GetMonHeader ; load pokemon picture location - coord hl, 1, 1 - call LoadFlippedFrontSpriteByMonIndex ; draw pokemon picture - ld a, [wcf91] - call PlayCry ; play pokemon cry - - pop hl - pop de - pop bc - pop af - - ld a, c - and a - jp z, .waitForButtonPress ; if the pokemon has not been owned, don't print the height, weight, or description - inc de ; de = address of feet (height) - ld a, [de] ; reads feet, but a is overwritten without being used - coord hl, 12, 6 - lb bc, 1, 2 - call PrintNumber ; print feet (height) - ld a, $60 ; feet symbol tile (one tick) - ld [hl], a - inc de - inc de ; de = address of inches (height) - coord hl, 15, 6 - lb bc, LEADING_ZEROES | 1, 2 - call PrintNumber ; print inches (height) - ld a, $61 ; inches symbol tile (two ticks) - ld [hl], a -; now print the weight (note that weight is stored in tenths of pounds internally) - inc de - inc de - inc de ; de = address of upper byte of weight - push de -; put weight in big-endian order at hDexWeight - ld hl, hDexWeight - ld a, [hl] ; save existing value of [hDexWeight] - push af - ld a, [de] ; a = upper byte of weight - ld [hli], a ; store upper byte of weight in [hDexWeight] - ld a, [hl] ; save existing value of [hDexWeight + 1] - push af - dec de - ld a, [de] ; a = lower byte of weight - ld [hl], a ; store lower byte of weight in [hDexWeight + 1] - ld de, hDexWeight - coord hl, 11, 8 - lb bc, 2, 5 ; 2 bytes, 5 digits - call PrintNumber ; print weight - coord hl, 14, 8 - ld a, [hDexWeight + 1] - sub 10 - ld a, [hDexWeight] - sbc 0 - jr nc, .next - ld [hl], "0" ; if the weight is less than 10, put a 0 before the decimal point -.next - inc hl - ld a, [hli] - ld [hld], a ; make space for the decimal point by moving the last digit forward one tile - ld [hl], "⠄" ; decimal point tile - pop af - ld [hDexWeight + 1], a ; restore original value of [hDexWeight + 1] - pop af - ld [hDexWeight], a ; restore original value of [hDexWeight] - pop hl - inc hl ; hl = address of pokedex description text - coord bc, 1, 11 - ld a, 2 - ld [$fff4], a - call TextCommandProcessor ; print pokedex description text - xor a - ld [$fff4], a -.waitForButtonPress - call JoypadLowSensitivity - ld a, [hJoy5] - and A_BUTTON | B_BUTTON - jr z, .waitForButtonPress - pop af - ld [hTilesetType], a - call GBPalWhiteOut - call ClearScreen - call RunDefaultPaletteCommand - call LoadTextBoxTilePatterns - call GBPalNormal - ld hl, wd72c - res 1, [hl] - ld a, $77 ; max volume - ld [rNR50], a - ret - -HeightWeightText: - db "HT ?",$60,"??",$61 - next "WT ???lb@" - -; XXX does anything point to this? -PokeText: - db "#@" - -; horizontal line that divides the pokedex text description from the rest of the data -PokedexDataDividerLine: - db $68,$69,$6B,$69,$6B - db $69,$6B,$69,$6B,$6B - db $6B,$6B,$69,$6B,$69 - db $6B,$69,$6B,$69,$6A - db "@" - -; draws a line of tiles -; INPUT: -; b = tile ID -; c = number of tile ID's to write -; de = amount to destination address after each tile (1 for horizontal, 20 for vertical) -; hl = destination address -DrawTileLine: - push bc - push de -.loop - ld [hl], b - add hl, de - dec c - jr nz, .loop - pop de - pop bc - ret - -INCLUDE "data/pokedex_entries.asm" - -PokedexToIndex: - ; converts the Pokédex number at wd11e to an index - push bc - push hl - ld a, [wd11e] - ld b, a - ld c, 0 - ld hl, PokedexOrder - -.loop ; go through the list until we find an entry with a matching dex number - inc c - ld a, [hli] - cp b - jr nz, .loop - - ld a, c - ld [wd11e], a - pop hl - pop bc - ret - -IndexToPokedex: - ; converts the index number at wd11e to a Pokédex number - push bc - push hl - ld a, [wd11e] - dec a - ld hl, PokedexOrder - ld b, 0 - ld c, a - add hl, bc - ld a, [hl] - ld [wd11e], a - pop hl - pop bc - ret - -INCLUDE "data/pokedex_order.asm" diff --git a/engine/menu/prize_menu.asm b/engine/menu/prize_menu.asm deleted file mode 100755 index 5e08bb8f..00000000 --- a/engine/menu/prize_menu.asm +++ /dev/null @@ -1,306 +0,0 @@ -CeladonPrizeMenu:: - ld b, COIN_CASE - call IsItemInBag - jr nz, .havingCoinCase - ld hl, RequireCoinCaseTextPtr - jp PrintText -.havingCoinCase - ld hl, wd730 - set 6, [hl] ; disable letter-printing delay - ld hl, ExchangeCoinsForPrizesTextPtr - call PrintText -; the following are the menu settings - xor a - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - ld a, A_BUTTON | B_BUTTON - ld [wMenuWatchedKeys], a - ld a, $03 - ld [wMaxMenuItem], a - ld a, $04 - ld [wTopMenuItemY], a - ld a, $01 - ld [wTopMenuItemX], a - call PrintPrizePrice - coord hl, 0, 2 - ld b, 8 - ld c, 16 - call TextBoxBorder - call GetPrizeMenuId - call UpdateSprites - ld hl, WhichPrizeTextPtr - call PrintText - call HandleMenuInput ; menu choice handler - bit 1, a ; keypress = B (Cancel) - jr nz, .noChoice - ld a, [wCurrentMenuItem] - cp 3 ; "NO,THANKS" choice - jr z, .noChoice - call HandlePrizeChoice -.noChoice - ld hl, wd730 - res 6, [hl] - ret - -RequireCoinCaseTextPtr: - TX_FAR _RequireCoinCaseText - TX_WAIT - db "@" - -ExchangeCoinsForPrizesTextPtr: - TX_FAR _ExchangeCoinsForPrizesText - db "@" - -WhichPrizeTextPtr: - TX_FAR _WhichPrizeText - db "@" - -GetPrizeMenuId: -; determine which one among the three -; prize-texts has been selected -; using the text ID (stored in [hSpriteIndexOrTextID]) -; load the three prizes at wd13d-wd13f -; load the three prices at wd141-wd146 -; display the three prizes' names -; (distinguishing between Pokemon names -; and Items (specifically TMs) names) - ld a, [hSpriteIndexOrTextID] - sub 3 ; prize-texts' id are 3, 4 and 5 - ld [wWhichPrizeWindow], a ; prize-texts' id (relative, i.e. 0, 1 or 2) - add a - add a - ld d, 0 - ld e, a - ld hl, PrizeDifferentMenuPtrs - add hl, de - ld a, [hli] - ld d, [hl] - ld e, a - inc hl - push hl - ld hl, wPrize1 - call CopyString - pop hl - ld a, [hli] - ld h, [hl] - ld l, a - ld de, wPrize1Price - ld bc, 6 - call CopyData - ld a, [wWhichPrizeWindow] - cp 2 ;is TM_menu? - jr nz, .putMonName - ld a, [wPrize1] - ld [wd11e], a - call GetItemName - coord hl, 2, 4 - call PlaceString - ld a, [wPrize2] - ld [wd11e], a - call GetItemName - coord hl, 2, 6 - call PlaceString - ld a, [wPrize3] - ld [wd11e], a - call GetItemName - coord hl, 2, 8 - call PlaceString - jr .putNoThanksText -.putMonName - ld a, [wPrize1] - ld [wd11e], a - call GetMonName - coord hl, 2, 4 - call PlaceString - ld a, [wPrize2] - ld [wd11e], a - call GetMonName - coord hl, 2, 6 - call PlaceString - ld a, [wPrize3] - ld [wd11e], a - call GetMonName - coord hl, 2, 8 - call PlaceString -.putNoThanksText - coord hl, 2, 10 - ld de, NoThanksText - call PlaceString -; put prices on the right side of the textbox - ld de, wPrize1Price - coord hl, 13, 5 -; reg. c: -; [low nybble] number of bytes -; [bit 765 = %100] space-padding (not zero-padding) - ld c, (1 << 7 | 2) -; Function $15CD displays BCD value (same routine -; used by text-command $02) - call PrintBCDNumber - ld de, wPrize2Price - coord hl, 13, 7 - ld c, (1 << 7 | 2) - call PrintBCDNumber - ld de, wPrize3Price - coord hl, 13, 9 - ld c, (1 << 7 | 2) - jp PrintBCDNumber - -INCLUDE "data/prizes.asm" - -PrintPrizePrice: - coord hl, 11, 0 - ld b, 1 - ld c, 7 - call TextBoxBorder - call UpdateSprites - coord hl, 12, 0 - ld de, .CoinString - call PlaceString - coord hl, 13, 1 - ld de, .SixSpacesString - call PlaceString - coord hl, 13, 1 - ld de, wPlayerCoins - ld c, %10000010 - call PrintBCDNumber - ret - -.CoinString: - db "COIN@" - -.SixSpacesString: - db " @" - -LoadCoinsToSubtract: - ld a, [wWhichPrize] - add a - ld d, 0 - ld e, a - ld hl, wPrize1Price - add hl, de ; get selected prize's price - xor a - ld [hUnusedCoinsByte], a - ld a, [hli] - ld [hCoins], a - ld a, [hl] - ld [hCoins + 1], a - ret - -HandlePrizeChoice: - ld a, [wCurrentMenuItem] - ld [wWhichPrize], a - ld d, 0 - ld e, a - ld hl, wPrize1 - add hl, de - ld a, [hl] - ld [wd11e], a - ld a, [wWhichPrizeWindow] - cp 2 ; is prize a TM? - jr nz, .getMonName - call GetItemName - jr .givePrize -.getMonName - call GetMonName -.givePrize - ld hl, SoYouWantPrizeTextPtr - call PrintText - call YesNoChoice - ld a, [wCurrentMenuItem] ; yes/no answer (Y=0, N=1) - and a - jr nz, .printOhFineThen - call LoadCoinsToSubtract - call HasEnoughCoins - jr c, .notEnoughCoins - ld a, [wWhichPrizeWindow] - cp $02 - jr nz, .giveMon - ld a, [wd11e] - ld b, a - ld a, 1 - ld c, a - call GiveItem - jr nc, .bagFull - jr .subtractCoins -.giveMon - ld a, [wd11e] - ld [wcf91], a - push af - call GetPrizeMonLevel - ld c, a - pop af - ld b, a - call GivePokemon - -; If either the party or box was full, wait after displaying message. - push af - ld a, [wAddedToParty] - and a - call z, WaitForTextScrollButtonPress - pop af - -; If the mon couldn't be given to the player (because both the party and box -; were full), return without subtracting coins. - ret nc - -.subtractCoins - call LoadCoinsToSubtract - ld hl, hCoins + 1 - ld de, wPlayerCoins + 1 - ld c, $02 ; how many bytes - predef SubBCDPredef - jp PrintPrizePrice -.bagFull - ld hl, PrizeRoomBagIsFullTextPtr - jp PrintText -.notEnoughCoins - ld hl, SorryNeedMoreCoinsText - jp PrintText -.printOhFineThen - ld hl, OhFineThenTextPtr - jp PrintText - -UnknownPrizeData: -; XXX what's this? - db $00,$01,$00,$01,$00,$01,$00,$00,$01 - -HereYouGoTextPtr: - TX_FAR _HereYouGoText - TX_WAIT - db "@" - -SoYouWantPrizeTextPtr: - TX_FAR _SoYouWantPrizeText - db "@" - -SorryNeedMoreCoinsText: - TX_FAR _SorryNeedMoreCoinsText - TX_WAIT - db "@" - -PrizeRoomBagIsFullTextPtr: - TX_FAR _OopsYouDontHaveEnoughRoomText - TX_WAIT - db "@" - -OhFineThenTextPtr: - TX_FAR _OhFineThenText - TX_WAIT - db "@" - -GetPrizeMonLevel: - ld a, [wcf91] - ld b, a - ld hl, PrizeMonLevelDictionary -.loop - ld a, [hli] - cp b - jr z, .matchFound - inc hl - jr .loop -.matchFound - ld a, [hl] - ld [wCurEnemyLVL], a - ret - -INCLUDE "data/prize_mon_levels.asm" diff --git a/engine/menu/start_menu.asm b/engine/menu/start_menu.asm deleted file mode 100755 index eb4b4f2d..00000000 --- a/engine/menu/start_menu.asm +++ /dev/null @@ -1,85 +0,0 @@ -DisplayStartMenu:: - ld a, BANK(StartMenu_Pokedex) - ld [H_LOADEDROMBANK], a - ld [MBC1RomBank], a - ld a, [wWalkBikeSurfState] ; walking/biking/surfing - ld [wWalkBikeSurfStateCopy], a - ld a, SFX_START_MENU - call PlaySound - -RedisplayStartMenu:: - callba DrawStartMenu - callba PrintSafariZoneSteps ; print Safari Zone info, if in Safari Zone - call UpdateSprites -.loop - call HandleMenuInput - ld b, a -.checkIfUpPressed - bit 6, a ; was Up pressed? - jr z, .checkIfDownPressed - ld a, [wCurrentMenuItem] ; menu selection - and a - jr nz, .loop - ld a, [wLastMenuItem] - and a - jr nz, .loop -; if the player pressed tried to go past the top item, wrap around to the bottom - CheckEvent EVENT_GOT_POKEDEX - ld a, 6 ; there are 7 menu items with the pokedex, so the max index is 6 - jr nz, .wrapMenuItemId - dec a ; there are only 6 menu items without the pokedex -.wrapMenuItemId - ld [wCurrentMenuItem], a - call EraseMenuCursor - jr .loop -.checkIfDownPressed - bit 7, a - jr z, .buttonPressed -; if the player pressed tried to go past the bottom item, wrap around to the top - CheckEvent EVENT_GOT_POKEDEX - ld a, [wCurrentMenuItem] - ld c, 7 ; there are 7 menu items with the pokedex - jr nz, .checkIfPastBottom - dec c ; there are only 6 menu items without the pokedex -.checkIfPastBottom - cp c - jr nz, .loop -; the player went past the bottom, so wrap to the top - xor a - ld [wCurrentMenuItem], a - call EraseMenuCursor - jr .loop -.buttonPressed ; A, B, or Start button pressed - call PlaceUnfilledArrowMenuCursor - ld a, [wCurrentMenuItem] - ld [wBattleAndStartSavedMenuItem], a ; save current menu selection - ld a, b - and %00001010 ; was the Start button or B button pressed? - jp nz, CloseStartMenu - call SaveScreenTilesToBuffer2 ; copy background from wTileMap to wTileMapBackup2 - CheckEvent EVENT_GOT_POKEDEX - ld a, [wCurrentMenuItem] - jr nz, .displayMenuItem - inc a ; adjust position to account for missing pokedex menu item -.displayMenuItem - cp 0 - jp z, StartMenu_Pokedex - cp 1 - jp z, StartMenu_Pokemon - cp 2 - jp z, StartMenu_Item - cp 3 - jp z, StartMenu_TrainerInfo - cp 4 - jp z, StartMenu_SaveReset - cp 5 - jp z, StartMenu_Option - -; EXIT falls through to here -CloseStartMenu:: - call Joypad - ld a, [hJoyPressed] - bit 0, a ; was A button newly pressed? - jr nz, CloseStartMenu - call LoadTextBoxTilePatterns - jp CloseTextDisplay diff --git a/engine/menu/start_sub_menus.asm b/engine/menu/start_sub_menus.asm deleted file mode 100755 index b81769a2..00000000 --- a/engine/menu/start_sub_menus.asm +++ /dev/null @@ -1,808 +0,0 @@ -StartMenu_Pokedex:: - predef ShowPokedexMenu - call LoadScreenTilesFromBuffer2 ; restore saved screen - call Delay3 - call LoadGBPal - call UpdateSprites - jp RedisplayStartMenu - -StartMenu_Pokemon:: - ld a, [wPartyCount] - and a - jp z, RedisplayStartMenu - xor a - ld [wMenuItemToSwap], a - ld [wPartyMenuTypeOrMessageID], a - ld [wUpdateSpritesEnabled], a - call DisplayPartyMenu - jr .checkIfPokemonChosen -.loop - xor a - ld [wMenuItemToSwap], a - ld [wPartyMenuTypeOrMessageID], a - call GoBackToPartyMenu -.checkIfPokemonChosen - jr nc, .chosePokemon -.exitMenu - call GBPalWhiteOutWithDelay3 - call RestoreScreenTilesAndReloadTilePatterns - call LoadGBPal - jp RedisplayStartMenu -.chosePokemon - call SaveScreenTilesToBuffer1 - ld a, FIELD_MOVE_MON_MENU - ld [wTextBoxID], a - call DisplayTextBoxID ; display pokemon menu options - ld hl, wFieldMoves - lb bc, 2, 12 ; max menu item ID, top menu item Y - ld e, 5 -.adjustMenuVariablesLoop - dec e - jr z, .storeMenuVariables - ld a, [hli] - and a ; end of field moves? - jr z, .storeMenuVariables - inc b - dec c - dec c - jr .adjustMenuVariablesLoop -.storeMenuVariables - ld hl, wTopMenuItemY - ld a, c - ld [hli], a ; top menu item Y - ld a, [hFieldMoveMonMenuTopMenuItemX] - ld [hli], a ; top menu item X - xor a - ld [hli], a ; current menu item ID - inc hl - ld a, b - ld [hli], a ; max menu item ID - ld a, A_BUTTON | B_BUTTON - ld [hli], a ; menu watched keys - xor a - ld [hl], a - call HandleMenuInput - push af - call LoadScreenTilesFromBuffer1 ; restore saved screen - pop af - bit 1, a ; was the B button pressed? - jp nz, .loop -; if the B button wasn't pressed - ld a, [wMaxMenuItem] - ld b, a - ld a, [wCurrentMenuItem] ; menu selection - cp b - jp z, .exitMenu ; if the player chose Cancel - dec b - cp b - jr z, .choseSwitch - dec b - cp b - jp z, .choseStats - ld c, a - ld b, 0 - ld hl, wFieldMoves - add hl, bc - jp .choseOutOfBattleMove -.choseSwitch - ld a, [wPartyCount] - cp 2 ; is there more than one pokemon in the party? - jp c, StartMenu_Pokemon ; if not, no switching - call SwitchPartyMon_InitVarOrSwapData ; init [wMenuItemToSwap] - ld a, SWAP_MONS_PARTY_MENU - ld [wPartyMenuTypeOrMessageID], a - call GoBackToPartyMenu - jp .checkIfPokemonChosen -.choseStats - call ClearSprites - xor a ; PLAYER_PARTY_DATA - ld [wMonDataLocation], a - predef StatusScreen - predef StatusScreen2 - call ReloadMapData - jp StartMenu_Pokemon -.choseOutOfBattleMove - push hl - ld a, [wWhichPokemon] - ld hl, wPartyMonNicks - call GetPartyMonName - pop hl - ld a, [hl] - dec a - add a - ld b, 0 - ld c, a - ld hl, .outOfBattleMovePointers - add hl, bc - ld a, [hli] - ld h, [hl] - ld l, a - ld a, [wObtainedBadges] ; badges obtained - jp hl -.outOfBattleMovePointers - dw .cut - dw .fly - dw .surf - dw .surf - dw .strength - dw .flash - dw .dig - dw .teleport - dw .softboiled -.fly - bit 2, a ; does the player have the Thunder Badge? - jp z, .newBadgeRequired - call CheckIfInOutsideMap - jr z, .canFly - ld a, [wWhichPokemon] - ld hl, wPartyMonNicks - call GetPartyMonName - ld hl, .cannotFlyHereText - call PrintText - jp .loop -.canFly - call ChooseFlyDestination - ld a, [wd732] - bit 3, a ; did the player decide to fly? - jp nz, .goBackToMap - call LoadFontTilePatterns - ld hl, wd72e - set 1, [hl] - jp StartMenu_Pokemon -.cut - bit 1, a ; does the player have the Cascade Badge? - jp z, .newBadgeRequired - predef UsedCut - ld a, [wActionResultOrTookBattleTurn] - and a - jp z, .loop - jp CloseTextDisplay -.surf - bit 4, a ; does the player have the Soul Badge? - jp z, .newBadgeRequired - callba IsSurfingAllowed - ld hl, wd728 - bit 1, [hl] - res 1, [hl] - jp z, .loop - ld a, SURFBOARD - ld [wcf91], a - ld [wPseudoItemID], a - call UseItem - ld a, [wActionResultOrTookBattleTurn] - and a - jp z, .loop - call GBPalWhiteOutWithDelay3 - jp .goBackToMap -.strength - bit 3, a ; does the player have the Rainbow Badge? - jp z, .newBadgeRequired - predef PrintStrengthTxt - call GBPalWhiteOutWithDelay3 - jp .goBackToMap -.flash - bit 0, a ; does the player have the Boulder Badge? - jp z, .newBadgeRequired - xor a - ld [wMapPalOffset], a - ld hl, .flashLightsAreaText - call PrintText - call GBPalWhiteOutWithDelay3 - jp .goBackToMap -.flashLightsAreaText - TX_FAR _FlashLightsAreaText - db "@" -.dig - ld a, ESCAPE_ROPE - ld [wcf91], a - ld [wPseudoItemID], a - call UseItem - ld a, [wActionResultOrTookBattleTurn] - and a - jp z, .loop - call GBPalWhiteOutWithDelay3 - jp .goBackToMap -.teleport - call CheckIfInOutsideMap - jr z, .canTeleport - ld a, [wWhichPokemon] - ld hl, wPartyMonNicks - call GetPartyMonName - ld hl, .cannotUseTeleportNowText - call PrintText - jp .loop -.canTeleport - ld hl, .warpToLastPokemonCenterText - call PrintText - ld hl, wd732 - set 3, [hl] - set 6, [hl] - ld hl, wd72e - set 1, [hl] - res 4, [hl] - ld c, 60 - call DelayFrames - call GBPalWhiteOutWithDelay3 - jp .goBackToMap -.warpToLastPokemonCenterText - TX_FAR _WarpToLastPokemonCenterText - db "@" -.cannotUseTeleportNowText - TX_FAR _CannotUseTeleportNowText - db "@" -.cannotFlyHereText - TX_FAR _CannotFlyHereText - db "@" -.softboiled - ld hl, wPartyMon1MaxHP - ld a, [wWhichPokemon] - ld bc, wPartyMon2 - wPartyMon1 - call AddNTimes - ld a, [hli] - ld [H_DIVIDEND], a - ld a, [hl] - ld [H_DIVIDEND + 1], a - ld a, 5 - ld [H_DIVISOR], a - ld b, 2 ; number of bytes - call Divide - ld bc, wPartyMon1HP - wPartyMon1MaxHP - add hl, bc - ld a, [hld] - ld b, a - ld a, [H_QUOTIENT + 3] - sub b - ld b, [hl] - ld a, [H_QUOTIENT + 2] - sbc b - jp nc, .notHealthyEnough - ld a, [wPartyAndBillsPCSavedMenuItem] - push af - ld a, POTION - ld [wcf91], a - ld [wPseudoItemID], a - call UseItem - pop af - ld [wPartyAndBillsPCSavedMenuItem], a - jp .loop -.notHealthyEnough ; if current HP is less than 1/5 of max HP - ld hl, .notHealthyEnoughText - call PrintText - jp .loop -.notHealthyEnoughText - TX_FAR _NotHealthyEnoughText - db "@" -.goBackToMap - call RestoreScreenTilesAndReloadTilePatterns - jp CloseTextDisplay -.newBadgeRequired - ld hl, .newBadgeRequiredText - call PrintText - jp .loop -.newBadgeRequiredText - TX_FAR _NewBadgeRequiredText - db "@" - -; writes a blank tile to all possible menu cursor positions on the party menu -ErasePartyMenuCursors:: - coord hl, 0, 1 - ld bc, 2 * 20 ; menu cursor positions are 2 rows apart - ld a, 6 ; 6 menu cursor positions -.loop - ld [hl], " " - add hl, bc - dec a - jr nz, .loop - ret - -ItemMenuLoop: - call LoadScreenTilesFromBuffer2DisableBGTransfer ; restore saved screen - call RunDefaultPaletteCommand - -StartMenu_Item:: - ld a, [wLinkState] - dec a ; is the player in the Colosseum or Trade Centre? - jr nz, .notInCableClubRoom - ld hl, CannotUseItemsHereText - 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) - xor a - ld [wPrintItemPrices], a - ld a, ITEMLISTMENU - ld [wListMenuID], a - ld a, [wBagSavedMenuItem] - ld [wCurrentMenuItem], a - call DisplayListMenuID - ld a, [wCurrentMenuItem] - ld [wBagSavedMenuItem], a - jr nc, .choseItem -.exitMenu - call LoadScreenTilesFromBuffer2 ; restore saved screen - call LoadTextBoxTilePatterns - call UpdateSprites - jp RedisplayStartMenu -.choseItem -; erase menu cursor (blank each tile in front of an item name) - ld a, " " - Coorda 5, 4 - Coorda 5, 6 - Coorda 5, 8 - Coorda 5, 10 - call PlaceUnfilledArrowMenuCursor - xor a - ld [wMenuItemToSwap], a - ld a, [wcf91] - cp BICYCLE - jp z, .useOrTossItem -.notBicycle1 - ld a, USE_TOSS_MENU_TEMPLATE - ld [wTextBoxID], a - call DisplayTextBoxID - ld hl, wTopMenuItemY - ld a, 11 - ld [hli], a ; top menu item Y - ld a, 14 - ld [hli], a ; top menu item X - xor a - ld [hli], a ; current menu item ID - inc hl - inc a ; a = 1 - ld [hli], a ; max menu item ID - ld a, A_BUTTON | B_BUTTON - ld [hli], a ; menu watched keys - xor a - ld [hl], a ; old menu item id - call HandleMenuInput - call PlaceUnfilledArrowMenuCursor - bit 1, a ; was the B button pressed? - jr z, .useOrTossItem - jp ItemMenuLoop -.useOrTossItem ; if the player made the choice to use or toss the item - ld a, [wcf91] - ld [wd11e], a - call GetItemName - call CopyStringToCF4B ; copy name to wcf4b - ld a, [wcf91] - cp BICYCLE - jr nz, .notBicycle2 - ld a, [wd732] - bit 5, a - jr z, .useItem_closeMenu - ld hl, CannotGetOffHereText - call PrintText - jp ItemMenuLoop -.notBicycle2 - ld a, [wCurrentMenuItem] - and a - jr nz, .tossItem -; use item - ld [wPseudoItemID], a ; a must be 0 due to above conditional jump - ld a, [wcf91] - cp HM_01 - jr nc, .useItem_partyMenu - ld hl, UsableItems_CloseMenu - ld de, 1 - call IsInArray - jr c, .useItem_closeMenu - ld a, [wcf91] - ld hl, UsableItems_PartyMenu - ld de, 1 - call IsInArray - jr c, .useItem_partyMenu - call UseItem - jp ItemMenuLoop -.useItem_closeMenu - xor a - ld [wPseudoItemID], a - call UseItem - ld a, [wActionResultOrTookBattleTurn] - and a - jp z, ItemMenuLoop - jp CloseStartMenu -.useItem_partyMenu - ld a, [wUpdateSpritesEnabled] - push af - call UseItem - ld a, [wActionResultOrTookBattleTurn] - cp $02 - jp z, .partyMenuNotDisplayed - call GBPalWhiteOutWithDelay3 - call RestoreScreenTilesAndReloadTilePatterns - pop af - ld [wUpdateSpritesEnabled], a - jp StartMenu_Item -.partyMenuNotDisplayed - pop af - ld [wUpdateSpritesEnabled], a - jp ItemMenuLoop -.tossItem - call IsKeyItem - ld a, [wIsKeyItem] - and a - jr nz, .skipAskingQuantity - ld a, [wcf91] - call IsItemHM - jr c, .skipAskingQuantity - call DisplayChooseQuantityMenu - inc a - jr z, .tossZeroItems -.skipAskingQuantity - ld hl, wNumBagItems - call TossItem -.tossZeroItems - jp ItemMenuLoop - -CannotUseItemsHereText: - TX_FAR _CannotUseItemsHereText - db "@" - -CannotGetOffHereText: - TX_FAR _CannotGetOffHereText - db "@" - -INCLUDE "data/party_items.asm" - -INCLUDE "data/overworld_items.asm" - -StartMenu_TrainerInfo:: - call GBPalWhiteOut - call ClearScreen - call UpdateSprites - ld a, [hTilesetType] - push af - xor a - ld [hTilesetType], a - call DrawTrainerInfo - predef DrawBadges ; draw badges - ld b, SET_PAL_TRAINER_CARD - call RunPaletteCommand - call GBPalNormal - call WaitForTextScrollButtonPress ; wait for button press - call GBPalWhiteOut - call LoadFontTilePatterns - call LoadScreenTilesFromBuffer2 ; restore saved screen - call RunDefaultPaletteCommand - call ReloadMapData - call LoadGBPal - pop af - ld [hTilesetType], a - jp RedisplayStartMenu - -; loads tile patterns and draws everything except for gym leader faces / badges -DrawTrainerInfo: - ld de, RedPicFront - lb bc, BANK(RedPicFront), $01 - predef DisplayPicCenteredOrUpperRight - call DisableLCD - coord hl, 0, 2 - ld a, " " - call TrainerInfo_DrawVerticalLine - coord hl, 1, 2 - call TrainerInfo_DrawVerticalLine - ld hl, vChars2 + $70 - ld de, vChars2 - ld bc, $70 * 4 - call CopyData - ld hl, TrainerInfoTextBoxTileGraphics ; trainer info text box tile patterns - ld de, vChars2 + $770 - ld bc, $0080 - push bc - call TrainerInfo_FarCopyData - ld hl, BlankLeaderNames - ld de, vChars2 + $600 - ld bc, $0170 - call TrainerInfo_FarCopyData - pop bc - ld hl, BadgeNumbersTileGraphics ; badge number tile patterns - ld de, vChars1 + $580 - call TrainerInfo_FarCopyData - ld hl, GymLeaderFaceAndBadgeTileGraphics ; gym leader face and badge tile patterns - ld de, vChars2 + $200 - ld bc, $0400 - ld a, $03 - call FarCopyData2 - ld hl, TextBoxGraphics - ld de, $00d0 - add hl, de ; hl = colon tile pattern - ld de, vChars1 + $560 - ld bc, $0010 - ld a, $04 - push bc - call FarCopyData2 - pop bc - ld hl, TrainerInfoTextBoxTileGraphics + $80 ; background tile pattern - ld de, vChars1 + $570 - call TrainerInfo_FarCopyData - call EnableLCD - ld hl, wTrainerInfoTextBoxWidthPlus1 - ld a, 18 + 1 - ld [hli], a - dec a - ld [hli], a - ld [hl], 1 - coord hl, 0, 0 - call TrainerInfo_DrawTextBox - ld hl, wTrainerInfoTextBoxWidthPlus1 - ld a, 16 + 1 - ld [hli], a - dec a - ld [hli], a - ld [hl], 3 - coord hl, 1, 10 - call TrainerInfo_DrawTextBox - coord hl, 0, 10 - ld a, $d7 - call TrainerInfo_DrawVerticalLine - coord hl, 19, 10 - call TrainerInfo_DrawVerticalLine - coord hl, 6, 9 - ld de, TrainerInfo_BadgesText - call PlaceString - coord hl, 2, 2 - ld de, TrainerInfo_NameMoneyTimeText - call PlaceString - coord hl, 7, 2 - ld de, wPlayerName - call PlaceString - coord hl, 8, 4 - ld de, wPlayerMoney - ld c, $e3 - call PrintBCDNumber - coord hl, 9, 6 - ld de, wPlayTimeHours ; hours - lb bc, LEFT_ALIGN | 1, 3 - call PrintNumber - ld [hl], $d6 ; colon tile ID - inc hl - ld de, wPlayTimeMinutes ; minutes - lb bc, LEADING_ZEROES | 1, 2 - jp PrintNumber - -TrainerInfo_FarCopyData: - ld a, BANK(TrainerInfoTextBoxTileGraphics) - jp FarCopyData2 - -TrainerInfo_NameMoneyTimeText: - db "NAME/" - next "MONEY/" - next "TIME/@" - -; $76 is a circle tile -TrainerInfo_BadgesText: - db $76,"BADGES",$76,"@" - -; draws a text box on the trainer info screen -; height is always 6 -; INPUT: -; hl = destination address -; [wTrainerInfoTextBoxWidthPlus1] = width -; [wTrainerInfoTextBoxWidth] = width - 1 -; [wTrainerInfoTextBoxNextRowOffset] = distance from the end of a text box row to the start of the next -TrainerInfo_DrawTextBox: - ld a, $79 ; upper left corner tile ID - lb de, $7a, $7b ; top edge and upper right corner tile ID's - call TrainerInfo_DrawHorizontalEdge ; draw top edge - call TrainerInfo_NextTextBoxRow - ld a, [wTrainerInfoTextBoxWidthPlus1] - ld e, a - ld d, 0 - ld c, 6 ; height of the text box -.loop - ld [hl], $7c ; left edge tile ID - add hl, de - ld [hl], $78 ; right edge tile ID - call TrainerInfo_NextTextBoxRow - dec c - jr nz, .loop - ld a, $7d ; lower left corner tile ID - lb de, $77, $7e ; bottom edge and lower right corner tile ID's - -TrainerInfo_DrawHorizontalEdge: - ld [hli], a ; place left corner tile - ld a, [wTrainerInfoTextBoxWidth] - ld c, a - ld a, d -.loop - ld [hli], a ; place edge tile - dec c - jr nz, .loop - ld a, e - ld [hl], a ; place right corner tile - ret - -TrainerInfo_NextTextBoxRow: - ld a, [wTrainerInfoTextBoxNextRowOffset] ; distance to the start of the next row -.loop - inc hl - dec a - jr nz, .loop - ret - -; draws a vertical line -; INPUT: -; hl = address of top tile in the line -; a = tile ID -TrainerInfo_DrawVerticalLine: - ld de, SCREEN_WIDTH - ld c, 8 -.loop - ld [hl], a - add hl, de - dec c - jr nz, .loop - ret - -StartMenu_SaveReset:: - ld a, [wd72e] - bit 6, a ; is the player using the link feature? - jp nz, Init - predef SaveSAV ; save the game - call LoadScreenTilesFromBuffer2 ; restore saved screen - jp HoldTextDisplayOpen - -StartMenu_Option:: - xor a - ld [H_AUTOBGTRANSFERENABLED], a - call ClearScreen - call UpdateSprites - callab DisplayOptionMenu - call LoadScreenTilesFromBuffer2 ; restore saved screen - call LoadTextBoxTilePatterns - call UpdateSprites - jp RedisplayStartMenu - -SwitchPartyMon:: - call SwitchPartyMon_InitVarOrSwapData ; swap data - ld a, [wSwappedMenuItem] - call SwitchPartyMon_ClearGfx - ld a, [wCurrentMenuItem] - call SwitchPartyMon_ClearGfx - jp RedrawPartyMenu_ - -SwitchPartyMon_ClearGfx: - push af - coord hl, 0, 0 - ld bc, SCREEN_WIDTH * 2 - call AddNTimes - ld c, SCREEN_WIDTH * 2 - ld a, " " -.clearMonBGLoop ; clear the mon's row in the party menu - ld [hli], a - dec c - jr nz, .clearMonBGLoop - pop af - ld hl, wOAMBuffer - ld bc, $10 - call AddNTimes - ld de, $4 - ld c, e -.clearMonOAMLoop - ld [hl], $a0 - add hl, de - dec c - jr nz, .clearMonOAMLoop - call WaitForSoundToFinish - ld a, SFX_SWAP - jp PlaySound - -SwitchPartyMon_InitVarOrSwapData: -; This is used to initialise [wMenuItemToSwap] and to actually swap the data. - ld a, [wMenuItemToSwap] - and a ; has [wMenuItemToSwap] been initialised yet? - jr nz, .pickedMonsToSwap -; If not, initialise [wMenuItemToSwap] so that it matches the current mon. - ld a, [wWhichPokemon] - inc a ; [wMenuItemToSwap] counts from 1 - ld [wMenuItemToSwap], a - ret -.pickedMonsToSwap - xor a - ld [wPartyMenuTypeOrMessageID], a - ld a, [wMenuItemToSwap] - dec a - ld b, a - ld a, [wCurrentMenuItem] - ld [wSwappedMenuItem], a - cp b ; swapping a mon with itself? - jr nz, .swappingDifferentMons -; can't swap a mon with itself - xor a - ld [wMenuItemToSwap], a - ld [wPartyMenuTypeOrMessageID], a - ret -.swappingDifferentMons - ld a, b - ld [wMenuItemToSwap], a - push hl - push de - ld hl, wPartySpecies - ld d, h - ld e, l - ld a, [wCurrentMenuItem] - add l - ld l, a - jr nc, .noCarry - inc h -.noCarry - ld a, [wMenuItemToSwap] - add e - ld e, a - jr nc, .noCarry2 - inc d -.noCarry2 - ld a, [hl] - ld [hSwapTemp], a - ld a, [de] - ld [hl], a - ld a, [hSwapTemp] - ld [de], a - ld hl, wPartyMons - ld bc, wPartyMon2 - wPartyMon1 - ld a, [wCurrentMenuItem] - call AddNTimes - push hl - ld de, wSwitchPartyMonTempBuffer - ld bc, wPartyMon2 - wPartyMon1 - call CopyData - ld hl, wPartyMons - ld bc, wPartyMon2 - wPartyMon1 - ld a, [wMenuItemToSwap] - call AddNTimes - pop de - push hl - ld bc, wPartyMon2 - wPartyMon1 - call CopyData - pop de - ld hl, wSwitchPartyMonTempBuffer - ld bc, wPartyMon2 - wPartyMon1 - call CopyData - ld hl, wPartyMonOT - ld a, [wCurrentMenuItem] - call SkipFixedLengthTextEntries - push hl - ld de, wSwitchPartyMonTempBuffer - ld bc, NAME_LENGTH - call CopyData - ld hl, wPartyMonOT - ld a, [wMenuItemToSwap] - call SkipFixedLengthTextEntries - pop de - push hl - ld bc, NAME_LENGTH - call CopyData - pop de - ld hl, wSwitchPartyMonTempBuffer - ld bc, NAME_LENGTH - call CopyData - ld hl, wPartyMonNicks - ld a, [wCurrentMenuItem] - call SkipFixedLengthTextEntries - push hl - ld de, wSwitchPartyMonTempBuffer - ld bc, NAME_LENGTH - call CopyData - ld hl, wPartyMonNicks - ld a, [wMenuItemToSwap] - call SkipFixedLengthTextEntries - pop de - push hl - ld bc, NAME_LENGTH - call CopyData - pop de - ld hl, wSwitchPartyMonTempBuffer - ld bc, NAME_LENGTH - call CopyData - ld a, [wMenuItemToSwap] - ld [wSwappedMenuItem], a - xor a - ld [wMenuItemToSwap], a - ld [wPartyMenuTypeOrMessageID], a - pop de - pop hl - ret diff --git a/engine/menu/status_screen.asm b/engine/menu/status_screen.asm deleted file mode 100755 index 20bee0ee..00000000 --- a/engine/menu/status_screen.asm +++ /dev/null @@ -1,481 +0,0 @@ -DrawHP: -; Draws the HP bar in the stats screen - call GetPredefRegisters - ld a, $1 - jr DrawHP_ - -DrawHP2: -; Draws the HP bar in the party screen - call GetPredefRegisters - ld a, $2 - -DrawHP_: - ld [wHPBarType], a - push hl - ld a, [wLoadedMonHP] - ld b, a - ld a, [wLoadedMonHP + 1] - ld c, a - or b - jr nz, .nonzeroHP - xor a - ld c, a - ld e, a - ld a, $6 - ld d, a - jp .drawHPBarAndPrintFraction -.nonzeroHP - ld a, [wLoadedMonMaxHP] - ld d, a - ld a, [wLoadedMonMaxHP + 1] - ld e, a - predef HPBarLength - ld a, $6 - ld d, a - ld c, a -.drawHPBarAndPrintFraction - pop hl - push de - push hl - push hl - call DrawHPBar - pop hl - ld a, [hFlags_0xFFF6] - bit 0, a - jr z, .printFractionBelowBar - ld bc, $9 ; right of bar - jr .printFraction -.printFractionBelowBar - ld bc, SCREEN_WIDTH + 1 ; below bar -.printFraction - add hl, bc - ld de, wLoadedMonHP - lb bc, 2, 3 - call PrintNumber - ld a, "/" - ld [hli], a - ld de, wLoadedMonMaxHP - lb bc, 2, 3 - call PrintNumber - pop hl - pop de - ret - - -; Predef 0x37 -StatusScreen: - call LoadMonData - ld a, [wMonDataLocation] - cp BOX_DATA - jr c, .DontRecalculate -; mon is in a box or daycare - ld a, [wLoadedMonBoxLevel] - ld [wLoadedMonLevel], a - ld [wCurEnemyLVL], a - ld hl, wLoadedMonHPExp - 1 - ld de, wLoadedMonStats - ld b, $1 - call CalcStats ; Recalculate stats -.DontRecalculate - ld hl, wd72c - set 1, [hl] - ld a, $33 - ld [rNR50], a ; Reduce the volume - call GBPalWhiteOutWithDelay3 - call ClearScreen - call UpdateSprites - call LoadHpBarAndStatusTilePatterns - ld de, BattleHudTiles1 ; source - ld hl, vChars2 + $6d0 ; dest - lb bc, BANK(BattleHudTiles1), $03 - call CopyVideoDataDouble ; ·│ :L and halfarrow line end - ld de, BattleHudTiles2 - ld hl, vChars2 + $780 - lb bc, BANK(BattleHudTiles2), $01 - call CopyVideoDataDouble ; │ - ld de, BattleHudTiles3 - ld hl, vChars2 + $760 - lb bc, BANK(BattleHudTiles3), $02 - call CopyVideoDataDouble ; ─┘ - ld de, PTile - ld hl, vChars2 + $720 - lb bc, BANK(PTile), (PTileEnd - PTile) / $8 - call CopyVideoDataDouble ; P (for PP), inline - ld a, [hTilesetType] - push af - xor a - ld [hTilesetType], a - coord hl, 19, 1 - lb bc, 6, 10 - call DrawLineBox ; Draws the box around name, HP and status - ld de, -6 - add hl, de - ld [hl], "⠄" ; . after No ("." is a different one) - dec hl - ld [hl], "№" - coord hl, 19, 9 - lb bc, 8, 6 - call DrawLineBox ; Draws the box around types, ID No. and OT - coord hl, 10, 9 - ld de, Type1Text - call PlaceString ; "TYPE1/" - coord hl, 11, 3 - predef DrawHP - ld hl, wStatusScreenHPBarColor - call GetHealthBarColor - ld b, SET_PAL_STATUS_SCREEN - call RunPaletteCommand - coord hl, 16, 6 - ld de, wLoadedMonStatus - call PrintStatusCondition - jr nz, .StatusWritten - coord hl, 16, 6 - ld de, OKText - call PlaceString ; "OK" -.StatusWritten - coord hl, 9, 6 - ld de, StatusText - call PlaceString ; "STATUS/" - coord hl, 14, 2 - call PrintLevel ; Pokémon level - ld a, [wMonHIndex] - ld [wd11e], a - ld [wd0b5], a - predef IndexToPokedex - coord hl, 3, 7 - ld de, wd11e - lb bc, LEADING_ZEROES | 1, 3 - call PrintNumber ; Pokémon no. - coord hl, 11, 10 - predef PrintMonType - ld hl, NamePointers2 - call .GetStringPointer - ld d, h - ld e, l - coord hl, 9, 1 - call PlaceString ; Pokémon name - ld hl, OTPointers - call .GetStringPointer - ld d, h - ld e, l - coord hl, 12, 16 - call PlaceString ; OT - coord hl, 12, 14 - ld de, wLoadedMonOTID - lb bc, LEADING_ZEROES | 2, 5 - call PrintNumber ; ID Number - ld d, $0 - call PrintStatsBox - call Delay3 - call GBPalNormal - coord hl, 1, 0 - call LoadFlippedFrontSpriteByMonIndex ; draw Pokémon picture - ld a, [wcf91] - call PlayCry ; play Pokémon cry - call WaitForTextScrollButtonPress ; wait for button - pop af - ld [hTilesetType], a - ret - -.GetStringPointer - ld a, [wMonDataLocation] - add a - ld c, a - ld b, 0 - add hl, bc - ld a, [hli] - ld h, [hl] - ld l, a - ld a, [wMonDataLocation] - cp DAYCARE_DATA - ret z - ld a, [wWhichPokemon] - jp SkipFixedLengthTextEntries - -OTPointers: - dw wPartyMonOT - dw wEnemyMonOT - dw wBoxMonOT - dw wDayCareMonOT - -NamePointers2: - dw wPartyMonNicks - dw wEnemyMonNicks - dw wBoxMonNicks - dw wDayCareMonName - -Type1Text: - db "TYPE1/", $4e - -Type2Text: - db "TYPE2/", $4e - -IDNoText: - db $73, "№/", $4e - -OTText: - db "OT/" - next "@" - -StatusText: - db "STATUS/@" - -OKText: - db "OK@" - -; Draws a line starting from hl high b and wide c -DrawLineBox: - ld de, SCREEN_WIDTH ; New line -.PrintVerticalLine - ld [hl], $78 ; │ - add hl, de - dec b - jr nz, .PrintVerticalLine - ld [hl], $77 ; ┘ - dec hl -.PrintHorizLine - ld [hl], $76 ; ─ - dec hl - dec c - jr nz, .PrintHorizLine - ld [hl], $6f ; ← (halfarrow ending) - ret - -PTile: - INCBIN "gfx/font/P.1bpp" -PTileEnd: - -PrintStatsBox: - ld a, d - and a ; a is 0 from the status screen - jr nz, .DifferentBox - coord hl, 0, 8 - ld b, 8 - ld c, 8 - call TextBoxBorder ; Draws the box - coord hl, 1, 9 ; Start printing stats from here - ld bc, $0019 ; Number offset - jr .PrintStats -.DifferentBox - coord hl, 9, 2 - ld b, 8 - ld c, 9 - call TextBoxBorder - coord hl, 11, 3 - ld bc, $0018 -.PrintStats - push bc - push hl - ld de, StatsText - call PlaceString - pop hl - pop bc - add hl, bc - ld de, wLoadedMonAttack - lb bc, 2, 3 - call PrintStat - ld de, wLoadedMonDefense - call PrintStat - ld de, wLoadedMonSpeed - call PrintStat - ld de, wLoadedMonSpecial - jp PrintNumber -PrintStat: - push hl - call PrintNumber - pop hl - ld de, SCREEN_WIDTH * 2 - add hl, de - ret - -StatsText: - db "ATTACK" - next "DEFENSE" - next "SPEED" - next "SPECIAL@" - -StatusScreen2: - ld a, [hTilesetType] - push af - xor a - ld [hTilesetType], a - ld [H_AUTOBGTRANSFERENABLED], a - ld bc, NUM_MOVES + 1 - ld hl, wMoves - call FillMemory - ld hl, wLoadedMonMoves - ld de, wMoves - ld bc, NUM_MOVES - call CopyData - callab FormatMovesString - coord hl, 9, 2 - lb bc, 5, 10 - call ClearScreenArea ; Clear under name - coord hl, 19, 3 - ld [hl], $78 - coord hl, 0, 8 - ld b, 8 - ld c, 18 - call TextBoxBorder ; Draw move container - coord hl, 2, 9 - ld de, wMovesString - call PlaceString ; Print moves - ld a, [wNumMovesMinusOne] - inc a - ld c, a - ld a, $4 - sub c - ld b, a ; Number of moves ? - coord hl, 11, 10 - ld de, SCREEN_WIDTH * 2 - ld a, $72 ; special P tile id - call StatusScreen_PrintPP ; Print "PP" - ld a, b - and a - jr z, .InitPP - ld c, a - ld a, "-" - call StatusScreen_PrintPP ; Fill the rest with -- -.InitPP - ld hl, wLoadedMonMoves - coord de, 14, 10 - ld b, 0 -.PrintPP - ld a, [hli] - and a - jr z, .PPDone - push bc - push hl - push de - ld hl, wCurrentMenuItem - ld a, [hl] - push af - ld a, b - ld [hl], a - push hl - callab GetMaxPP - pop hl - pop af - ld [hl], a - pop de - pop hl - push hl - ld bc, wPartyMon1PP - wPartyMon1Moves - 1 - add hl, bc - ld a, [hl] - and $3f - ld [wStatusScreenCurrentPP], a - ld h, d - ld l, e - push hl - ld de, wStatusScreenCurrentPP - lb bc, 1, 2 - call PrintNumber - ld a, "/" - ld [hli], a - ld de, wMaxPP - lb bc, 1, 2 - call PrintNumber - pop hl - ld de, SCREEN_WIDTH * 2 - add hl, de - ld d, h - ld e, l - pop hl - pop bc - inc b - ld a, b - cp $4 - jr nz, .PrintPP -.PPDone - coord hl, 9, 3 - ld de, StatusScreenExpText - call PlaceString - ld a, [wLoadedMonLevel] - push af - cp MAX_LEVEL - jr z, .Level100 - inc a - ld [wLoadedMonLevel], a ; Increase temporarily if not 100 -.Level100 - coord hl, 14, 6 - ld [hl], $70 ; 1-tile "to" - inc hl - inc hl - call PrintLevel - pop af - ld [wLoadedMonLevel], a - ld de, wLoadedMonExp - coord hl, 12, 4 - lb bc, 3, 7 - call PrintNumber ; exp - call CalcExpToLevelUp - ld de, wLoadedMonExp - coord hl, 7, 6 - lb bc, 3, 7 - call PrintNumber ; exp needed to level up - coord hl, 9, 0 - call StatusScreen_ClearName - coord hl, 9, 1 - call StatusScreen_ClearName - ld a, [wMonHIndex] - ld [wd11e], a - call GetMonName - coord hl, 9, 1 - call PlaceString - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a - call Delay3 - call WaitForTextScrollButtonPress ; wait for button - pop af - ld [hTilesetType], a - ld hl, wd72c - res 1, [hl] - ld a, $77 - ld [rNR50], a - call GBPalWhiteOut - jp ClearScreen - -CalcExpToLevelUp: - ld a, [wLoadedMonLevel] - cp MAX_LEVEL - jr z, .atMaxLevel - inc a - ld d, a - callab CalcExperience - ld hl, wLoadedMonExp + 2 - ld a, [hExperience + 2] - sub [hl] - ld [hld], a - ld a, [hExperience + 1] - sbc [hl] - ld [hld], a - ld a, [hExperience] - sbc [hl] - ld [hld], a - ret -.atMaxLevel - ld hl, wLoadedMonExp - xor a - ld [hli], a - ld [hli], a - ld [hl], a - ret - -StatusScreenExpText: - db "EXP POINTS" - next "LEVEL UP@" - -StatusScreen_ClearName: - ld bc, 10 - ld a, " " - jp FillMemory - -StatusScreen_PrintPP: -; print PP or -- c times, going down two rows each time - ld [hli], a - ld [hld], a - add hl, de - dec c - jr nz, StatusScreen_PrintPP - ret diff --git a/engine/menu/swap_items.asm b/engine/menu/swap_items.asm deleted file mode 100644 index 826fe60b..00000000 --- a/engine/menu/swap_items.asm +++ /dev/null @@ -1,149 +0,0 @@ -HandleItemListSwapping:: - ld a, [wListMenuID] - cp ITEMLISTMENU - jp nz, DisplayListMenuIDLoop ; only rearrange item list menus - push hl - ld hl, wListPointer - ld a, [hli] - ld h, [hl] - ld l, a - inc hl ; hl = beginning of list entries - ld a, [wCurrentMenuItem] - ld b, a - ld a, [wListScrollOffset] - add b - add a - ld c, a - ld b, 0 - add hl, bc ; hl = address of currently selected item entry - ld a, [hl] - pop hl - inc a - jp z, DisplayListMenuIDLoop ; ignore attempts to swap the Cancel menu item - ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1) - and a ; has the first item to swap already been chosen? - jr nz, .swapItems -; if not, set the currently selected item as the first item - ld a, [wCurrentMenuItem] - inc a - ld b, a - ld a, [wListScrollOffset] ; index of top (visible) menu item within the list - add b - ld [wMenuItemToSwap], a ; ID of item chosen for swapping (counts from 1) - ld c, 20 - call DelayFrames - jp DisplayListMenuIDLoop -.swapItems - ld a, [wCurrentMenuItem] - inc a - ld b, a - ld a, [wListScrollOffset] - add b - ld b, a - ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1) - cp b ; is the currently selected item the same as the first item to swap? - jp z, DisplayListMenuIDLoop ; ignore attempts to swap an item with itself - dec a - ld [wMenuItemToSwap], a ; ID of item chosen for swapping (counts from 1) - ld c, 20 - call DelayFrames - push hl - push de - ld hl, wListPointer - ld a, [hli] - ld h, [hl] - ld l, a - inc hl ; hl = beginning of list entries - ld d, h - ld e, l ; de = beginning of list entries - ld a, [wCurrentMenuItem] - ld b, a - ld a, [wListScrollOffset] - add b - add a - ld c, a - ld b, 0 - add hl, bc ; hl = address of currently selected item entry - ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1) - add a - add e - ld e, a - jr nc, .noCarry - inc d -.noCarry ; de = address of first item to swap - ld a, [de] - ld b, a - ld a, [hli] - cp b - jr z, .swapSameItemType -.swapDifferentItems - ld [$ff95], a ; [$ff95] = second item ID - ld a, [hld] - ld [$ff96], a ; [$ff96] = second item quantity - ld a, [de] - ld [hli], a ; put first item ID in second item slot - inc de - ld a, [de] - ld [hl], a ; put first item quantity in second item slot - ld a, [$ff96] - ld [de], a ; put second item quantity in first item slot - dec de - ld a, [$ff95] - ld [de], a ; put second item ID in first item slot - xor a - ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped - pop de - pop hl - jp DisplayListMenuIDLoop -.swapSameItemType - inc de - ld a, [hl] - ld b, a - ld a, [de] - add b ; a = sum of both item quantities - cp 100 ; is the sum too big for one item slot? - jr c, .combineItemSlots -; swap enough items from the first slot to max out the second slot if they can't be combined - sub 99 - ld [de], a - ld a, 99 - ld [hl], a - jr .done -.combineItemSlots - ld [hl], a ; put the sum in the second item slot - ld hl, wListPointer - ld a, [hli] - ld h, [hl] - ld l, a - dec [hl] ; decrease the number of items - ld a, [hl] - ld [wListCount], a ; update number of items variable - cp 1 - jr nz, .skipSettingMaxMenuItemID - ld [wMaxMenuItem], a ; if the number of items is only one now, update the max menu item ID -.skipSettingMaxMenuItemID - dec de - ld h, d - ld l, e - inc hl - inc hl ; hl = address of item after first item to swap -.moveItemsUpLoop ; erase the first item slot and move up all the following item slots to fill the gap - ld a, [hli] - ld [de], a - inc de - inc a ; reached the $ff terminator? - jr z, .afterMovingItemsUp - ld a, [hli] - ld [de], a - inc de - jr .moveItemsUpLoop -.afterMovingItemsUp - xor a - ld [wListScrollOffset], a - ld [wCurrentMenuItem], a -.done - xor a - ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped - pop de - pop hl - jp DisplayListMenuIDLoop diff --git a/engine/menu/text_box.asm b/engine/menu/text_box.asm deleted file mode 100644 index 00045959..00000000 --- a/engine/menu/text_box.asm +++ /dev/null @@ -1,767 +0,0 @@ -; function to draw various text boxes -DisplayTextBoxID_:: - ld a, [wTextBoxID] - cp TWO_OPTION_MENU - jp z, DisplayTwoOptionMenu - ld c, a - ld hl, TextBoxFunctionTable - ld de, 3 - call SearchTextBoxTable - jr c, .functionTableMatch - ld hl, TextBoxCoordTable - ld de, 5 - call SearchTextBoxTable - jr c, .coordTableMatch - ld hl, TextBoxTextAndCoordTable - ld de, 9 - call SearchTextBoxTable - jr c, .textAndCoordTableMatch -.done - ret -.functionTableMatch - ld a, [hli] - ld h, [hl] - ld l, a ; hl = address of function - ld de, .done - push de - jp hl ; jump to the function -.coordTableMatch - call GetTextBoxIDCoords - call GetAddressOfScreenCoords - call TextBoxBorder - ret -.textAndCoordTableMatch - call GetTextBoxIDCoords - push hl - call GetAddressOfScreenCoords - call TextBoxBorder - pop hl - call GetTextBoxIDText - ld a, [wd730] - push af - ld a, [wd730] - set 6, a ; no pauses between printing each letter - ld [wd730], a - call PlaceString - pop af - ld [wd730], a - call UpdateSprites - ret - -; function to search a table terminated with $ff for a byte matching c in increments of de -; sets carry flag if a match is found and clears carry flag if not -SearchTextBoxTable: - dec de -.loop - ld a, [hli] - cp $ff - jr z, .notFound - cp c - jr z, .found - add hl, de - jr .loop -.found - scf -.notFound - ret - -; function to load coordinates from the TextBoxCoordTable or the TextBoxTextAndCoordTable -; INPUT: -; hl = address of coordinates -; OUTPUT: -; b = height -; c = width -; d = row of upper left corner -; e = column of upper left corner -GetTextBoxIDCoords: - ld a, [hli] ; column of upper left corner - ld e, a - ld a, [hli] ; row of upper left corner - ld d, a - ld a, [hli] ; column of lower right corner - sub e - dec a - ld c, a ; c = width - ld a, [hli] ; row of lower right corner - sub d - dec a - ld b, a ; b = height - ret - -; function to load a text address and text coordinates from the TextBoxTextAndCoordTable -GetTextBoxIDText: - ld a, [hli] - ld e, a - ld a, [hli] - ld d, a ; de = address of text - push de ; save text address - ld a, [hli] - ld e, a ; column of upper left corner of text - ld a, [hl] - ld d, a ; row of upper left corner of text - call GetAddressOfScreenCoords - pop de ; restore text address - ret - -; function to point hl to the screen coordinates -; INPUT: -; d = row -; e = column -; OUTPUT: -; hl = address of upper left corner of text box -GetAddressOfScreenCoords: - push bc - coord hl, 0, 0 - ld bc, 20 -.loop ; loop to add d rows to the base address - ld a, d - and a - jr z, .addedRows - add hl, bc - dec d - jr .loop -.addedRows - pop bc - add hl, de - ret - -; Format: -; 00: text box ID -; 01-02: function address -TextBoxFunctionTable: - dbw MONEY_BOX, DisplayMoneyBox - dbw BUY_SELL_QUIT_MENU, DoBuySellQuitMenu - dbw FIELD_MOVE_MON_MENU, DisplayFieldMoveMonMenu - db $ff ; terminator - -; Format: -; 00: text box ID -; 01: column of upper left corner -; 02: row of upper left corner -; 03: column of lower right corner -; 04: row of lower right corner -TextBoxCoordTable: - db MESSAGE_BOX, 0, 12, 19, 17 - db $03, 0, 0, 19, 14 - db $07, 0, 0, 11, 6 - db LIST_MENU_BOX, 4, 2, 19, 12 - db $10, 7, 0, 19, 17 - db MON_SPRITE_POPUP, 6, 4, 14, 13 - db $ff ; terminator - -; Format: -; 00: text box ID -; 01: column of upper left corner -; 02: row of upper left corner -; 03: column of lower right corner -; 04: row of lower right corner -; 05-06: address of text -; 07: column of beginning of text -; 08: row of beginning of text -; table of window positions and corresponding text [key, start column, start row, end column, end row, text pointer [2 bytes], text column, text row] -TextBoxTextAndCoordTable: - db JP_MOCHIMONO_MENU_TEMPLATE - db 0,0,14,17 ; text box coordinates - dw JapaneseMochimonoText - db 3,0 ; text coordinates - - db USE_TOSS_MENU_TEMPLATE - db 13,10,19,14 ; text box coordinates - dw UseTossText - db 15,11 ; text coordinates - - db JP_SAVE_MESSAGE_MENU_TEMPLATE - db 0,0,7,5 ; text box coordinates - dw JapaneseSaveMessageText - db 2,2 ; text coordinates - - db JP_SPEED_OPTIONS_MENU_TEMPLATE - db 0,6,5,10 ; text box coordinates - dw JapaneseSpeedOptionsText - db 2,7 ; text coordinates - - db BATTLE_MENU_TEMPLATE - db 8,12,19,17 ; text box coordinates - dw BattleMenuText - db 10,14 ; text coordinates - - db SAFARI_BATTLE_MENU_TEMPLATE - db 0,12,19,17 ; text box coordinates - dw SafariZoneBattleMenuText - db 2,14 ; text coordinates - - db SWITCH_STATS_CANCEL_MENU_TEMPLATE - db 11,11,19,17 ; text box coordinates - dw SwitchStatsCancelText - db 13,12 ; text coordinates - - db BUY_SELL_QUIT_MENU_TEMPLATE - db 0,0,10,6 ; text box coordinates - dw BuySellQuitText - db 2,1 ; text coordinates - - db MONEY_BOX_TEMPLATE - db 11,0,19,2 ; text box coordinates - dw MoneyText - db 13,0 ; text coordinates - - db JP_AH_MENU_TEMPLATE - db 7,6,11,10 ; text box coordinates - dw JapaneseAhText - db 8,8 ; text coordinates - - db JP_POKEDEX_MENU_TEMPLATE - db 11,8,19,17 ; text box coordinates - dw JapanesePokedexMenu - db 12,10 ; text coordinates - -; note that there is no terminator - -BuySellQuitText: - db "BUY" - next "SELL" - next "QUIT@@" - -UseTossText: - db "USE" - next "TOSS@" - -JapaneseSaveMessageText: - db "きろく" - next "メッセージ@" - -JapaneseSpeedOptionsText: - db "はやい" - next "おそい@" - -MoneyText: - db "MONEY@" - -JapaneseMochimonoText: - db "もちもの@" - -JapaneseMainMenuText: - db "つづきから" - next "さいしょから@" - -BattleMenuText: - db "FIGHT ",$E1,$E2 - next "ITEM RUN@" - -SafariZoneBattleMenuText: - db "BALL× BAIT" - next "THROW ROCK RUN@" - -SwitchStatsCancelText: - db "SWITCH" - next "STATS" - next "CANCEL@" - -JapaneseAhText: - db "アッ!@" - -JapanesePokedexMenu: - db "データをみる" - next "なきごえ" - next "ぶんぷをみる" - next "キャンセル@" - -DisplayMoneyBox: - ld hl, wd730 - set 6, [hl] - ld a, MONEY_BOX_TEMPLATE - ld [wTextBoxID], a - call DisplayTextBoxID - coord hl, 13, 1 - ld b, 1 - ld c, 6 - call ClearScreenArea - coord hl, 12, 1 - ld de, wPlayerMoney - ld c, $a3 - call PrintBCDNumber - ld hl, wd730 - res 6, [hl] - ret - -CurrencyString: - db " ¥@" - -DoBuySellQuitMenu: - ld a, [wd730] - set 6, a ; no printing delay - ld [wd730], a - xor a - ld [wChosenMenuItem], a - ld a, BUY_SELL_QUIT_MENU_TEMPLATE - ld [wTextBoxID], a - call DisplayTextBoxID - ld a, A_BUTTON | B_BUTTON - ld [wMenuWatchedKeys], a - ld a, $2 - ld [wMaxMenuItem], a - ld a, $1 - ld [wTopMenuItemY], a - ld a, $1 - ld [wTopMenuItemX], a - xor a - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - ld [wMenuWatchMovingOutOfBounds], a - ld a, [wd730] - res 6, a ; turn on the printing delay - ld [wd730], a - call HandleMenuInput - call PlaceUnfilledArrowMenuCursor - bit 0, a ; was A pressed? - jr nz, .pressedA - bit 1, a ; was B pressed? (always true since only A/B are watched) - jr z, .pressedA - ld a, CANCELLED_MENU - ld [wMenuExitMethod], a - jr .quit -.pressedA - ld a, CHOSE_MENU_ITEM - ld [wMenuExitMethod], a - ld a, [wCurrentMenuItem] - ld [wChosenMenuItem], a - ld b, a - ld a, [wMaxMenuItem] - cp b - jr z, .quit - ret -.quit - ld a, CANCELLED_MENU - ld [wMenuExitMethod], a - ld a, [wCurrentMenuItem] - ld [wChosenMenuItem], a - scf - ret - -; displays a menu with two options to choose from -; b = Y of upper left corner of text region -; c = X of upper left corner of text region -; hl = address where the text box border should be drawn -DisplayTwoOptionMenu: - push hl - ld a, [wd730] - set 6, a ; no printing delay - ld [wd730], a - -; pointless because both values are overwritten before they are read - xor a - ld [wChosenMenuItem], a - ld [wMenuExitMethod], a - - ld a, A_BUTTON | B_BUTTON - ld [wMenuWatchedKeys], a - ld a, $1 - ld [wMaxMenuItem], a - ld a, b - ld [wTopMenuItemY], a - ld a, c - ld [wTopMenuItemX], a - xor a - ld [wLastMenuItem], a - ld [wMenuWatchMovingOutOfBounds], a - push hl - ld hl, wTwoOptionMenuID - bit 7, [hl] ; select second menu item by default? - res 7, [hl] - jr z, .storeCurrentMenuItem - inc a -.storeCurrentMenuItem - ld [wCurrentMenuItem], a - pop hl - push hl - push hl - call TwoOptionMenu_SaveScreenTiles - ld a, [wTwoOptionMenuID] - ld hl, TwoOptionMenuStrings - ld e, a - ld d, $0 - ld a, $5 -.menuStringLoop - add hl, de - dec a - jr nz, .menuStringLoop - ld a, [hli] - ld c, a - ld a, [hli] - ld b, a - ld e, l - ld d, h - pop hl - push de - ld a, [wTwoOptionMenuID] - cp TRADE_CANCEL_MENU - jr nz, .notTradeCancelMenu - call CableClub_TextBoxBorder - jr .afterTextBoxBorder -.notTradeCancelMenu - call TextBoxBorder -.afterTextBoxBorder - call UpdateSprites - pop hl - ld a, [hli] - and a ; put blank line before first menu item? - ld bc, 20 + 2 - jr z, .noBlankLine - ld bc, 2 * 20 + 2 -.noBlankLine - ld a, [hli] - ld e, a - ld a, [hli] - ld d, a - 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 - call HandleMenuInput - pop hl - bit 1, a ; A button pressed? - jr nz, .choseSecondMenuItem ; automatically choose the second option if B is pressed -.pressedAButton - ld a, [wCurrentMenuItem] - ld [wChosenMenuItem], a - and a - jr nz, .choseSecondMenuItem -; chose first menu item - ld a, CHOSE_FIRST_ITEM - ld [wMenuExitMethod], a - ld c, 15 - call DelayFrames - call TwoOptionMenu_RestoreScreenTiles - and a - ret -.choseSecondMenuItem - ld a, 1 - ld [wCurrentMenuItem], a - ld [wChosenMenuItem], a - ld a, CHOSE_SECOND_ITEM - ld [wMenuExitMethod], a - ld c, 15 - call DelayFrames - call TwoOptionMenu_RestoreScreenTiles - scf - ret - -; Some of the wider/taller two option menus will not have the screen areas -; they cover be fully saved/restored by the two functions below. -; The bottom and right edges of the menu may remain after the function returns. - -TwoOptionMenu_SaveScreenTiles: - ld de, wBuffer - lb bc, 5, 6 -.loop - ld a, [hli] - ld [de], a - inc de - dec c - jr nz, .loop - push bc - ld bc, SCREEN_WIDTH - 6 - add hl, bc - pop bc - ld c, $6 - dec b - jr nz, .loop - ret - -TwoOptionMenu_RestoreScreenTiles: - ld de, wBuffer - lb bc, 5, 6 -.loop - ld a, [de] - inc de - ld [hli], a - dec c - jr nz, .loop - push bc - ld bc, SCREEN_WIDTH - 6 - add hl, bc - pop bc - ld c, 6 - dec b - jr nz, .loop - call UpdateSprites - ret - -; Format: -; 00: byte width -; 01: byte height -; 02: byte put blank line before first menu item -; 03: word text pointer -TwoOptionMenuStrings: - db 4,3,0 - dw .YesNoMenu - db 6,3,0 - dw .NorthWestMenu - db 6,3,0 - dw .SouthEastMenu - db 6,3,0 - dw .YesNoMenu - db 6,3,0 - dw .NorthEastMenu - db 7,3,0 - dw .TradeCancelMenu - db 7,4,1 - dw .HealCancelMenu - db 4,3,0 - dw .NoYesMenu - -.NoYesMenu - db "NO" - next "YES@" -.YesNoMenu - db "YES" - next "NO@" -.NorthWestMenu - db "NORTH" - next "WEST@" -.SouthEastMenu - db "SOUTH" - next "EAST@" -.NorthEastMenu - db "NORTH" - next "EAST@" -.TradeCancelMenu - db "TRADE" - next "CANCEL@" -.HealCancelMenu - db "HEAL" - next "CANCEL@" - -DisplayFieldMoveMonMenu: - xor a - ld hl, wFieldMoves - ld [hli], a ; wFieldMoves - ld [hli], a ; wFieldMoves + 1 - ld [hli], a ; wFieldMoves + 2 - ld [hli], a ; wFieldMoves + 3 - ld [hli], a ; wNumFieldMoves - ld [hl], 12 ; wFieldMovesLeftmostXCoord - call GetMonFieldMoves - ld a, [wNumFieldMoves] - and a - jr nz, .fieldMovesExist - -; no field moves - coord hl, 11, 11 - ld b, 5 - ld c, 7 - call TextBoxBorder - call UpdateSprites - ld a, 12 - ld [hFieldMoveMonMenuTopMenuItemX], a - coord hl, 13, 12 - ld de, PokemonMenuEntries - jp PlaceString - -.fieldMovesExist - push af - -; Calculate the text box position and dimensions based on the leftmost X coord -; of the field move names before adjusting for the number of field moves. - coord hl, 0, 11 - ld a, [wFieldMovesLeftmostXCoord] - dec a - ld e, a - ld d, 0 - add hl, de - ld b, 5 - ld a, 18 - sub e - ld c, a - pop af - -; For each field move, move the top of the text box up 2 rows while the leaving -; the bottom of the text box at the bottom of the screen. - ld de, -SCREEN_WIDTH * 2 -.textBoxHeightLoop - add hl, de - inc b - inc b - dec a - jr nz, .textBoxHeightLoop - -; Make space for an extra blank row above the top field move. - ld de, -SCREEN_WIDTH - add hl, de - inc b - - call TextBoxBorder - call UpdateSprites - -; Calculate the position of the first field move name to print. - coord hl, 0, 12 - ld a, [wFieldMovesLeftmostXCoord] - inc a - ld e, a - ld d, 0 - add hl, de - ld de, -SCREEN_WIDTH * 2 - ld a, [wNumFieldMoves] -.calcFirstFieldMoveYLoop - add hl, de - dec a - jr nz, .calcFirstFieldMoveYLoop - - xor a - ld [wNumFieldMoves], a - ld de, wFieldMoves -.printNamesLoop - push hl - ld hl, FieldMoveNames - ld a, [de] - and a - jr z, .donePrintingNames - inc de - ld b, a ; index of name -.skipNamesLoop ; skip past names before the name we want - dec b - jr z, .reachedName -.skipNameLoop ; skip past current name - ld a, [hli] - cp "@" - jr nz, .skipNameLoop - jr .skipNamesLoop -.reachedName - ld b, h - ld c, l - pop hl - push de - ld d, b - ld e, c - call PlaceString - ld bc, SCREEN_WIDTH * 2 - add hl, bc - pop de - jr .printNamesLoop - -.donePrintingNames - pop hl - ld a, [wFieldMovesLeftmostXCoord] - ld [hFieldMoveMonMenuTopMenuItemX], a - coord hl, 0, 12 - ld a, [wFieldMovesLeftmostXCoord] - inc a - ld e, a - ld d, 0 - add hl, de - ld de, PokemonMenuEntries - jp PlaceString - -FieldMoveNames: - db "CUT@" - db "FLY@" - db "@" - db "SURF@" - db "STRENGTH@" - db "FLASH@" - db "DIG@" - db "TELEPORT@" - db "SOFTBOILED@" - -PokemonMenuEntries: - db "STATS" - next "SWITCH" - next "CANCEL@" - -GetMonFieldMoves: - ld a, [wWhichPokemon] - ld hl, wPartyMon1Moves - ld bc, wPartyMon2 - wPartyMon1 - call AddNTimes - ld d, h - ld e, l - ld c, NUM_MOVES + 1 - ld hl, wFieldMoves -.loop - push hl -.nextMove - dec c - jr z, .done - ld a, [de] ; move ID - and a - jr z, .done - ld b, a - inc de - ld hl, FieldMoveDisplayData -.fieldMoveLoop - ld a, [hli] - cp $ff - jr z, .nextMove ; if the move is not a field move - cp b - jr z, .foundFieldMove - inc hl - inc hl - jr .fieldMoveLoop -.foundFieldMove - ld a, b - ld [wLastFieldMoveID], a - ld a, [hli] ; field move name index - ld b, [hl] ; field move leftmost X coordinate - pop hl - ld [hli], a ; store name index in wFieldMoves - ld a, [wNumFieldMoves] - inc a - ld [wNumFieldMoves], a - ld a, [wFieldMovesLeftmostXCoord] - cp b - jr c, .skipUpdatingLeftmostXCoord - ld a, b - ld [wFieldMovesLeftmostXCoord], a -.skipUpdatingLeftmostXCoord - ld a, [wLastFieldMoveID] - ld b, a - jr .loop -.done - pop hl - ret - -; Format: [Move id], [name index], [leftmost tile] -; Move id = id of move -; Name index = index of name in FieldMoveNames -; Leftmost tile = -1 + tile column in which the first letter of the move's name should be displayed -; "SOFTBOILED" is $08 because it has 4 more letters than "SURF", for example, whose value is $0C -FieldMoveDisplayData: - db CUT, $01, $0C - db FLY, $02, $0C - db $B4, $03, $0C ; unused field move - db SURF, $04, $0C - db STRENGTH, $05, $0A - db FLASH, $06, $0C - db DIG, $07, $0C - db TELEPORT, $08, $0A - db SOFTBOILED, $09, $08 - db $ff ; list terminator diff --git a/engine/menu/vending_machine.asm b/engine/menu/vending_machine.asm deleted file mode 100755 index 554c5d4f..00000000 --- a/engine/menu/vending_machine.asm +++ /dev/null @@ -1,133 +0,0 @@ -VendingMachineMenu:: - ld hl, VendingMachineText1 - call PrintText - ld a, MONEY_BOX - ld [wTextBoxID], a - call DisplayTextBoxID - xor a - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - ld a, A_BUTTON | B_BUTTON - ld [wMenuWatchedKeys], a - ld a, 3 - ld [wMaxMenuItem], a - ld a, 5 - ld [wTopMenuItemY], a - ld a, 1 - ld [wTopMenuItemX], a - ld hl, wd730 - set 6, [hl] - coord hl, 0, 3 - ld b, 8 - ld c, 12 - call TextBoxBorder - call UpdateSprites - coord hl, 2, 5 - ld de, DrinkText - call PlaceString - coord hl, 9, 6 - ld de, DrinkPriceText - call PlaceString - ld hl, wd730 - res 6, [hl] - call HandleMenuInput - bit 1, a ; pressed B? - jr nz, .notThirsty - ld a, [wCurrentMenuItem] - cp 3 ; chose Cancel? - jr z, .notThirsty - xor a - ld [hMoney], a - ld [hMoney + 2], a - ld a, $2 - ld [hMoney + 1], a - call HasEnoughMoney - jr nc, .enoughMoney - ld hl, VendingMachineText4 - jp PrintText -.enoughMoney - call LoadVendingMachineItem - ld a, [hVendingMachineItem] - ld b, a - ld c, 1 - call GiveItem - jr nc, .BagFull - - ld b, 60 ; number of times to play the "brrrrr" sound -.playDeliverySound - ld c, 2 - call DelayFrames - push bc - ld a, SFX_PUSH_BOULDER - call PlaySound - pop bc - dec b - jr nz, .playDeliverySound - - ld hl, VendingMachineText5 - call PrintText - ld hl, hVendingMachinePrice + 2 - ld de, wPlayerMoney + 2 - ld c, $3 - predef SubBCDPredef - ld a, MONEY_BOX - ld [wTextBoxID], a - jp DisplayTextBoxID -.BagFull - ld hl, VendingMachineText6 - jp PrintText -.notThirsty - ld hl, VendingMachineText7 - jp PrintText - -VendingMachineText1: - TX_FAR _VendingMachineText1 - db "@" - -DrinkText: - db "FRESH WATER" - next "SODA POP" - next "LEMONADE" - next "CANCEL@" - -DrinkPriceText: - db "¥200" - next "¥300" - next "¥350" - next "@" - -VendingMachineText4: - TX_FAR _VendingMachineText4 - db "@" - -VendingMachineText5: - TX_FAR _VendingMachineText5 - db "@" - -VendingMachineText6: - TX_FAR _VendingMachineText6 - db "@" - -VendingMachineText7: - TX_FAR _VendingMachineText7 - db "@" - -LoadVendingMachineItem: - ld hl, VendingPrices - ld a, [wCurrentMenuItem] - add a - add a - ld d, 0 - ld e, a - add hl, de - ld a, [hli] - ld [hVendingMachineItem], a - ld a, [hli] - ld [hVendingMachinePrice], a - ld a, [hli] - ld [hVendingMachinePrice + 1], a - ld a, [hl] - ld [hVendingMachinePrice + 2], a - ret - -INCLUDE "data/vending_prices.asm" diff --git a/engine/menus/display_text_id_init.asm b/engine/menus/display_text_id_init.asm new file mode 100644 index 00000000..5043ad22 --- /dev/null +++ b/engine/menus/display_text_id_init.asm @@ -0,0 +1,78 @@ +; function that performs initialization for DisplayTextID +DisplayTextIDInit:: + xor a + ld [wListMenuID], a + ld a, [wAutoTextBoxDrawingControl] + bit 0, a + jr nz, .skipDrawingTextBoxBorder + ld a, [hSpriteIndexOrTextID] ; text ID (or sprite ID) + and a + jr nz, .notStartMenu +; if text ID is 0 (i.e. the start menu) +; Note that the start menu text border is also drawn in the function directly +; below this, so this seems unnecessary. + CheckEvent EVENT_GOT_POKEDEX +; start menu with pokedex + coord hl, 10, 0 + ld b, $0e + ld c, $08 + jr nz, .drawTextBoxBorder +; start menu without pokedex + coord hl, 10, 0 + ld b, $0c + ld c, $08 + jr .drawTextBoxBorder +; if text ID is not 0 (i.e. not the start menu) then do a standard dialogue text box +.notStartMenu + coord hl, 0, 12 + ld b, $04 + ld c, $12 +.drawTextBoxBorder + call TextBoxBorder +.skipDrawingTextBoxBorder + ld hl, wFontLoaded + set 0, [hl] + ld hl, wFlags_0xcd60 + bit 4, [hl] + res 4, [hl] + jr nz, .skipMovingSprites + call UpdateSprites +.skipMovingSprites +; loop to copy C1X9 (direction the sprite is facing) to C2X9 for each sprite +; this is done because when you talk to an NPC, they turn to look your way +; the original direction they were facing must be restored after the dialogue is over + ld hl, wSpriteStateData1 + $19 + ld c, $0f + ld de, $0010 +.spriteFacingDirectionCopyLoop + ld a, [hl] + inc h + ld [hl], a + dec h + add hl, de + dec c + jr nz, .spriteFacingDirectionCopyLoop +; loop to force all the sprites in the middle of animation to stand still +; (so that they don't like they're frozen mid-step during the dialogue) + ld hl, wSpriteStateData1 + 2 + ld de, $0010 + ld c, e +.spriteStandStillLoop + ld a, [hl] + cp $ff ; is the sprite visible? + jr z, .nextSprite +; if it is visible + and $fc + ld [hl], a +.nextSprite + add hl, de + dec c + jr nz, .spriteStandStillLoop + ld b, $9c ; window background address + call CopyScreenTileBufferToVRAM ; transfer background in WRAM to VRAM + xor a + ld [hWY], a ; put the window on the screen + call LoadFontTilePatterns + ld a, $01 + ld [H_AUTOBGTRANSFERENABLED], a ; enable continuous WRAM to VRAM transfer each V-blank + ret diff --git a/engine/menus/draw_badges.asm b/engine/menus/draw_badges.asm new file mode 100644 index 00000000..1888e32f --- /dev/null +++ b/engine/menus/draw_badges.asm @@ -0,0 +1,120 @@ +DrawBadges: +; Draw 4x2 gym leader faces, with the faces replaced by +; badges if they are owned. Used in the player status screen. + +; In Japanese versions, names are displayed above faces. +; Instead of removing relevant code, the name graphics were erased. + +; Tile ids for face/badge graphics. + ld de, wBadgeOrFaceTiles + ld hl, .FaceBadgeTiles + ld bc, 8 + call CopyData + +; Booleans for each badge. + ld hl, wTempObtainedBadgesBooleans + ld bc, 8 + xor a + call FillMemory + +; Alter these based on owned badges. + ld de, wTempObtainedBadgesBooleans + ld hl, wBadgeOrFaceTiles + ld a, [wObtainedBadges] + ld b, a + ld c, 8 +.CheckBadge + srl b + jr nc, .NextBadge + ld a, [hl] + add 4 ; Badge graphics are after each face + ld [hl], a + ld a, 1 + ld [de], a +.NextBadge + inc hl + inc de + dec c + jr nz, .CheckBadge + +; Draw two rows of badges. + ld hl, wBadgeNumberTile + ld a, $d8 ; [1] + ld [hli], a + ld [hl], $60 ; First name + + coord hl, 2, 11 + ld de, wTempObtainedBadgesBooleans + call .DrawBadgeRow + + coord hl, 2, 14 + ld de, wTempObtainedBadgesBooleans + 4 +; call .DrawBadgeRow +; ret + +.DrawBadgeRow +; Draw 4 badges. + + ld c, 4 +.DrawBadge + push de + push hl + +; Badge no. + ld a, [wBadgeNumberTile] + ld [hli], a + inc a + ld [wBadgeNumberTile], a + +; Names aren't printed if the badge is owned. + ld a, [de] + and a + ld a, [wBadgeNameTile] + jr nz, .SkipName + call .PlaceTiles + jr .PlaceBadge + +.SkipName + inc a + inc a + inc hl + +.PlaceBadge + ld [wBadgeNameTile], a + ld de, SCREEN_WIDTH - 1 + add hl, de + ld a, [wBadgeOrFaceTiles] + call .PlaceTiles + add hl, de + call .PlaceTiles + +; Shift badge array back one byte. + push bc + ld hl, wBadgeOrFaceTiles + 1 + ld de, wBadgeOrFaceTiles + ld bc, 8 + call CopyData + pop bc + + pop hl + ld de, 4 + add hl, de + + pop de + inc de + dec c + jr nz, .DrawBadge + ret + +.PlaceTiles + ld [hli], a + inc a + ld [hl], a + inc a + ret + +.FaceBadgeTiles + db $20, $28, $30, $38, $40, $48, $50, $58 + +GymLeaderFaceAndBadgeTileGraphics: + INCBIN "gfx/trainer_card/badges.2bpp" diff --git a/engine/menus/draw_start_menu.asm b/engine/menus/draw_start_menu.asm new file mode 100644 index 00000000..21e444e9 --- /dev/null +++ b/engine/menus/draw_start_menu.asm @@ -0,0 +1,89 @@ +; function that displays the start menu +DrawStartMenu:: + CheckEvent EVENT_GOT_POKEDEX +; menu with pokedex + coord hl, 10, 0 + ld b, $0e + ld c, $08 + jr nz, .drawTextBoxBorder +; shorter menu if the player doesn't have the pokedex + coord hl, 10, 0 + ld b, $0c + ld c, $08 +.drawTextBoxBorder + call TextBoxBorder + ld a, D_DOWN | D_UP | START | B_BUTTON | A_BUTTON + ld [wMenuWatchedKeys], a + ld a, $02 + ld [wTopMenuItemY], a ; Y position of first menu choice + ld a, $0b + ld [wTopMenuItemX], a ; X position of first menu choice + ld a, [wBattleAndStartSavedMenuItem] ; remembered menu selection from last time + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + xor a + ld [wMenuWatchMovingOutOfBounds], a + ld hl, wd730 + set 6, [hl] ; no pauses between printing each letter + coord hl, 12, 2 + CheckEvent EVENT_GOT_POKEDEX +; case for not having pokedex + ld a, $06 + jr z, .storeMenuItemCount +; case for having pokedex + ld de, StartMenuPokedexText + call PrintStartMenuItem + ld a, $07 +.storeMenuItemCount + ld [wMaxMenuItem], a ; number of menu items + ld de, StartMenuPokemonText + call PrintStartMenuItem + ld de, StartMenuItemText + call PrintStartMenuItem + ld de, wPlayerName ; player's name + call PrintStartMenuItem + ld a, [wd72e] + bit 6, a ; is the player using the link feature? +; case for not using link feature + ld de, StartMenuSaveText + jr z, .printSaveOrResetText +; case for using link feature + ld de, StartMenuResetText +.printSaveOrResetText + call PrintStartMenuItem + ld de, StartMenuOptionText + call PrintStartMenuItem + ld de, StartMenuExitText + call PlaceString + ld hl, wd730 + res 6, [hl] ; turn pauses between printing letters back on + ret + +StartMenuPokedexText: + db "POKéDEX@" + +StartMenuPokemonText: + db "POKéMON@" + +StartMenuItemText: + db "ITEM@" + +StartMenuSaveText: + db "SAVE@" + +StartMenuResetText: + db "RESET@" + +StartMenuExitText: + db "EXIT@" + +StartMenuOptionText: + db "OPTION@" + +PrintStartMenuItem: + push hl + call PlaceString + pop hl + ld de, SCREEN_WIDTH * 2 + add hl, de + ret diff --git a/engine/menus/league_pc.asm b/engine/menus/league_pc.asm new file mode 100755 index 00000000..170c0ef3 --- /dev/null +++ b/engine/menus/league_pc.asm @@ -0,0 +1,120 @@ +PKMNLeaguePC: + ld hl, AccessedHoFPCText + call PrintText + ld hl, wd730 + set 6, [hl] + push hl + ld a, [wUpdateSpritesEnabled] + push af + ld a, [hTilesetType] + push af + xor a + ld [hTilesetType], a + ld [wSpriteFlipped], a + ld [wUpdateSpritesEnabled], a + ld [wHoFTeamIndex2], a + ld [wHoFTeamNo], a + ld a, [wNumHoFTeams] + ld b, a + cp HOF_TEAM_CAPACITY + 1 + jr c, .loop +; If the total number of hall of fame teams is greater than the storage +; capacity, then calculate the number of the first team that is still recorded. + ld b, HOF_TEAM_CAPACITY + sub b + ld [wHoFTeamNo], a +.loop + ld hl, wHoFTeamNo + inc [hl] + push bc + ld a, [wHoFTeamIndex2] + ld [wHoFTeamIndex], a + callba LoadHallOfFameTeams + call LeaguePCShowTeam + pop bc + jr c, .doneShowingTeams + ld hl, wHoFTeamIndex2 + inc [hl] + ld a, [hl] + cp b + jr nz, .loop +.doneShowingTeams + pop af + ld [hTilesetType], a + pop af + ld [wUpdateSpritesEnabled], a + pop hl + res 6, [hl] + call GBPalWhiteOutWithDelay3 + call ClearScreen + call RunDefaultPaletteCommand + jp GBPalNormal + +LeaguePCShowTeam: + ld c, PARTY_LENGTH +.loop + push bc + call LeaguePCShowMon + call WaitForTextScrollButtonPress + ld a, [hJoyHeld] + bit 1, a + jr nz, .exit + ld hl, wHallOfFame + HOF_MON + ld de, wHallOfFame + ld bc, HOF_TEAM - HOF_MON + call CopyData + pop bc + ld a, [wHallOfFame + 0] + cp $ff + jr z, .done + dec c + jr nz, .loop +.done + and a + ret +.exit + pop bc + scf + ret + +LeaguePCShowMon: + call GBPalWhiteOutWithDelay3 + call ClearScreen + ld hl, wHallOfFame + ld a, [hli] + ld [wHoFMonSpecies], a + ld [wcf91], a + ld [wd0b5], a + ld [wBattleMonSpecies2], a + ld [wWholeScreenPaletteMonSpecies], a + ld a, [hli] + ld [wHoFMonLevel], a + ld de, wcd6d + ld bc, NAME_LENGTH + call CopyData + ld b, SET_PAL_POKEMON_WHOLE_SCREEN + ld c, 0 + call RunPaletteCommand + coord hl, 12, 5 + call GetMonHeader + call LoadFrontSpriteByMonIndex + call GBPalNormal + coord hl, 0, 13 + ld b, 2 + ld c, $12 + call TextBoxBorder + coord hl, 1, 15 + ld de, HallOfFameNoText + call PlaceString + coord hl, 16, 15 + ld de, wHoFTeamNo + lb bc, 1, 3 + call PrintNumber + jpba HoFDisplayMonInfo + +HallOfFameNoText: + db "HALL OF FAME No @" + +AccessedHoFPCText: + TX_FAR _AccessedHoFPCText + db "@" diff --git a/engine/menus/main_menu.asm b/engine/menus/main_menu.asm new file mode 100755 index 00000000..8eda6744 --- /dev/null +++ b/engine/menus/main_menu.asm @@ -0,0 +1,712 @@ +MainMenu: +; Check save file + call InitOptions + xor a + ld [wOptionsInitialized], a + inc a + ld [wSaveFileStatus], a + call CheckForPlayerNameInSRAM + jr nc, .mainMenuLoop + + predef LoadSAV + +.mainMenuLoop + ld c, 20 + call DelayFrames + xor a ; LINK_STATE_NONE + ld [wLinkState], a + ld hl, wPartyAndBillsPCSavedMenuItem + ld [hli], a + ld [hli], a + ld [hli], a + ld [hl], a + ld [wDefaultMap], a + ld hl, wd72e + res 6, [hl] + call ClearScreen + call RunDefaultPaletteCommand + call LoadTextBoxTilePatterns + call LoadFontTilePatterns + ld hl, wd730 + set 6, [hl] + ld a, [wSaveFileStatus] + cp 1 + jr z, .noSaveFile +; there's a save file + coord hl, 0, 0 + ld b, 6 + ld c, 13 + call TextBoxBorder + coord hl, 2, 2 + ld de, ContinueText + call PlaceString + jr .next2 +.noSaveFile + coord hl, 0, 0 + ld b, 4 + ld c, 13 + call TextBoxBorder + coord hl, 2, 2 + ld de, NewGameText + call PlaceString +.next2 + ld hl, wd730 + res 6, [hl] + call UpdateSprites + xor a + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + ld [wMenuJoypadPollCount], a + inc a + ld [wTopMenuItemX], a + inc a + ld [wTopMenuItemY], a + ld a, A_BUTTON | B_BUTTON | START + ld [wMenuWatchedKeys], a + ld a, [wSaveFileStatus] + ld [wMaxMenuItem], a + call HandleMenuInput + bit 1, a ; pressed B? + jp nz, DisplayTitleScreen ; if so, go back to the title screen + ld c, 20 + call DelayFrames + ld a, [wCurrentMenuItem] + ld b, a + ld a, [wSaveFileStatus] + cp 2 + jp z, .skipInc +; If there's no save file, increment the current menu item so that the numbers +; are the same whether or not there's a save file. + inc b +.skipInc + ld a, b + and a + jr z, .choseContinue + cp 1 + jp z, StartNewGame + call DisplayOptionMenu + ld a, 1 + ld [wOptionsInitialized], a + jp .mainMenuLoop +.choseContinue + call DisplayContinueGameInfo + ld hl, wCurrentMapScriptFlags + set 5, [hl] +.inputLoop + xor a + ld [hJoyPressed], a + ld [hJoyReleased], a + ld [hJoyHeld], a + call Joypad + ld a, [hJoyHeld] + bit 0, a + jr nz, .pressedA + bit 1, a + jp nz, .mainMenuLoop ; pressed B + jr .inputLoop +.pressedA + call GBPalWhiteOutWithDelay3 + call ClearScreen + ld a, PLAYER_DIR_DOWN + ld [wPlayerDirection], a + ld c, 10 + call DelayFrames + ld a, [wNumHoFTeams] + and a + jp z, SpecialEnterMap + ld a, [wCurMap] ; map ID + cp HALL_OF_FAME + jp nz, SpecialEnterMap + xor a + ld [wDestinationMap], a + ld hl, wd732 + set 2, [hl] ; fly warp or dungeon warp + call SpecialWarpIn + jp SpecialEnterMap + +InitOptions: + ld a, 1 ; no delay + ld [wLetterPrintingDelayFlags], a + ld a, 3 ; medium speed + ld [wOptions], a + ret + +LinkMenu: + xor a + ld [wLetterPrintingDelayFlags], a + ld hl, wd72e + set 6, [hl] + ld hl, TextTerminator_6b20 + call PrintText + call SaveScreenTilesToBuffer1 + ld hl, WhereWouldYouLikeText + call PrintText + coord hl, 5, 5 + ld b, $6 + ld c, $d + call TextBoxBorder + call UpdateSprites + coord hl, 7, 7 + ld de, CableClubOptionsText + call PlaceString + xor a + ld [wUnusedCD37], a + ld [wd72d], a + ld hl, wTopMenuItemY + ld a, $7 + ld [hli], a + ld a, $6 + ld [hli], a + xor a + ld [hli], a + inc hl + ld a, $2 + ld [hli], a + inc a + ; ld a, A_BUTTON | B_BUTTON + ld [hli], a ; wMenuWatchedKeys + xor a + ld [hl], a +.waitForInputLoop + call HandleMenuInput + and A_BUTTON | B_BUTTON + add a + add a + ld b, a + ld a, [wCurrentMenuItem] + add b + add $d0 + ld [wLinkMenuSelectionSendBuffer], a + ld [wLinkMenuSelectionSendBuffer + 1], a +.exchangeMenuSelectionLoop + call Serial_ExchangeLinkMenuSelection + ld a, [wLinkMenuSelectionReceiveBuffer] + ld b, a + and $f0 + cp $d0 + jr z, .asm_5c7d + ld a, [wLinkMenuSelectionReceiveBuffer + 1] + ld b, a + and $f0 + cp $d0 + jr nz, .exchangeMenuSelectionLoop +.asm_5c7d + ld a, b + and $c ; did the enemy press A or B? + jr nz, .enemyPressedAOrB +; the enemy didn't press A or B + ld a, [wLinkMenuSelectionSendBuffer] + and $c ; did the player press A or B? + jr z, .waitForInputLoop ; if neither the player nor the enemy pressed A or B, try again + jr .doneChoosingMenuSelection ; if the player pressed A or B but the enemy didn't, use the player's selection +.enemyPressedAOrB + ld a, [wLinkMenuSelectionSendBuffer] + and $c ; did the player press A or B? + jr z, .useEnemyMenuSelection ; if the enemy pressed A or B but the player didn't, use the enemy's selection +; the enemy and the player both pressed A or B +; The gameboy that is clocking the connection wins. + ld a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + jr z, .doneChoosingMenuSelection +.useEnemyMenuSelection + ld a, b + ld [wLinkMenuSelectionSendBuffer], a + and $3 + ld [wCurrentMenuItem], a +.doneChoosingMenuSelection + ld a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + jr nz, .skipStartingTransfer + call DelayFrame + call DelayFrame + ld a, START_TRANSFER_INTERNAL_CLOCK + ld [rSC], a +.skipStartingTransfer + ld b, $7f + ld c, $7f + ld d, $ec + ld a, [wLinkMenuSelectionSendBuffer] + and (B_BUTTON << 2) ; was B button pressed? + jr nz, .updateCursorPosition +; A button was pressed + ld a, [wCurrentMenuItem] + cp $2 + jr z, .updateCursorPosition + ld c, d + ld d, b + dec a + jr z, .updateCursorPosition + ld b, c + ld c, d +.updateCursorPosition + ld a, b + Coorda 6, 7 + ld a, c + Coorda 6, 9 + ld a, d + Coorda 6, 11 + ld c, 40 + call DelayFrames + call LoadScreenTilesFromBuffer1 + ld a, [wLinkMenuSelectionSendBuffer] + and (B_BUTTON << 2) ; was B button pressed? + jr nz, .choseCancel ; cancel if B pressed + ld a, [wCurrentMenuItem] + cp $2 + jr z, .choseCancel + xor a + ld [wWalkBikeSurfState], a ; start walking + ld a, [wCurrentMenuItem] + and a + ld a, COLOSSEUM + jr nz, .next + ld a, TRADE_CENTER +.next + ld [wd72d], a + ld hl, PleaseWaitText + call PrintText + ld c, 50 + call DelayFrames + ld hl, wd732 + res 1, [hl] + ld a, [wDefaultMap] + ld [wDestinationMap], a + call SpecialWarpIn + ld c, 20 + call DelayFrames + xor a + ld [wMenuJoypadPollCount], a + ld [wSerialExchangeNybbleSendData], a + inc a ; LINK_STATE_IN_CABLE_CLUB + ld [wLinkState], a + ld [wEnteringCableClub], a + jr SpecialEnterMap +.choseCancel + xor a + ld [wMenuJoypadPollCount], a + call Delay3 + call CloseLinkConnection + ld hl, LinkCanceledText + call PrintText + ld hl, wd72e + res 6, [hl] + ret + +WhereWouldYouLikeText: + TX_FAR _WhereWouldYouLikeText + db "@" + +PleaseWaitText: + TX_FAR _PleaseWaitText + db "@" + +LinkCanceledText: + TX_FAR _LinkCanceledText + db "@" + +StartNewGame: + ld hl, wd732 + res 1, [hl] + call OakSpeech + ld c, 20 + call DelayFrames + +; enter map after using a special warp or loading the game from the main menu +SpecialEnterMap:: + xor a + ld [hJoyPressed], a + ld [hJoyHeld], a + ld [hJoy5], a + ld [wd72d], a + ld hl, wd732 + set 0, [hl] ; count play time + call ResetPlayerSpriteData + ld c, 20 + call DelayFrames + ld a, [wEnteringCableClub] + and a + ret nz + jp EnterMap + +ContinueText: + db "CONTINUE", $4e + +NewGameText: + db "NEW GAME" + next "OPTION@" + +CableClubOptionsText: + db "TRADE CENTER" + next "COLOSSEUM" + next "CANCEL@" + +DisplayContinueGameInfo: + xor a + ld [H_AUTOBGTRANSFERENABLED], a + coord hl, 4, 7 + ld b, 8 + ld c, 14 + call TextBoxBorder + coord hl, 5, 9 + ld de, SaveScreenInfoText + call PlaceString + coord hl, 12, 9 + ld de, wPlayerName + call PlaceString + coord hl, 17, 11 + call PrintNumBadges + coord hl, 16, 13 + call PrintNumOwnedMons + coord hl, 13, 15 + call PrintPlayTime + ld a, 1 + ld [H_AUTOBGTRANSFERENABLED], a + ld c, 30 + jp DelayFrames + +PrintSaveScreenText: + xor a + ld [H_AUTOBGTRANSFERENABLED], a + coord hl, 4, 0 + ld b, $8 + ld c, $e + call TextBoxBorder + call LoadTextBoxTilePatterns + call UpdateSprites + coord hl, 5, 2 + ld de, SaveScreenInfoText + call PlaceString + coord hl, 12, 2 + ld de, wPlayerName + call PlaceString + coord hl, 17, 4 + call PrintNumBadges + coord hl, 16, 6 + call PrintNumOwnedMons + coord hl, 13, 8 + call PrintPlayTime + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + ld c, 30 + jp DelayFrames + +PrintNumBadges: + push hl + ld hl, wObtainedBadges + ld b, $1 + call CountSetBits + pop hl + ld de, wNumSetBits + lb bc, 1, 2 + jp PrintNumber + +PrintNumOwnedMons: + push hl + ld hl, wPokedexOwned + ld b, wPokedexOwnedEnd - wPokedexOwned + call CountSetBits + pop hl + ld de, wNumSetBits + lb bc, 1, 3 + jp PrintNumber + +PrintPlayTime: + ld de, wPlayTimeHours + lb bc, 1, 3 + call PrintNumber + ld [hl], $6d + inc hl + ld de, wPlayTimeMinutes + lb bc, LEADING_ZEROES | 1, 2 + jp PrintNumber + +SaveScreenInfoText: + db "PLAYER" + next "BADGES " + next "#DEX " + next "TIME@" + +DisplayOptionMenu: + coord hl, 0, 0 + ld b, 3 + ld c, 18 + call TextBoxBorder + coord hl, 0, 5 + ld b, 3 + ld c, 18 + call TextBoxBorder + coord hl, 0, 10 + ld b, 3 + ld c, 18 + call TextBoxBorder + coord hl, 1, 1 + ld de, TextSpeedOptionText + call PlaceString + coord hl, 1, 6 + ld de, BattleAnimationOptionText + call PlaceString + coord hl, 1, 11 + ld de, BattleStyleOptionText + call PlaceString + coord hl, 2, 16 + ld de, OptionMenuCancelText + call PlaceString + xor a + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + inc a + ld [wLetterPrintingDelayFlags], a + ld [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 + ld [H_AUTOBGTRANSFERENABLED], a ; enable auto background transfer + call Delay3 +.loop + call PlaceMenuCursor + call SetOptionsFromCursorPositions +.getJoypadStateLoop + call JoypadLowSensitivity + ld a, [hJoy5] + ld b, a + and A_BUTTON | B_BUTTON | START | D_RIGHT | D_LEFT | D_UP | D_DOWN ; any key besides select pressed? + jr z, .getJoypadStateLoop + bit 1, b ; B button pressed? + jr nz, .exitMenu + bit 3, b ; Start button pressed? + jr nz, .exitMenu + bit 0, b ; A button pressed? + jr z, .checkDirectionKeys + ld a, [wTopMenuItemY] + cp 16 ; is the cursor on Cancel? + jr nz, .loop +.exitMenu + ld a, SFX_PRESS_AB + call PlaySound + ret +.eraseOldMenuCursor + ld [wTopMenuItemX], a + call EraseMenuCursor + jp .loop +.checkDirectionKeys + ld a, [wTopMenuItemY] + bit 7, b ; Down pressed? + jr nz, .downPressed + bit 6, b ; Up pressed? + jr nz, .upPressed + cp 8 ; cursor in Battle Animation section? + jr z, .cursorInBattleAnimation + cp 13 ; cursor in Battle Style section? + jr z, .cursorInBattleStyle + cp 16 ; cursor on Cancel? + jr z, .loop +.cursorInTextSpeed + bit 5, b ; Left pressed? + jp nz, .pressedLeftInTextSpeed + jp .pressedRightInTextSpeed +.downPressed + cp 16 + ld b, -13 + ld hl, wOptionsTextSpeedCursorX + jr z, .updateMenuVariables + ld b, 5 + cp 3 + inc hl + jr z, .updateMenuVariables + cp 8 + inc hl + jr z, .updateMenuVariables + ld b, 3 + inc hl + jr .updateMenuVariables +.upPressed + cp 8 + ld b, -5 + ld hl, wOptionsTextSpeedCursorX + jr z, .updateMenuVariables + cp 13 + inc hl + jr z, .updateMenuVariables + cp 16 + ld b, -3 + inc hl + jr z, .updateMenuVariables + ld b, 13 + inc hl +.updateMenuVariables + add b + ld [wTopMenuItemY], a + ld a, [hl] + ld [wTopMenuItemX], a + call PlaceUnfilledArrowMenuCursor + jp .loop +.cursorInBattleAnimation + ld a, [wOptionsBattleAnimCursorX] ; battle animation cursor X coordinate + xor $0b ; toggle between 1 and 10 + ld [wOptionsBattleAnimCursorX], a + jp .eraseOldMenuCursor +.cursorInBattleStyle + ld a, [wOptionsBattleStyleCursorX] ; battle style cursor X coordinate + xor $0b ; toggle between 1 and 10 + ld [wOptionsBattleStyleCursorX], a + jp .eraseOldMenuCursor +.pressedLeftInTextSpeed + ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate + cp 1 + jr z, .updateTextSpeedXCoord + cp 7 + jr nz, .fromSlowToMedium + sub 6 + jr .updateTextSpeedXCoord +.fromSlowToMedium + sub 7 + jr .updateTextSpeedXCoord +.pressedRightInTextSpeed + ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate + cp 14 + jr z, .updateTextSpeedXCoord + cp 7 + jr nz, .fromFastToMedium + add 7 + jr .updateTextSpeedXCoord +.fromFastToMedium + add 6 +.updateTextSpeedXCoord + ld [wOptionsTextSpeedCursorX], a ; text speed cursor X coordinate + jp .eraseOldMenuCursor + +TextSpeedOptionText: + db "TEXT SPEED" + next " FAST MEDIUM SLOW@" + +BattleAnimationOptionText: + db "BATTLE ANIMATION" + next " ON OFF@" + +BattleStyleOptionText: + db "BATTLE STYLE" + next " SHIFT SET@" + +OptionMenuCancelText: + db "CANCEL@" + +; sets the options variable according to the current placement of the menu cursors in the options menu +SetOptionsFromCursorPositions: + ld hl, TextSpeedOptionData + ld a, [wOptionsTextSpeedCursorX] ; text speed cursor X coordinate + ld c, a +.loop + ld a, [hli] + cp c + jr z, .textSpeedMatchFound + inc hl + jr .loop +.textSpeedMatchFound + ld a, [hl] + ld d, a + ld a, [wOptionsBattleAnimCursorX] ; battle animation cursor X coordinate + dec a + jr z, .battleAnimationOn +.battleAnimationOff + set 7, d + jr .checkBattleStyle +.battleAnimationOn + res 7, d +.checkBattleStyle + ld a, [wOptionsBattleStyleCursorX] ; battle style cursor X coordinate + dec a + jr z, .battleStyleShift +.battleStyleSet + set 6, d + jr .storeOptions +.battleStyleShift + res 6, d +.storeOptions + ld a, d + ld [wOptions], a + ret + +; reads the options variable and places menu cursors in the correct positions within the options menu +SetCursorPositionsFromOptions: + ld hl, TextSpeedOptionData + 1 + ld a, [wOptions] + ld c, a + and $3f + push bc + ld de, 2 + call IsInArray + pop bc + dec hl + ld a, [hl] + ld [wOptionsTextSpeedCursorX], a ; text speed cursor X coordinate + coord hl, 0, 3 + call .placeUnfilledRightArrow + sla c + ld a, 1 ; On + jr nc, .storeBattleAnimationCursorX + ld a, 10 ; Off +.storeBattleAnimationCursorX + ld [wOptionsBattleAnimCursorX], a ; battle animation cursor X coordinate + coord hl, 0, 8 + call .placeUnfilledRightArrow + sla c + ld a, 1 + jr nc, .storeBattleStyleCursorX + ld a, 10 +.storeBattleStyleCursorX + ld [wOptionsBattleStyleCursorX], a ; battle style cursor X coordinate + coord hl, 0, 13 + call .placeUnfilledRightArrow +; cursor in front of Cancel + coord hl, 0, 16 + ld a, 1 +.placeUnfilledRightArrow + ld e, a + ld d, 0 + add hl, de + ld [hl], $ec ; unfilled right arrow menu cursor + ret + +; table that indicates how the 3 text speed options affect frame delays +; Format: +; 00: X coordinate of menu cursor +; 01: delay after printing a letter (in frames) +TextSpeedOptionData: + db 14,5 ; Slow + db 7,3 ; Medium + db 1,1 ; Fast + db 7 ; default X coordinate (Medium) + db $ff ; terminator + +CheckForPlayerNameInSRAM: +; Check if the player name data in SRAM has a string terminator character +; (indicating that a name may have been saved there) and return whether it does +; in carry. + ld a, SRAM_ENABLE + ld [MBC1SRamEnable], a + ld a, $1 + ld [MBC1SRamBankingMode], a + ld [MBC1SRamBank], a + ld b, NAME_LENGTH + ld hl, sPlayerName +.loop + ld a, [hli] + cp "@" + jr z, .found + dec b + jr nz, .loop +; not found + xor a + ld [MBC1SRamEnable], a + ld [MBC1SRamBankingMode], a + and a + ret +.found + xor a + ld [MBC1SRamEnable], a + ld [MBC1SRamBankingMode], a + scf + ret diff --git a/engine/menus/naming_screen.asm b/engine/menus/naming_screen.asm new file mode 100755 index 00000000..2b86d6f4 --- /dev/null +++ b/engine/menus/naming_screen.asm @@ -0,0 +1,494 @@ +AskName: + call SaveScreenTilesToBuffer1 + call GetPredefRegisters + push hl + ld a, [wIsInBattle] + dec a + coord hl, 0, 0 + ld b, 4 + ld c, 11 + call z, ClearScreenArea ; only if in wild battle + ld a, [wcf91] + ld [wd11e], a + call GetMonName + ld hl, DoYouWantToNicknameText + call PrintText + coord hl, 14, 7 + lb bc, 8, 15 + ld a, TWO_OPTION_MENU + ld [wTextBoxID], a + call DisplayTextBoxID + pop hl + ld a, [wCurrentMenuItem] + and a + jr nz, .declinedNickname + ld a, [wUpdateSpritesEnabled] + push af + xor a + ld [wUpdateSpritesEnabled], a + push hl + ld a, NAME_MON_SCREEN + ld [wNamingScreenType], a + call DisplayNamingScreen + ld a, [wIsInBattle] + and a + jr nz, .inBattle + call ReloadMapSpriteTilePatterns +.inBattle + call LoadScreenTilesFromBuffer1 + pop hl + pop af + ld [wUpdateSpritesEnabled], a + ld a, [wcf4b] + cp "@" + ret nz +.declinedNickname + ld d, h + ld e, l + ld hl, wcd6d + ld bc, NAME_LENGTH + jp CopyData + +DoYouWantToNicknameText: + TX_FAR _DoYouWantToNicknameText + db "@" + +DisplayNameRaterScreen:: + ld hl, wBuffer + xor a + ld [wUpdateSpritesEnabled], a + ld a, NAME_MON_SCREEN + ld [wNamingScreenType], a + call DisplayNamingScreen + call GBPalWhiteOutWithDelay3 + call RestoreScreenTilesAndReloadTilePatterns + call LoadGBPal + ld a, [wcf4b] + cp "@" + jr z, .playerCancelled + ld hl, wPartyMonNicks + ld bc, NAME_LENGTH + ld a, [wWhichPokemon] + call AddNTimes + ld e, l + ld d, h + ld hl, wBuffer + ld bc, NAME_LENGTH + call CopyData + and a + ret +.playerCancelled + scf + ret + +DisplayNamingScreen: + push hl + ld hl, wd730 + set 6, [hl] + call GBPalWhiteOutWithDelay3 + call ClearScreen + call UpdateSprites + ld b, SET_PAL_GENERIC + call RunPaletteCommand + call LoadHpBarAndStatusTilePatterns + call LoadEDTile + callba LoadMonPartySpriteGfx + coord hl, 0, 4 + ld b, 9 + ld c, 18 + call TextBoxBorder + call PrintNamingText + ld a, 3 + ld [wTopMenuItemY], a + ld a, 1 + ld [wTopMenuItemX], a + ld [wLastMenuItem], a + ld [wCurrentMenuItem], a + ld a, $ff + ld [wMenuWatchedKeys], a + ld a, 7 + ld [wMaxMenuItem], a + ld a, "@" + ld [wcf4b], a + xor a + ld hl, wNamingScreenSubmitName + ld [hli], a + ld [hli], a + ld [wAnimCounter], a +.selectReturnPoint + call PrintAlphabet + call GBPalNormal +.ABStartReturnPoint + ld a, [wNamingScreenSubmitName] + and a + jr nz, .submitNickname + call PrintNicknameAndUnderscores +.dPadReturnPoint + call PlaceMenuCursor +.inputLoop + ld a, [wCurrentMenuItem] + push af + callba AnimatePartyMon_ForceSpeed1 + pop af + ld [wCurrentMenuItem], a + call JoypadLowSensitivity + ld a, [hJoyPressed] + and a + jr z, .inputLoop + ld hl, .namingScreenButtonFunctions +.checkForPressedButton + sla a + jr c, .foundPressedButton + inc hl + inc hl + inc hl + inc hl + jr .checkForPressedButton +.foundPressedButton + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + ld a, [hli] + ld h, [hl] + ld l, a + push de + jp hl + +.submitNickname + pop de + ld hl, wcf4b + ld bc, NAME_LENGTH + call CopyData + call GBPalWhiteOutWithDelay3 + call ClearScreen + call ClearSprites + call RunDefaultPaletteCommand + call GBPalNormal + xor a + ld [wAnimCounter], a + ld hl, wd730 + res 6, [hl] + ld a, [wIsInBattle] + and a + jp z, LoadTextBoxTilePatterns + jpab LoadHudTilePatterns + +.namingScreenButtonFunctions + dw .dPadReturnPoint + dw .pressedDown + dw .dPadReturnPoint + dw .pressedUp + dw .dPadReturnPoint + dw .pressedLeft + dw .dPadReturnPoint + dw .pressedRight + dw .ABStartReturnPoint + dw .pressedStart + dw .selectReturnPoint + dw .pressedSelect + dw .ABStartReturnPoint + dw .pressedB + dw .ABStartReturnPoint + dw .pressedA + +.pressedA_changedCase + pop de + ld de, .selectReturnPoint + push de +.pressedSelect + ld a, [wAlphabetCase] + xor $1 + ld [wAlphabetCase], a + ret + +.pressedStart + ld a, 1 + ld [wNamingScreenSubmitName], a + ret + +.pressedA + ld a, [wCurrentMenuItem] + cp $5 ; "ED" row + jr nz, .didNotPressED + ld a, [wTopMenuItemX] + cp $11 ; "ED" column + jr z, .pressedStart +.didNotPressED + ld a, [wCurrentMenuItem] + cp $6 ; case switch row + jr nz, .didNotPressCaseSwtich + ld a, [wTopMenuItemX] + cp $1 ; case switch column + jr z, .pressedA_changedCase +.didNotPressCaseSwtich + ld hl, wMenuCursorLocation + ld a, [hli] + ld h, [hl] + ld l, a + inc hl + ld a, [hl] + ld [wNamingScreenLetter], a + call CalcStringLength + ld a, [wNamingScreenLetter] + cp $e5 + ld de, Dakutens + jr z, .dakutensAndHandakutens + cp $e4 + ld de, Handakutens + jr z, .dakutensAndHandakutens + ld a, [wNamingScreenType] + cp NAME_MON_SCREEN + jr nc, .checkMonNameLength + ld a, [wNamingScreenNameLength] + cp $7 ; max length of player/rival names + jr .checkNameLength +.checkMonNameLength + ld a, [wNamingScreenNameLength] + cp $a ; max length of pokemon nicknames +.checkNameLength + jr c, .addLetter + ret + +.dakutensAndHandakutens + push hl + call DakutensAndHandakutens + pop hl + ret nc + dec hl +.addLetter + ld a, [wNamingScreenLetter] + ld [hli], a + ld [hl], "@" + ld a, SFX_PRESS_AB + call PlaySound + ret +.pressedB + ld a, [wNamingScreenNameLength] + and a + ret z + call CalcStringLength + dec hl + ld [hl], "@" + ret +.pressedRight + ld a, [wCurrentMenuItem] + cp $6 + ret z ; can't scroll right on bottom row + ld a, [wTopMenuItemX] + cp $11 ; max + jp z, .wrapToFirstColumn + inc a + inc a + jr .done +.wrapToFirstColumn + ld a, $1 + jr .done +.pressedLeft + ld a, [wCurrentMenuItem] + cp $6 + ret z ; can't scroll right on bottom row + ld a, [wTopMenuItemX] + dec a + jp z, .wrapToLastColumn + dec a + jr .done +.wrapToLastColumn + ld a, $11 ; max + jr .done +.pressedUp + ld a, [wCurrentMenuItem] + dec a + ld [wCurrentMenuItem], a + and a + ret nz + ld a, $6 ; wrap to bottom row + ld [wCurrentMenuItem], a + ld a, $1 ; force left column + jr .done +.pressedDown + ld a, [wCurrentMenuItem] + inc a + ld [wCurrentMenuItem], a + cp $7 + jr nz, .wrapToTopRow + ld a, $1 + ld [wCurrentMenuItem], a + jr .done +.wrapToTopRow + cp $6 + ret nz + ld a, $1 +.done + ld [wTopMenuItemX], a + jp EraseMenuCursor + +LoadEDTile: + ld de, ED_Tile + ld hl, vFont + $700 + ld bc, (ED_TileEnd - ED_Tile) / $8 + ; to fix the graphical bug on poor emulators + ;lb bc, BANK(ED_Tile), (ED_TileEnd - ED_Tile) / $8 + jp CopyVideoDataDouble + +ED_Tile: + INCBIN "gfx/font/ED.1bpp" +ED_TileEnd: + +PrintAlphabet: + xor a + ld [H_AUTOBGTRANSFERENABLED], a + ld a, [wAlphabetCase] + and a + ld de, LowerCaseAlphabet + jr nz, .lowercase + ld de, UpperCaseAlphabet +.lowercase + coord hl, 2, 5 + lb bc, 5, 9 ; 5 rows, 9 columns +.outerLoop + push bc +.innerLoop + ld a, [de] + ld [hli], a + inc hl + inc de + dec c + jr nz, .innerLoop + ld bc, SCREEN_WIDTH + 2 + add hl, bc + pop bc + dec b + jr nz, .outerLoop + call PlaceString + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + jp Delay3 + +INCLUDE "text/alphabets.asm" + +PrintNicknameAndUnderscores: + call CalcStringLength + ld a, c + ld [wNamingScreenNameLength], a + coord hl, 10, 2 + lb bc, 1, 10 + call ClearScreenArea + coord hl, 10, 2 + ld de, wcf4b + call PlaceString + coord hl, 10, 3 + ld a, [wNamingScreenType] + cp NAME_MON_SCREEN + jr nc, .pokemon1 + ld b, 7 ; player or rival max name length + jr .playerOrRival1 +.pokemon1 + ld b, 10 ; pokemon max name length +.playerOrRival1 + ld a, $76 ; underscore tile id +.placeUnderscoreLoop + ld [hli], a + dec b + jr nz, .placeUnderscoreLoop + ld a, [wNamingScreenType] + cp NAME_MON_SCREEN + ld a, [wNamingScreenNameLength] + jr nc, .pokemon2 + cp 7 ; player or rival max name length + jr .playerOrRival2 +.pokemon2 + cp 10 ; pokemon max name length +.playerOrRival2 + jr nz, .emptySpacesRemaining + ; when all spaces are filled, force the cursor onto the ED tile + call EraseMenuCursor + ld a, $11 ; "ED" x coord + ld [wTopMenuItemX], a + ld a, $5 ; "ED" y coord + ld [wCurrentMenuItem], a + ld a, [wNamingScreenType] + cp NAME_MON_SCREEN + ld a, 9 ; keep the last underscore raised + jr nc, .pokemon3 + ld a, 6 ; keep the last underscore raised +.pokemon3 +.emptySpacesRemaining + ld c, a + ld b, $0 + coord hl, 10, 3 + add hl, bc + ld [hl], $77 ; raised underscore tile id + ret + +DakutensAndHandakutens: + push de + call CalcStringLength + dec hl + ld a, [hl] + pop hl + ld de, $2 + call IsInArray + ret nc + inc hl + ld a, [hl] + ld [wNamingScreenLetter], a + ret + +INCLUDE "text/dakutens.asm" + +; calculates the length of the string at wcf4b and stores it in c +CalcStringLength: + ld hl, wcf4b + ld c, $0 +.loop + ld a, [hl] + cp "@" + ret z + inc hl + inc c + jr .loop + +PrintNamingText: + coord hl, 0, 1 + ld a, [wNamingScreenType] + ld de, YourTextString + and a + jr z, .notNickname + ld de, RivalsTextString + dec a + jr z, .notNickname + ld a, [wcf91] + ld [wMonPartySpriteSpecies], a + push af + callba WriteMonPartySpriteOAMBySpecies + pop af + ld [wd11e], a + call GetMonName + coord hl, 4, 1 + call PlaceString + ld hl, $1 + add hl, bc + ld [hl], $c9 + coord hl, 1, 3 + ld de, NicknameTextString + jr .placeString +.notNickname + call PlaceString + ld l, c + ld h, b + ld de, NameTextString +.placeString + jp PlaceString + +YourTextString: + db "YOUR @" + +RivalsTextString: + db "RIVAL's @" + +NameTextString: + db "NAME?@" + +NicknameTextString: + db "NICKNAME?@" diff --git a/engine/menus/oaks_pc.asm b/engine/menus/oaks_pc.asm new file mode 100755 index 00000000..03c9b8f1 --- /dev/null +++ b/engine/menus/oaks_pc.asm @@ -0,0 +1,28 @@ +OpenOaksPC: + call SaveScreenTilesToBuffer2 + ld hl, AccessedOaksPCText + call PrintText + ld hl, GetDexRatedText + call PrintText + call YesNoChoice + ld a, [wCurrentMenuItem] + and a + jr nz, .closePC + predef DisplayDexRating +.closePC + ld hl, ClosedOaksPCText + call PrintText + jp LoadScreenTilesFromBuffer2 + +GetDexRatedText: + TX_FAR _GetDexRatedText + db "@" + +ClosedOaksPCText: + TX_FAR _ClosedOaksPCText + TX_WAIT + db "@" + +AccessedOaksPCText: + TX_FAR _AccessedOaksPCText + db "@" diff --git a/engine/menus/party_menu.asm b/engine/menus/party_menu.asm new file mode 100755 index 00000000..41b6074b --- /dev/null +++ b/engine/menus/party_menu.asm @@ -0,0 +1,325 @@ +; [wPartyMenuTypeOrMessageID] = menu type / message ID +; if less than $F0, it is a menu type +; menu types: +; 00: normal pokemon menu (e.g. Start menu) +; 01: use healing item on pokemon menu +; 02: in-battle switch pokemon menu +; 03: learn TM/HM menu +; 04: swap pokemon positions menu +; 05: use evolution stone on pokemon menu +; otherwise, it is a message ID +; f0: poison healed +; f1: burn healed +; f2: freeze healed +; f3: sleep healed +; f4: paralysis healed +; f5: HP healed +; f6: health returned +; f7: revitalized +; f8: leveled up +DrawPartyMenu_:: + xor a + ld [H_AUTOBGTRANSFERENABLED], a + call ClearScreen + call UpdateSprites + callba LoadMonPartySpriteGfxWithLCDDisabled ; load pokemon icon graphics + +RedrawPartyMenu_:: + ld a, [wPartyMenuTypeOrMessageID] + cp SWAP_MONS_PARTY_MENU + jp z, .printMessage + call ErasePartyMenuCursors + callba InitPartyMenuBlkPacket + coord hl, 3, 0 + ld de, wPartySpecies + xor a + ld c, a + ld [hPartyMonIndex], a + ld [wWhichPartyMenuHPBar], a +.loop + ld a, [de] + cp $FF ; reached the terminator? + jp z, .afterDrawingMonEntries + push bc + push de + push hl + ld a, c + push hl + ld hl, wPartyMonNicks + call GetPartyMonName + pop hl + call PlaceString ; print the pokemon's name + callba WriteMonPartySpriteOAMByPartyIndex ; place the appropriate pokemon icon + ld a, [hPartyMonIndex] + ld [wWhichPokemon], a + inc a + ld [hPartyMonIndex], a + call LoadMonData + pop hl + push hl + ld a, [wMenuItemToSwap] + and a ; is the player swapping pokemon positions? + jr z, .skipUnfilledRightArrow +; if the player is swapping pokemon positions + dec a + ld b, a + ld a, [wWhichPokemon] + cp b ; is the player swapping the current pokemon in the list? + jr nz, .skipUnfilledRightArrow +; the player is swapping the current pokemon in the list + dec hl + dec hl + dec hl + ld a, "▷" ; unfilled right arrow menu cursor + ld [hli], a ; place the cursor + inc hl + inc hl +.skipUnfilledRightArrow + ld a, [wPartyMenuTypeOrMessageID] ; menu type + cp TMHM_PARTY_MENU + jr z, .teachMoveMenu + cp EVO_STONE_PARTY_MENU + jr z, .evolutionStoneMenu + push hl + ld bc, 14 ; 14 columns to the right + add hl, bc + ld de, wLoadedMonStatus + call PrintStatusCondition + pop hl + push hl + ld bc, SCREEN_WIDTH + 1 ; down 1 row and right 1 column + ld a, [hFlags_0xFFF6] + set 0, a + ld [hFlags_0xFFF6], a + add hl, bc + predef DrawHP2 ; draw HP bar and prints current / max HP + ld a, [hFlags_0xFFF6] + res 0, a + ld [hFlags_0xFFF6], a + call SetPartyMenuHPBarColor ; color the HP bar (on SGB) + pop hl + jr .printLevel +.teachMoveMenu + push hl + predef CanLearnTM ; check if the pokemon can learn the move + pop hl + ld de, .ableToLearnMoveText + ld a, c + and a + jr nz, .placeMoveLearnabilityString + ld de, .notAbleToLearnMoveText +.placeMoveLearnabilityString + ld bc, 20 + 9 ; down 1 row and right 9 columns + push hl + add hl, bc + call PlaceString + pop hl +.printLevel + ld bc, 10 ; move 10 columns to the right + add hl, bc + call PrintLevel + pop hl + pop de + inc de + ld bc, 2 * 20 + add hl, bc + pop bc + inc c + jp .loop +.ableToLearnMoveText + db "ABLE@" +.notAbleToLearnMoveText + db "NOT ABLE@" +.evolutionStoneMenu + push hl + ld hl, EvosMovesPointerTable + ld b, 0 + ld a, [wLoadedMonSpecies] + dec a + add a + rl b + ld c, a + add hl, bc + ld de, wEvosMoves + ld a, BANK(EvosMovesPointerTable) + ld bc, 2 + call FarCopyData + ld hl, wEvosMoves + ld a, [hli] + ld h, [hl] + ld l, a + ld de, wEvosMoves + ld a, BANK(EvosMovesPointerTable) + ld bc, wEvosMoves.end - wEvosMoves + call FarCopyData + ld hl, wEvosMoves + ld de, .notAbleToEvolveText +; loop through the pokemon's evolution entries +.checkEvolutionsLoop + ld a, [hli] + and a ; reached terminator? + jr z, .placeEvolutionStoneString ; if so, place the "NOT ABLE" string + inc hl + inc hl + cp EV_ITEM + jr nz, .checkEvolutionsLoop +; if it's a stone evolution entry + dec hl + dec hl + ld b, [hl] + ld a, [wEvoStoneItemID] ; the stone the player used + inc hl + inc hl + inc hl + cp b ; does the player's stone match this evolution entry's stone? + jr nz, .checkEvolutionsLoop +; if it does match + ld de, .ableToEvolveText +.placeEvolutionStoneString + ld bc, 20 + 9 ; down 1 row and right 9 columns + pop hl + push hl + add hl, bc + call PlaceString + pop hl + jr .printLevel +.ableToEvolveText + db "ABLE@" +.notAbleToEvolveText + db "NOT ABLE@" +.afterDrawingMonEntries + ld b, SET_PAL_PARTY_MENU + call RunPaletteCommand +.printMessage + ld hl, wd730 + ld a, [hl] + push af + push hl + set 6, [hl] ; turn off letter printing delay + ld a, [wPartyMenuTypeOrMessageID] ; message ID + cp $F0 + jr nc, .printItemUseMessage + add a + ld hl, PartyMenuMessagePointers + ld b, 0 + ld c, a + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + call PrintText +.done + pop hl + pop af + ld [hl], a + ld a, 1 + ld [H_AUTOBGTRANSFERENABLED], a + call Delay3 + jp GBPalNormal +.printItemUseMessage + and $0F + ld hl, PartyMenuItemUseMessagePointers + add a + ld c, a + ld b, 0 + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + push hl + ld a, [wUsedItemOnWhichPokemon] + ld hl, wPartyMonNicks + call GetPartyMonName + pop hl + call PrintText + jr .done + +PartyMenuItemUseMessagePointers: + dw AntidoteText + dw BurnHealText + dw IceHealText + dw AwakeningText + dw ParlyzHealText + dw PotionText + dw FullHealText + dw ReviveText + dw RareCandyText + +PartyMenuMessagePointers: + dw PartyMenuNormalText + dw PartyMenuItemUseText + dw PartyMenuBattleText + dw PartyMenuUseTMText + dw PartyMenuSwapMonText + dw PartyMenuItemUseText + +PartyMenuNormalText: + TX_FAR _PartyMenuNormalText + db "@" + +PartyMenuItemUseText: + TX_FAR _PartyMenuItemUseText + db "@" + +PartyMenuBattleText: + TX_FAR _PartyMenuBattleText + db "@" + +PartyMenuUseTMText: + TX_FAR _PartyMenuUseTMText + db "@" + +PartyMenuSwapMonText: + TX_FAR _PartyMenuSwapMonText + db "@" + +PotionText: + TX_FAR _PotionText + db "@" + +AntidoteText: + TX_FAR _AntidoteText + db "@" + +ParlyzHealText: + TX_FAR _ParlyzHealText + db "@" + +BurnHealText: + TX_FAR _BurnHealText + db "@" + +IceHealText: + TX_FAR _IceHealText + db "@" + +AwakeningText: + TX_FAR _AwakeningText + db "@" + +FullHealText: + TX_FAR _FullHealText + db "@" + +ReviveText: + TX_FAR _ReviveText + db "@" + +RareCandyText: + TX_FAR _RareCandyText + TX_SFX_ITEM_1 ; probably supposed to play SFX_LEVEL_UP but the wrong music bank is loaded + TX_BLINK + db "@" + +SetPartyMenuHPBarColor: + ld hl, wPartyMenuHPBarColors + ld a, [wWhichPartyMenuHPBar] + ld c, a + ld b, 0 + add hl, bc + call GetHealthBarColor + ld b, UPDATE_PARTY_MENU_BLK_PACKET + call RunPaletteCommand + ld hl, wWhichPartyMenuHPBar + inc [hl] + ret diff --git a/engine/menus/pc.asm b/engine/menus/pc.asm new file mode 100755 index 00000000..6ec45f2e --- /dev/null +++ b/engine/menus/pc.asm @@ -0,0 +1,141 @@ +ActivatePC:: + call SaveScreenTilesToBuffer2 + ld a, SFX_TURN_ON_PC + call PlaySound + ld hl, TurnedOnPC1Text + call PrintText + call WaitForSoundToFinish + ld hl, wFlags_0xcd60 + set 3, [hl] + call LoadScreenTilesFromBuffer2 + call Delay3 +PCMainMenu: + callba DisplayPCMainMenu + ld hl, wFlags_0xcd60 + set 5, [hl] + call HandleMenuInput + bit 1, a ;if player pressed B + jp nz, LogOff + ld a, [wMaxMenuItem] + cp 2 + jr nz, .next ;if not 2 menu items (not counting log off) (2 occurs before you get the pokedex) + ld a, [wCurrentMenuItem] + and a + jp z, BillsPC ;if current menu item id is 0, it's bills pc + cp 1 + jr z, .playersPC ;if current menu item id is 1, it's players pc + jp LogOff ;otherwise, it's 2, and you're logging off +.next + cp 3 + jr nz, .next2 ;if not 3 menu items (not counting log off) (3 occurs after you get the pokedex, before you beat the pokemon league) + ld a, [wCurrentMenuItem] + and a + jp z, BillsPC ;if current menu item id is 0, it's bills pc + cp 1 + jr z, .playersPC ;if current menu item id is 1, it's players pc + cp 2 + jp z, OaksPC ;if current menu item id is 2, it's oaks pc + jp LogOff ;otherwise, it's 3, and you're logging off +.next2 + ld a, [wCurrentMenuItem] + and a + jp z, BillsPC ;if current menu item id is 0, it's bills pc + cp 1 + jr z, .playersPC ;if current menu item id is 1, it's players pc + cp 2 + jp z, OaksPC ;if current menu item id is 2, it's oaks pc + cp 3 + jp z, PKMNLeague ;if current menu item id is 3, it's pkmnleague + jp LogOff ;otherwise, it's 4, and you're logging off +.playersPC + ld hl, wFlags_0xcd60 + res 5, [hl] + set 3, [hl] + ld a, SFX_ENTER_PC + call PlaySound + call WaitForSoundToFinish + ld hl, AccessedMyPCText + call PrintText + callba PlayerPC + jr ReloadMainMenu +OaksPC: + ld a, SFX_ENTER_PC + call PlaySound + call WaitForSoundToFinish + callba OpenOaksPC + jr ReloadMainMenu +PKMNLeague: + ld a, SFX_ENTER_PC + call PlaySound + call WaitForSoundToFinish + callba PKMNLeaguePC + jr ReloadMainMenu +BillsPC: + ld a, SFX_ENTER_PC + call PlaySound + call WaitForSoundToFinish + CheckEvent EVENT_MET_BILL + jr nz, .billsPC ;if you've met bill, use that bill's instead of someone's + ld hl, AccessedSomeonesPCText + jr .printText +.billsPC + ld hl, AccessedBillsPCText +.printText + call PrintText + callba BillsPC_ +ReloadMainMenu: + xor a + ld [wDoNotWaitForButtonPressAfterDisplayingText], a + call ReloadMapData + call UpdateSprites + jp PCMainMenu +LogOff: + ld a, SFX_TURN_OFF_PC + call PlaySound + call WaitForSoundToFinish + ld hl, wFlags_0xcd60 + res 3, [hl] + res 5, [hl] + ret + +TurnedOnPC1Text: + TX_FAR _TurnedOnPC1Text + db "@" + +AccessedBillsPCText: + TX_FAR _AccessedBillsPCText + db "@" + +AccessedSomeonesPCText: + TX_FAR _AccessedSomeonesPCText + db "@" + +AccessedMyPCText: + TX_FAR _AccessedMyPCText + db "@" + +; removes one of the specified item ID [hItemToRemoveID] from bag (if existent) +RemoveItemByID:: + ld hl, wBagItems + ld a, [hItemToRemoveID] + ld b, a + xor a + ld [hItemToRemoveIndex], a +.loop + ld a, [hli] + cp -1 ; reached terminator? + ret z + cp b + jr z, .foundItem + inc hl + ld a, [hItemToRemoveIndex] + inc a + ld [hItemToRemoveIndex], a + jr .loop +.foundItem + ld a, $1 + ld [wItemQuantity], a + ld a, [hItemToRemoveIndex] + ld [wWhichPokemon], a + ld hl, wNumBagItems + jp RemoveItemFromInventory diff --git a/engine/menus/players_pc.asm b/engine/menus/players_pc.asm new file mode 100755 index 00000000..403632fa --- /dev/null +++ b/engine/menus/players_pc.asm @@ -0,0 +1,303 @@ +PlayerPC:: + ld hl, wd730 + set 6, [hl] + ld a, ITEM_NAME + ld [wNameListType], a + call SaveScreenTilesToBuffer1 + xor a + ld [wBagSavedMenuItem], a + ld [wParentMenuItem], a + ld a, [wFlags_0xcd60] + bit 3, a ; accessing player's PC through another PC? + jr nz, PlayerPCMenu +; accessing it directly + ld a, SFX_TURN_ON_PC + call PlaySound + ld hl, TurnedOnPC2Text + call PrintText + +PlayerPCMenu: + ld a, [wParentMenuItem] + ld [wCurrentMenuItem], a + ld hl, wFlags_0xcd60 + set 5, [hl] + call LoadScreenTilesFromBuffer2 + coord hl, 0, 0 + ld b, $8 + ld c, $e + call TextBoxBorder + call UpdateSprites + coord hl, 2, 2 + ld de, PlayersPCMenuEntries + call PlaceString + ld hl, wTopMenuItemY + ld a, 2 + ld [hli], a ; wTopMenuItemY + dec a + ld [hli], a ; wTopMenuItemX + inc hl + inc hl + ld a, 3 + ld [hli], a ; wMaxMenuItem + ld a, A_BUTTON | B_BUTTON + ld [hli], a ; wMenuWatchedKeys + xor a + ld [hl], a + ld hl, wListScrollOffset + ld [hli], a ; wListScrollOffset + ld [hl], a ; wMenuWatchMovingOutOfBounds + ld [wPlayerMonNumber], a + ld hl, WhatDoYouWantText + call PrintText + call HandleMenuInput + bit 1, a + jp nz, ExitPlayerPC + call PlaceUnfilledArrowMenuCursor + ld a, [wCurrentMenuItem] + ld [wParentMenuItem], a + and a + jp z, PlayerPCWithdraw + dec a + jp z, PlayerPCDeposit + dec a + jp z, PlayerPCToss + +ExitPlayerPC: + ld a, [wFlags_0xcd60] + bit 3, a ; accessing player's PC through another PC? + jr nz, .next +; accessing it directly + ld a, SFX_TURN_OFF_PC + call PlaySound + call WaitForSoundToFinish +.next + ld hl, wFlags_0xcd60 + res 5, [hl] + call LoadScreenTilesFromBuffer2 + xor a + ld [wListScrollOffset], a + ld [wBagSavedMenuItem], a + ld hl, wd730 + res 6, [hl] + xor a + ld [wDoNotWaitForButtonPressAfterDisplayingText], a + ret + +PlayerPCDeposit: + xor a + ld [wCurrentMenuItem], a + ld [wListScrollOffset], a + ld a, [wNumBagItems] + and a + jr nz, .loop + ld hl, NothingToDepositText + call PrintText + jp PlayerPCMenu +.loop + ld hl, WhatToDepositText + call PrintText + ld hl, wNumBagItems + ld a, l + ld [wListPointer], a + ld a, h + ld [wListPointer + 1], a + xor a + ld [wPrintItemPrices], a + ld a, ITEMLISTMENU + ld [wListMenuID], a + call DisplayListMenuID + jp c, PlayerPCMenu + call IsKeyItem + ld a, 1 + ld [wItemQuantity], a + ld a, [wIsKeyItem] + and a + jr nz, .next +; if it's not a key item, there can be more than one of the item + ld hl, DepositHowManyText + call PrintText + call DisplayChooseQuantityMenu + cp $ff + jp z, .loop +.next + ld hl, wNumBoxItems + call AddItemToInventory + jr c, .roomAvailable + ld hl, NoRoomToStoreText + call PrintText + jp .loop +.roomAvailable + ld hl, wNumBagItems + call RemoveItemFromInventory + call WaitForSoundToFinish + ld a, SFX_WITHDRAW_DEPOSIT + call PlaySound + call WaitForSoundToFinish + ld hl, ItemWasStoredText + call PrintText + jp .loop + +PlayerPCWithdraw: + xor a + ld [wCurrentMenuItem], a + ld [wListScrollOffset], a + ld a, [wNumBoxItems] + and a + jr nz, .loop + ld hl, NothingStoredText + call PrintText + jp PlayerPCMenu +.loop + ld hl, WhatToWithdrawText + call PrintText + ld hl, wNumBoxItems + ld a, l + ld [wListPointer], a + ld a, h + ld [wListPointer + 1], a + xor a + ld [wPrintItemPrices], a + ld a, ITEMLISTMENU + ld [wListMenuID], a + call DisplayListMenuID + jp c, PlayerPCMenu + call IsKeyItem + ld a, 1 + ld [wItemQuantity], a + ld a, [wIsKeyItem] + and a + jr nz, .next +; if it's not a key item, there can be more than one of the item + ld hl, WithdrawHowManyText + call PrintText + call DisplayChooseQuantityMenu + cp $ff + jp z, .loop +.next + ld hl, wNumBagItems + call AddItemToInventory + jr c, .roomAvailable + ld hl, CantCarryMoreText + call PrintText + jp .loop +.roomAvailable + ld hl, wNumBoxItems + call RemoveItemFromInventory + call WaitForSoundToFinish + ld a, SFX_WITHDRAW_DEPOSIT + call PlaySound + call WaitForSoundToFinish + ld hl, WithdrewItemText + call PrintText + jp .loop + +PlayerPCToss: + xor a + ld [wCurrentMenuItem], a + ld [wListScrollOffset], a + ld a, [wNumBoxItems] + and a + jr nz, .loop + ld hl, NothingStoredText + call PrintText + jp PlayerPCMenu +.loop + ld hl, WhatToTossText + call PrintText + ld hl, wNumBoxItems + ld a, l + ld [wListPointer], a + ld a, h + ld [wListPointer + 1], a + xor a + ld [wPrintItemPrices], a + ld a, ITEMLISTMENU + ld [wListMenuID], a + push hl + call DisplayListMenuID + pop hl + jp c, PlayerPCMenu + push hl + call IsKeyItem + pop hl + ld a, 1 + ld [wItemQuantity], a + ld a, [wIsKeyItem] + and a + jr nz, .next + ld a, [wcf91] + call IsItemHM + jr c, .next +; if it's not a key item, there can be more than one of the item + push hl + ld hl, TossHowManyText + call PrintText + call DisplayChooseQuantityMenu + pop hl + cp $ff + jp z, .loop +.next + call TossItem ; disallows tossing key items + jp .loop + +PlayersPCMenuEntries: + db "WITHDRAW ITEM" + next "DEPOSIT ITEM" + next "TOSS ITEM" + next "LOG OFF@" + +TurnedOnPC2Text: + TX_FAR _TurnedOnPC2Text + db "@" + +WhatDoYouWantText: + TX_FAR _WhatDoYouWantText + db "@" + +WhatToDepositText: + TX_FAR _WhatToDepositText + db "@" + +DepositHowManyText: + TX_FAR _DepositHowManyText + db "@" + +ItemWasStoredText: + TX_FAR _ItemWasStoredText + db "@" + +NothingToDepositText: + TX_FAR _NothingToDepositText + db "@" + +NoRoomToStoreText: + TX_FAR _NoRoomToStoreText + db "@" + +WhatToWithdrawText: + TX_FAR _WhatToWithdrawText + db "@" + +WithdrawHowManyText: + TX_FAR _WithdrawHowManyText + db "@" + +WithdrewItemText: + TX_FAR _WithdrewItemText + db "@" + +NothingStoredText: + TX_FAR _NothingStoredText + db "@" + +CantCarryMoreText: + TX_FAR _CantCarryMoreText + db "@" + +WhatToTossText: + TX_FAR _WhatToTossText + db "@" + +TossHowManyText: + TX_FAR _TossHowManyText + db "@" diff --git a/engine/menus/pokedex.asm b/engine/menus/pokedex.asm new file mode 100755 index 00000000..8e1fd480 --- /dev/null +++ b/engine/menus/pokedex.asm @@ -0,0 +1,665 @@ +ShowPokedexMenu: + call GBPalWhiteOut + call ClearScreen + call UpdateSprites + ld a, [wListScrollOffset] + push af + xor a + ld [wCurrentMenuItem], a + ld [wListScrollOffset], a + ld [wLastMenuItem], a + inc a + ld [wd11e], a + ld [hJoy7], a +.setUpGraphics + ld b, SET_PAL_GENERIC + call RunPaletteCommand + callab LoadPokedexTilePatterns +.doPokemonListMenu + ld hl, wTopMenuItemY + ld a, 3 + ld [hli], a ; top menu item Y + xor a + ld [hli], a ; top menu item X + inc a + ld [wMenuWatchMovingOutOfBounds], a + inc hl + inc hl + ld a, 6 + ld [hli], a ; max menu item ID + ld [hl], D_LEFT | D_RIGHT | B_BUTTON | A_BUTTON + call HandlePokedexListMenu + jr c, .goToSideMenu ; if the player chose a pokemon from the list +.exitPokedex + xor a + ld [wMenuWatchMovingOutOfBounds], a + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + ld [hJoy7], a + ld [wWastedByteCD3A], a + ld [wOverrideSimulatedJoypadStatesMask], a + pop af + ld [wListScrollOffset], a + 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 + jp .setUpGraphics ; if pokemon data or area was shown + +; handles the menu on the lower right in the pokedex screen +; OUTPUT: +; b = reason for exiting menu +; 00: showed pokemon data or area +; 01: the player chose Quit +; 02: the pokemon has not been seen yet or the player pressed the B button +HandlePokedexSideMenu: + call PlaceUnfilledArrowMenuCursor + ld a, [wCurrentMenuItem] + push af + ld b, a + ld a, [wLastMenuItem] + push af + ld a, [wListScrollOffset] + push af + add b + inc a + ld [wd11e], a + ld a, [wd11e] + push af + ld a, [wDexMaxSeenMon] + push af ; this doesn't need to be preserved + ld hl, wPokedexSeen + call IsPokemonBitSet + ld b, 2 + jr z, .exitSideMenu + call PokedexToIndex + ld hl, wTopMenuItemY + ld a, 10 + 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 [hli], a ; max menu item ID + ;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 +.handleMenuInput + call HandleMenuInput + bit 1, a ; was the B button pressed? + ld b, 2 + jr nz, .buttonBPressed + ld a, [wCurrentMenuItem] + and a + jr z, .choseData + dec a + jr z, .choseCry + dec a + jr z, .choseArea +.choseQuit + ld b, 1 +.exitSideMenu + pop af + ld [wDexMaxSeenMon], a + pop af + ld [wd11e], a + pop af + ld [wListScrollOffset], a + pop af + ld [wLastMenuItem], a + pop af + ld [wCurrentMenuItem], a + push bc + coord hl, 0, 3 + ld de, 20 + lb bc, " ", 13 + call DrawTileLine ; cover up the menu cursor in the pokemon list + pop bc + ret + +.buttonBPressed + push bc + coord hl, 15, 10 + ld de, 20 + lb bc, " ", 7 + call DrawTileLine ; cover up the menu cursor in the side menu + pop bc + jr .exitSideMenu + +.choseData + call ShowPokedexDataInternal + ld b, 0 + jr .exitSideMenu + +; play pokemon cry +.choseCry + ld a, [wd11e] + call GetCryData + call PlaySound + jr .handleMenuInput + +.choseArea + predef LoadTownMap_Nest ; display pokemon areas + ld b, 0 + 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: + xor a + ld [H_AUTOBGTRANSFERENABLED], a +; draw the horizontal line separating the seen and owned amounts from the menu + coord hl, 15, 8 + ld a, "─" + ld [hli], a + ld [hli], a + ld [hli], a + ld [hli], a + ld [hli], a + coord hl, 14, 0 + ld [hl], $71 ; vertical line tile + coord hl, 14, 1 + call DrawPokedexVerticalLine + coord hl, 14, 9 + call DrawPokedexVerticalLine + ld hl, wPokedexSeen + ld b, wPokedexSeenEnd - wPokedexSeen + call CountSetBits + ld de, wNumSetBits + coord hl, 16, 3 + lb bc, 1, 3 + call PrintNumber ; print number of seen pokemon + ld hl, wPokedexOwned + ld b, wPokedexOwnedEnd - wPokedexOwned + call CountSetBits + ld de, wNumSetBits + coord hl, 16, 6 + lb bc, 1, 3 + call PrintNumber ; print number of owned pokemon + coord hl, 16, 2 + ld de, PokedexSeenText + call PlaceString + coord hl, 16, 5 + ld de, PokedexOwnText + call PlaceString + coord hl, 1, 1 + ld de, PokedexContentsText + call PlaceString + coord hl, 16, 10 + ld de, PokedexMenuItemsText + call PlaceString +; find the highest pokedex number among the pokemon the player has seen + ld hl, wPokedexSeenEnd - 1 + ld b, (wPokedexSeenEnd - wPokedexSeen) * 8 + 1 +.maxSeenPokemonLoop + ld a, [hld] + ld c, 8 +.maxSeenPokemonInnerLoop + dec b + sla a + jr c, .storeMaxSeenPokemon + dec c + jr nz, .maxSeenPokemonInnerLoop + jr .maxSeenPokemonLoop + +.storeMaxSeenPokemon + ld a, b + ld [wDexMaxSeenMon], a +.loop + xor a + ld [H_AUTOBGTRANSFERENABLED], a + coord hl, 4, 2 + lb bc, 14, 10 + call ClearScreenArea + coord hl, 1, 3 + ld a, [wListScrollOffset] + ld [wd11e], a + ld d, 7 + ld a, [wDexMaxSeenMon] + cp 7 + jr nc, .printPokemonLoop + ld d, a + dec a + ld [wMaxMenuItem], a +; loop to print pokemon pokedex numbers and names +; if the player has owned the pokemon, it puts a pokeball beside the name +.printPokemonLoop + ld a, [wd11e] + inc a + ld [wd11e], a + push af + push de + push hl + ld de, -SCREEN_WIDTH + add hl, de + ld de, wd11e + lb bc, LEADING_ZEROES | 1, 3 + call PrintNumber ; print the pokedex number + ld de, SCREEN_WIDTH + add hl, de + dec hl + push hl + ld hl, wPokedexOwned + call IsPokemonBitSet + pop hl + ld a, " " + jr z, .writeTile + ld a, $72 ; pokeball tile +.writeTile + ld [hl], a ; put a pokeball next to pokemon that the player has owned + push hl + ld hl, wPokedexSeen + call IsPokemonBitSet + jr nz, .getPokemonName ; if the player has seen the pokemon + ld de, .dashedLine ; print a dashed line in place of the name if the player hasn't seen the pokemon + jr .skipGettingName +.dashedLine ; for unseen pokemon in the list + db "----------@" +.getPokemonName + call PokedexToIndex + call GetMonName +.skipGettingName + pop hl + inc hl + call PlaceString + pop hl + ld bc, 2 * SCREEN_WIDTH + add hl, bc + pop de + pop af + ld [wd11e], a + dec d + jr nz, .printPokemonLoop + ld a, 01 + ld [H_AUTOBGTRANSFERENABLED], a + call Delay3 + call GBPalNormal + call HandleMenuInput + bit 1, a ; was the B button pressed? + jp nz, .buttonBPressed +.checkIfUpPressed + bit 6, a ; was Up pressed? + jr z, .checkIfDownPressed +.upPressed ; scroll up one row + ld a, [wListScrollOffset] + and a + jp z, .loop + dec a + ld [wListScrollOffset], a + jp .loop +.checkIfDownPressed + bit 7, a ; was Down pressed? + jr z, .checkIfRightPressed +.downPressed ; scroll down one row + ld a, [wDexMaxSeenMon] + cp 7 + jp c, .loop ; can't if the list is shorter than 7 + sub 7 + ld b, a + ld a, [wListScrollOffset] + cp b + jp z, .loop + inc a + ld [wListScrollOffset], a + jp .loop +.checkIfRightPressed + bit 4, a ; was Right pressed? + jr z, .checkIfLeftPressed +.rightPressed ; scroll down 7 rows + ld a, [wDexMaxSeenMon] + cp 7 + jp c, .loop ; can't if the list is shorter than 7 + sub 6 + ld b, a + ld a, [wListScrollOffset] + add 7 + ld [wListScrollOffset], a + cp b + jp c, .loop + dec b + ld a, b + ld [wListScrollOffset], a + jp .loop +.checkIfLeftPressed ; scroll up 7 rows + bit 5, a ; was Left pressed? + jr z, .buttonAPressed +.leftPressed + ld a, [wListScrollOffset] + sub 7 + ld [wListScrollOffset], a + jp nc, .loop + xor a + ld [wListScrollOffset], a + jp .loop +.buttonAPressed + scf + ret +.buttonBPressed + and a + ret + +DrawPokedexVerticalLine: + ld c, 9 ; height of line + ld de, SCREEN_WIDTH + ld a, $71 ; vertical line tile +.loop + ld [hl], a + add hl, de + xor 1 ; toggle between vertical line tile and box tile + dec c + jr nz, .loop + ret + +PokedexSeenText: + db "SEEN@" + +PokedexOwnText: + db "OWN@" + +PokedexContentsText: + db "CONTENTS@" + +PokedexMenuItemsText: + db "DATA" + next "CRY" + next "AREA" + next "QUIT@" + +; tests if a pokemon's bit is set in the seen or owned pokemon bit fields +; INPUT: +; [wd11e] = pokedex number +; hl = address of bit field +IsPokemonBitSet: + ld a, [wd11e] + dec a + ld c, a + ld b, FLAG_TEST + predef FlagActionPredef + ld a, c + and a + ret + +; function to display pokedex data from outside the pokedex +ShowPokedexData: + call GBPalWhiteOutWithDelay3 + call ClearScreen + call UpdateSprites + callab LoadPokedexTilePatterns ; load pokedex tiles + +; function to display pokedex data from inside the pokedex +ShowPokedexDataInternal: + ld hl, wd72c + set 1, [hl] + ld a, $33 ; 3/7 volume + ld [rNR50], a + call GBPalWhiteOut ; zero all palettes + call ClearScreen + ld a, [wd11e] ; pokemon ID + ld [wcf91], a + push af + ld b, SET_PAL_POKEDEX + call RunPaletteCommand + pop af + ld [wd11e], a + ld a, [hTilesetType] + push af + xor a + ld [hTilesetType], a + + coord hl, 0, 0 + ld de, 1 + lb bc, $64, SCREEN_WIDTH + call DrawTileLine ; draw top border + + coord hl, 0, 17 + ld b, $6f + call DrawTileLine ; draw bottom border + + coord hl, 0, 1 + ld de, 20 + lb bc, $66, $10 + call DrawTileLine ; draw left border + + coord hl, 19, 1 + ld b, $67 + call DrawTileLine ; draw right border + + ld a, $63 ; upper left corner tile + Coorda 0, 0 + ld a, $65 ; upper right corner tile + Coorda 19, 0 + ld a, $6c ; lower left corner tile + Coorda 0, 17 + ld a, $6e ; lower right corner tile + Coorda 19, 17 + + coord hl, 0, 9 + ld de, PokedexDataDividerLine + call PlaceString ; draw horizontal divider line + + coord hl, 9, 6 + ld de, HeightWeightText + call PlaceString + + call GetMonName + coord hl, 9, 2 + call PlaceString + + ld hl, PokedexEntryPointers + ld a, [wd11e] + dec a + ld e, a + ld d, 0 + add hl, de + add hl, de + ld a, [hli] + ld e, a + ld d, [hl] ; de = address of pokedex entry + + coord hl, 9, 4 + call PlaceString ; print species name + + ld h, b + ld l, c + push de + ld a, [wd11e] + push af + call IndexToPokedex + + coord hl, 2, 8 + ld a, "№" + ld [hli], a + ld a, "⠄" + ld [hli], a + ld de, wd11e + lb bc, LEADING_ZEROES | 1, 3 + call PrintNumber ; print pokedex number + + ld hl, wPokedexOwned + call IsPokemonBitSet + pop af + ld [wd11e], a + ld a, [wcf91] + ld [wd0b5], a + pop de + + push af + push bc + push de + push hl + + call Delay3 + call GBPalNormal + call GetMonHeader ; load pokemon picture location + coord hl, 1, 1 + call LoadFlippedFrontSpriteByMonIndex ; draw pokemon picture + ld a, [wcf91] + call PlayCry ; play pokemon cry + + pop hl + pop de + pop bc + pop af + + ld a, c + and a + jp z, .waitForButtonPress ; if the pokemon has not been owned, don't print the height, weight, or description + inc de ; de = address of feet (height) + ld a, [de] ; reads feet, but a is overwritten without being used + coord hl, 12, 6 + lb bc, 1, 2 + call PrintNumber ; print feet (height) + ld a, $60 ; feet symbol tile (one tick) + ld [hl], a + inc de + inc de ; de = address of inches (height) + coord hl, 15, 6 + lb bc, LEADING_ZEROES | 1, 2 + call PrintNumber ; print inches (height) + ld a, $61 ; inches symbol tile (two ticks) + ld [hl], a +; now print the weight (note that weight is stored in tenths of pounds internally) + inc de + inc de + inc de ; de = address of upper byte of weight + push de +; put weight in big-endian order at hDexWeight + ld hl, hDexWeight + ld a, [hl] ; save existing value of [hDexWeight] + push af + ld a, [de] ; a = upper byte of weight + ld [hli], a ; store upper byte of weight in [hDexWeight] + ld a, [hl] ; save existing value of [hDexWeight + 1] + push af + dec de + ld a, [de] ; a = lower byte of weight + ld [hl], a ; store lower byte of weight in [hDexWeight + 1] + ld de, hDexWeight + coord hl, 11, 8 + lb bc, 2, 5 ; 2 bytes, 5 digits + call PrintNumber ; print weight + coord hl, 14, 8 + ld a, [hDexWeight + 1] + sub 10 + ld a, [hDexWeight] + sbc 0 + jr nc, .next + ld [hl], "0" ; if the weight is less than 10, put a 0 before the decimal point +.next + inc hl + ld a, [hli] + ld [hld], a ; make space for the decimal point by moving the last digit forward one tile + ld [hl], "⠄" ; decimal point tile + pop af + ld [hDexWeight + 1], a ; restore original value of [hDexWeight + 1] + pop af + ld [hDexWeight], a ; restore original value of [hDexWeight] + pop hl + inc hl ; hl = address of pokedex description text + coord bc, 1, 11 + ld a, 2 + ld [$fff4], a + call TextCommandProcessor ; print pokedex description text + xor a + ld [$fff4], a +.waitForButtonPress + call JoypadLowSensitivity + ld a, [hJoy5] + and A_BUTTON | B_BUTTON + jr z, .waitForButtonPress + pop af + ld [hTilesetType], a + call GBPalWhiteOut + call ClearScreen + call RunDefaultPaletteCommand + call LoadTextBoxTilePatterns + call GBPalNormal + ld hl, wd72c + res 1, [hl] + ld a, $77 ; max volume + ld [rNR50], a + ret + +HeightWeightText: + db "HT ?",$60,"??",$61 + next "WT ???lb@" + +; XXX does anything point to this? +PokeText: + db "#@" + +; horizontal line that divides the pokedex text description from the rest of the data +PokedexDataDividerLine: + db $68,$69,$6B,$69,$6B + db $69,$6B,$69,$6B,$6B + db $6B,$6B,$69,$6B,$69 + db $6B,$69,$6B,$69,$6A + db "@" + +; draws a line of tiles +; INPUT: +; b = tile ID +; c = number of tile ID's to write +; de = amount to destination address after each tile (1 for horizontal, 20 for vertical) +; hl = destination address +DrawTileLine: + push bc + push de +.loop + ld [hl], b + add hl, de + dec c + jr nz, .loop + pop de + pop bc + ret + +INCLUDE "data/pokedex_entries.asm" + +PokedexToIndex: + ; converts the Pokédex number at wd11e to an index + push bc + push hl + ld a, [wd11e] + ld b, a + ld c, 0 + ld hl, PokedexOrder + +.loop ; go through the list until we find an entry with a matching dex number + inc c + ld a, [hli] + cp b + jr nz, .loop + + ld a, c + ld [wd11e], a + pop hl + pop bc + ret + +IndexToPokedex: + ; converts the index number at wd11e to a Pokédex number + push bc + push hl + ld a, [wd11e] + dec a + ld hl, PokedexOrder + ld b, 0 + ld c, a + add hl, bc + ld a, [hl] + ld [wd11e], a + pop hl + pop bc + ret + +INCLUDE "data/pokedex_order.asm" diff --git a/engine/menus/save.asm b/engine/menus/save.asm new file mode 100755 index 00000000..33a7ba8d --- /dev/null +++ b/engine/menus/save.asm @@ -0,0 +1,708 @@ +LoadSAV: +;(if carry -> write +;"the file data is destroyed") + call ClearScreen + call LoadFontTilePatterns + call LoadTextBoxTilePatterns + call LoadSAV0 + jr c, .badsum + call LoadSAV1 + jr c, .badsum + call LoadSAV2 + jr c, .badsum + ld a, $2 ; good checksum + jr .goodsum +.badsum + ld hl, wd730 + push hl + set 6, [hl] + ld hl, FileDataDestroyedText + call PrintText + ld c, 100 + call DelayFrames + pop hl + res 6, [hl] + ld a, $1 ; bad checksum +.goodsum + ld [wSaveFileStatus], a + ret + +FileDataDestroyedText: + TX_FAR _FileDataDestroyedText + db "@" + +LoadSAV0: + ld a, SRAM_ENABLE + ld [MBC1SRamEnable], a + 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 + call SAVCheckSum + ld c, a + ld a, [sMainDataCheckSum] ; SAV's checksum + cp c + jp z, .checkSumsMatched + +; If the computed checksum didn't match the saved on, try again. + ld hl, sPlayerName + ld bc, sMainDataCheckSum - sPlayerName + call SAVCheckSum + ld c, a + ld a, [sMainDataCheckSum] ; SAV's checksum + cp c + jp nz, SAVBadCheckSum + +.checkSumsMatched + ld hl, sPlayerName + ld de, wPlayerName + ld bc, NAME_LENGTH + call CopyData + ld hl, sMainData + ld de, wMainDataStart + ld bc, wMainDataEnd - wMainDataStart + call CopyData + ld hl, wCurMapTileset + set 7, [hl] + ld hl, sSpriteData + ld de, wSpriteDataStart + ld bc, wSpriteDataEnd - wSpriteDataStart + call CopyData + ld a, [sTilesetType] + ld [hTilesetType], a + ld hl, sCurBoxData + ld de, wBoxDataStart + ld bc, wBoxDataEnd - wBoxDataStart + call CopyData + and a + jp SAVGoodChecksum + +LoadSAV1: + ld a, SRAM_ENABLE + ld [MBC1SRamEnable], a + 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 + call SAVCheckSum + ld c, a + ld a, [sMainDataCheckSum] ; SAV's checksum + cp c + jr nz, SAVBadCheckSum + ld hl, sCurBoxData + ld de, wBoxDataStart + ld bc, wBoxDataEnd - wBoxDataStart + call CopyData + and a + jp SAVGoodChecksum + +LoadSAV2: + ld a, SRAM_ENABLE + ld [MBC1SRamEnable], a + 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 + call SAVCheckSum + ld c, a + ld a, [sMainDataCheckSum] ; SAV's checksum + cp c + jp nz, SAVBadCheckSum + ld hl, sPartyData + ld de, wPartyDataStart + ld bc, wPartyDataEnd - wPartyDataStart + call CopyData + ld hl, sMainData + ld de, wPokedexOwned + ld bc, wPokedexSeenEnd - wPokedexOwned + call CopyData + and a + jp SAVGoodChecksum + +SAVBadCheckSum: + scf + +SAVGoodChecksum: + ld a, $0 + ld [MBC1SRamBankingMode], a + ld [MBC1SRamEnable], a + ret + +LoadSAVIgnoreBadCheckSum: +; unused function that loads save data and ignores bad checksums + call LoadSAV0 + call LoadSAV1 + jp LoadSAV2 + +SaveSAV: + callba PrintSaveScreenText + ld hl, WouldYouLikeToSaveText + call SaveSAVConfirm + and a ;|0 = Yes|1 = No| + ret nz + ld a, [wSaveFileStatus] + dec a + jr z, .save + call SAVCheckRandomID + jr z, .save + ld hl, OlderFileWillBeErasedText + call SaveSAVConfirm + and a + ret nz +.save + call SaveSAVtoSRAM + coord hl, 1, 13 + lb bc, 4, 18 + call ClearScreenArea + coord hl, 1, 14 + ld de, NowSavingString + call PlaceString + ld c, 120 + call DelayFrames + ld hl, GameSavedText + call PrintText + ld a, SFX_SAVE + call PlaySoundWaitForCurrent + call WaitForSoundToFinish + ld c, 30 + jp DelayFrames + +NowSavingString: + db "Now saving...@" + +SaveSAVConfirm: + call PrintText + coord hl, 0, 7 + lb bc, 8, 1 + ld a, TWO_OPTION_MENU + ld [wTextBoxID], a + call DisplayTextBoxID ; yes/no menu + ld a, [wCurrentMenuItem] + ret + +WouldYouLikeToSaveText: + TX_FAR _WouldYouLikeToSaveText + db "@" + +GameSavedText: + TX_FAR _GameSavedText + db "@" + +OlderFileWillBeErasedText: + TX_FAR _OlderFileWillBeErasedText + db "@" + +SaveSAVtoSRAM0: + ld a, SRAM_ENABLE + ld [MBC1SRamEnable], a + ld a, $1 + ld [MBC1SRamBankingMode], a + ld [MBC1SRamBank], a + ld hl, wPlayerName + ld de, sPlayerName + ld bc, NAME_LENGTH + call CopyData + ld hl, wMainDataStart + ld de, sMainData + ld bc, wMainDataEnd - wMainDataStart + call CopyData + ld hl, wSpriteDataStart + ld de, sSpriteData + ld bc, wSpriteDataEnd - wSpriteDataStart + call CopyData + ld hl, wBoxDataStart + ld de, sCurBoxData + ld bc, wBoxDataEnd - wBoxDataStart + call CopyData + ld a, [hTilesetType] + ld [sTilesetType], a + ld hl, sPlayerName + ld bc, sMainDataCheckSum - sPlayerName + call SAVCheckSum + ld [sMainDataCheckSum], a + xor a + ld [MBC1SRamBankingMode], a + ld [MBC1SRamEnable], a + ret + +SaveSAVtoSRAM1: +; stored pokémon + ld a, SRAM_ENABLE + ld [MBC1SRamEnable], a + ld a, $1 + ld [MBC1SRamBankingMode], a + ld [MBC1SRamBank], a + ld hl, wBoxDataStart + ld de, sCurBoxData + ld bc, wBoxDataEnd - wBoxDataStart + call CopyData + ld hl, sPlayerName + ld bc, sMainDataCheckSum - sPlayerName + call SAVCheckSum + ld [sMainDataCheckSum], a + xor a + ld [MBC1SRamBankingMode], a + ld [MBC1SRamEnable], a + ret + +SaveSAVtoSRAM2: + ld a, SRAM_ENABLE + ld [MBC1SRamEnable], a + ld a, $1 + ld [MBC1SRamBankingMode], a + ld [MBC1SRamBank], a + ld hl, wPartyDataStart + ld de, sPartyData + ld bc, wPartyDataEnd - wPartyDataStart + call CopyData + ld hl, wPokedexOwned ; pokédex only + ld de, sMainData + ld bc, wPokedexSeenEnd - wPokedexOwned + call CopyData + ld hl, sPlayerName + ld bc, sMainDataCheckSum - sPlayerName + call SAVCheckSum + ld [sMainDataCheckSum], a + xor a + ld [MBC1SRamBankingMode], a + ld [MBC1SRamEnable], a + ret + +SaveSAVtoSRAM:: + ld a, $2 + ld [wSaveFileStatus], a + call SaveSAVtoSRAM0 + call SaveSAVtoSRAM1 + jp SaveSAVtoSRAM2 + +SAVCheckSum: +;Check Sum (result[1 byte] is complemented) + ld d, 0 +.loop + ld a, [hli] + add d + ld d, a + dec bc + ld a, b + or c + jr nz, .loop + ld a, d + cpl + ret + +CalcIndividualBoxCheckSums: + ld hl, sBox1 ; sBox7 + ld de, sBank2IndividualBoxChecksums ; sBank3IndividualBoxChecksums + ld b, NUM_BOXES / 2 +.loop + push bc + push de + ld bc, wBoxDataEnd - wBoxDataStart + call SAVCheckSum + pop de + ld [de], a + inc de + pop bc + dec b + jr nz, .loop + ret + +GetBoxSRAMLocation: +; in: a = box num +; out: b = box SRAM bank, hl = pointer to start of box + ld hl, BoxSRAMPointerTable + ld a, [wCurrentBoxNum] + and $7f + cp NUM_BOXES / 2 + ld b, 2 + jr c, .next + inc b + sub NUM_BOXES / 2 +.next + ld e, a + ld d, 0 + add hl, de + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a + ret + +BoxSRAMPointerTable: + dw sBox1 ; sBox7 + dw sBox2 ; sBox8 + dw sBox3 ; sBox9 + dw sBox4 ; sBox10 + dw sBox5 ; sBox11 + dw sBox6 ; sBox12 + +ChangeBox:: + ld hl, WhenYouChangeBoxText + call PrintText + call YesNoChoice + ld a, [wCurrentMenuItem] + and a + ret nz ; return if No was chosen + ld hl, wCurrentBoxNum + bit 7, [hl] ; is it the first time player is changing the box? + call z, EmptyAllSRAMBoxes ; if so, empty all boxes in SRAM + call DisplayChangeBoxMenu + call UpdateSprites + ld hl, hFlags_0xFFF6 + set 1, [hl] + call HandleMenuInput + ld hl, hFlags_0xFFF6 + res 1, [hl] + bit 1, a ; pressed b + ret nz + call GetBoxSRAMLocation + ld e, l + ld d, h + ld hl, wBoxDataStart + call CopyBoxToOrFromSRAM ; copy old box from WRAM to SRAM + ld a, [wCurrentMenuItem] + set 7, a + ld [wCurrentBoxNum], a + call GetBoxSRAMLocation + ld de, wBoxDataStart + call CopyBoxToOrFromSRAM ; copy new box from SRAM to WRAM + ld hl, wMapTextPtr + ld de, wChangeBoxSavedMapTextPointer + ld a, [hli] + ld [de], a + inc de + ld a, [hl] + ld [de], a + call RestoreMapTextPointer + call SaveSAVtoSRAM + ld hl, wChangeBoxSavedMapTextPointer + call SetMapTextPointer + ld a, SFX_SAVE + call PlaySoundWaitForCurrent + call WaitForSoundToFinish + ret + +WhenYouChangeBoxText: + TX_FAR _WhenYouChangeBoxText + db "@" + +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 + ld a, b + ld [MBC1SRamBank], a + ld bc, wBoxDataEnd - wBoxDataStart + call CopyData + pop hl + +; mark the memory that the box was copied from as am empty box + xor a + ld [hli], a + dec a + ld [hl], a + + ld hl, sBox1 ; sBox7 + ld bc, sBank2AllBoxesChecksum - sBox1 + call SAVCheckSum + ld [sBank2AllBoxesChecksum], a ; sBank3AllBoxesChecksum + call CalcIndividualBoxCheckSums + xor a + ld [MBC1SRamBankingMode], a + ld [MBC1SRamEnable], a + ret + +DisplayChangeBoxMenu: + xor a + ld [H_AUTOBGTRANSFERENABLED], a + ld a, A_BUTTON | B_BUTTON + ld [wMenuWatchedKeys], a + ld a, 11 + ld [wMaxMenuItem], a + ld a, 1 + ld [wTopMenuItemY], a + ld a, 12 + ld [wTopMenuItemX], a + xor a + ld [wMenuWatchMovingOutOfBounds], a + ld a, [wCurrentBoxNum] + and $7f + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + coord hl, 0, 0 + ld b, 2 + ld c, 9 + call TextBoxBorder + ld hl, ChooseABoxText + call PrintText + coord hl, 11, 0 + ld b, 12 + ld c, 7 + call TextBoxBorder + ld hl, hFlags_0xFFF6 + set 2, [hl] + ld de, BoxNames + coord hl, 13, 1 + call PlaceString + ld hl, hFlags_0xFFF6 + res 2, [hl] + ld a, [wCurrentBoxNum] + and $7f + cp 9 + jr c, .singleDigitBoxNum + sub 9 + coord hl, 8, 2 + ld [hl], "1" + add "0" + jr .next +.singleDigitBoxNum + add "1" +.next + Coorda 9, 2 + coord hl, 1, 2 + ld de, BoxNoText + call PlaceString + call GetMonCountsForAllBoxes + coord hl, 18, 1 + ld de, wBoxMonCounts + ld bc, SCREEN_WIDTH + ld a, $c +.loop + push af + ld a, [de] + and a ; is the box empty? + jr z, .skipPlacingPokeball + ld [hl], $78 ; place pokeball tile next to box name if box not empty +.skipPlacingPokeball + add hl, bc + inc de + pop af + dec a + jr nz, .loop + ld a, 1 + ld [H_AUTOBGTRANSFERENABLED], a + ret + +ChooseABoxText: + TX_FAR _ChooseABoxText + db "@" + +BoxNames: + db "BOX 1" + next "BOX 2" + next "BOX 3" + next "BOX 4" + next "BOX 5" + next "BOX 6" + next "BOX 7" + next "BOX 8" + next "BOX 9" + next "BOX10" + next "BOX11" + next "BOX12@" + +BoxNoText: + db "BOX No.@" + +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 + ld a, 2 + ld [MBC1SRamBank], a + call EmptySRAMBoxesInBank + ld a, 3 + ld [MBC1SRamBank], a + call EmptySRAMBoxesInBank + xor a + ld [MBC1SRamBankingMode], a + ld [MBC1SRamEnable], a + ret + +EmptySRAMBoxesInBank: +; marks every box in the current SRAM bank as empty + ld hl, sBox1 ; sBox7 + call EmptySRAMBox + ld hl, sBox2 ; sBox8 + call EmptySRAMBox + ld hl, sBox3 ; sBox9 + call EmptySRAMBox + ld hl, sBox4 ; sBox10 + call EmptySRAMBox + ld hl, sBox5 ; sBox11 + call EmptySRAMBox + ld hl, sBox6 ; sBox12 + call EmptySRAMBox + ld hl, sBox1 ; sBox7 + ld bc, sBank2AllBoxesChecksum - sBox1 + call SAVCheckSum + ld [sBank2AllBoxesChecksum], a ; sBank3AllBoxesChecksum + call CalcIndividualBoxCheckSums + ret + +EmptySRAMBox: + xor a + ld [hli], a + dec a + ld [hl], a + ret + +GetMonCountsForAllBoxes: + ld hl, wBoxMonCounts + push hl + ld a, SRAM_ENABLE + ld [MBC1SRamEnable], a + ld a, $1 + ld [MBC1SRamBankingMode], a + ld a, $2 + ld [MBC1SRamBank], a + call GetMonCountsForBoxesInBank + ld a, $3 + ld [MBC1SRamBank], a + call GetMonCountsForBoxesInBank + xor a + ld [MBC1SRamBankingMode], a + ld [MBC1SRamEnable], a + pop hl + +; copy the count for the current box from WRAM + ld a, [wCurrentBoxNum] + and $7f + ld c, a + ld b, 0 + add hl, bc + ld a, [wNumInBox] + ld [hl], a + + ret + +GetMonCountsForBoxesInBank: + ld a, [sBox1] ; sBox7 + ld [hli], a + ld a, [sBox2] ; sBox8 + ld [hli], a + ld a, [sBox3] ; sBox9 + ld [hli], a + ld a, [sBox4] ; sBox10 + ld [hli], a + ld a, [sBox5] ; sBox11 + ld [hli], a + ld a, [sBox6] ; sBox12 + ld [hli], a + ret + +SAVCheckRandomID: +;checks if Sav file is the same by checking player's name 1st letter ($a598) +; and the two random numbers generated at game beginning +;(which are stored at wPlayerID)s + ld a, $0a + ld [MBC1SRamEnable], a + ld a, $01 + ld [MBC1SRamBankingMode], a + ld [MBC1SRamBank], a + ld a, [sPlayerName] + and a + jr z, .next + ld hl, sPlayerName + ld bc, sMainDataCheckSum - sPlayerName + call SAVCheckSum + ld c, a + ld a, [sMainDataCheckSum] + cp c + jr nz, .next + ld hl, sMainData + (wPlayerID - wMainDataStart) ; player ID + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wPlayerID] + cp l + jr nz, .next + ld a, [wPlayerID + 1] + cp h +.next + ld a, $00 + ld [MBC1SRamBankingMode], a + ld [MBC1SRamEnable], a + ret + +SaveHallOfFameTeams: + ld a, [wNumHoFTeams] + dec a + cp HOF_TEAM_CAPACITY + jr nc, .shiftHOFTeams + ld hl, sHallOfFame + ld bc, HOF_TEAM + call AddNTimes + ld e, l + ld d, h + ld hl, wHallOfFame + ld bc, HOF_TEAM + jr HallOfFame_Copy + +.shiftHOFTeams +; if the space designated for HOF teams is full, then shift all HOF teams to the next slot, making space for the new HOF team +; this deletes the last HOF team though + ld hl, sHallOfFame + HOF_TEAM + ld de, sHallOfFame + ld bc, HOF_TEAM * (HOF_TEAM_CAPACITY - 1) + call HallOfFame_Copy + ld hl, wHallOfFame + ld de, sHallOfFame + HOF_TEAM * (HOF_TEAM_CAPACITY - 1) + ld bc, HOF_TEAM + jr HallOfFame_Copy + +LoadHallOfFameTeams: + ld hl, sHallOfFame + ld bc, HOF_TEAM + ld a, [wHoFTeamIndex] + call AddNTimes + ld de, wHallOfFame + ld bc, HOF_TEAM + ; fallthrough + +HallOfFame_Copy: + ld a, SRAM_ENABLE + ld [MBC1SRamEnable], a + ld a, $1 + ld [MBC1SRamBankingMode], a + xor a + ld [MBC1SRamBank], a + call CopyData + xor a + ld [MBC1SRamBankingMode], a + ld [MBC1SRamEnable], a + 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 PadSRAM_FF + xor a + ld [MBC1SRamBankingMode], a + ld [MBC1SRamEnable], a + ret + +PadSRAM_FF: + ld [MBC1SRamBank], a + ld hl, $a000 + ld bc, $2000 + ld a, $ff + jp FillMemory diff --git a/engine/menus/start_sub_menus.asm b/engine/menus/start_sub_menus.asm new file mode 100755 index 00000000..b81769a2 --- /dev/null +++ b/engine/menus/start_sub_menus.asm @@ -0,0 +1,808 @@ +StartMenu_Pokedex:: + predef ShowPokedexMenu + call LoadScreenTilesFromBuffer2 ; restore saved screen + call Delay3 + call LoadGBPal + call UpdateSprites + jp RedisplayStartMenu + +StartMenu_Pokemon:: + ld a, [wPartyCount] + and a + jp z, RedisplayStartMenu + xor a + ld [wMenuItemToSwap], a + ld [wPartyMenuTypeOrMessageID], a + ld [wUpdateSpritesEnabled], a + call DisplayPartyMenu + jr .checkIfPokemonChosen +.loop + xor a + ld [wMenuItemToSwap], a + ld [wPartyMenuTypeOrMessageID], a + call GoBackToPartyMenu +.checkIfPokemonChosen + jr nc, .chosePokemon +.exitMenu + call GBPalWhiteOutWithDelay3 + call RestoreScreenTilesAndReloadTilePatterns + call LoadGBPal + jp RedisplayStartMenu +.chosePokemon + call SaveScreenTilesToBuffer1 + ld a, FIELD_MOVE_MON_MENU + ld [wTextBoxID], a + call DisplayTextBoxID ; display pokemon menu options + ld hl, wFieldMoves + lb bc, 2, 12 ; max menu item ID, top menu item Y + ld e, 5 +.adjustMenuVariablesLoop + dec e + jr z, .storeMenuVariables + ld a, [hli] + and a ; end of field moves? + jr z, .storeMenuVariables + inc b + dec c + dec c + jr .adjustMenuVariablesLoop +.storeMenuVariables + ld hl, wTopMenuItemY + ld a, c + ld [hli], a ; top menu item Y + ld a, [hFieldMoveMonMenuTopMenuItemX] + ld [hli], a ; top menu item X + xor a + ld [hli], a ; current menu item ID + inc hl + ld a, b + ld [hli], a ; max menu item ID + ld a, A_BUTTON | B_BUTTON + ld [hli], a ; menu watched keys + xor a + ld [hl], a + call HandleMenuInput + push af + call LoadScreenTilesFromBuffer1 ; restore saved screen + pop af + bit 1, a ; was the B button pressed? + jp nz, .loop +; if the B button wasn't pressed + ld a, [wMaxMenuItem] + ld b, a + ld a, [wCurrentMenuItem] ; menu selection + cp b + jp z, .exitMenu ; if the player chose Cancel + dec b + cp b + jr z, .choseSwitch + dec b + cp b + jp z, .choseStats + ld c, a + ld b, 0 + ld hl, wFieldMoves + add hl, bc + jp .choseOutOfBattleMove +.choseSwitch + ld a, [wPartyCount] + cp 2 ; is there more than one pokemon in the party? + jp c, StartMenu_Pokemon ; if not, no switching + call SwitchPartyMon_InitVarOrSwapData ; init [wMenuItemToSwap] + ld a, SWAP_MONS_PARTY_MENU + ld [wPartyMenuTypeOrMessageID], a + call GoBackToPartyMenu + jp .checkIfPokemonChosen +.choseStats + call ClearSprites + xor a ; PLAYER_PARTY_DATA + ld [wMonDataLocation], a + predef StatusScreen + predef StatusScreen2 + call ReloadMapData + jp StartMenu_Pokemon +.choseOutOfBattleMove + push hl + ld a, [wWhichPokemon] + ld hl, wPartyMonNicks + call GetPartyMonName + pop hl + ld a, [hl] + dec a + add a + ld b, 0 + ld c, a + ld hl, .outOfBattleMovePointers + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wObtainedBadges] ; badges obtained + jp hl +.outOfBattleMovePointers + dw .cut + dw .fly + dw .surf + dw .surf + dw .strength + dw .flash + dw .dig + dw .teleport + dw .softboiled +.fly + bit 2, a ; does the player have the Thunder Badge? + jp z, .newBadgeRequired + call CheckIfInOutsideMap + jr z, .canFly + ld a, [wWhichPokemon] + ld hl, wPartyMonNicks + call GetPartyMonName + ld hl, .cannotFlyHereText + call PrintText + jp .loop +.canFly + call ChooseFlyDestination + ld a, [wd732] + bit 3, a ; did the player decide to fly? + jp nz, .goBackToMap + call LoadFontTilePatterns + ld hl, wd72e + set 1, [hl] + jp StartMenu_Pokemon +.cut + bit 1, a ; does the player have the Cascade Badge? + jp z, .newBadgeRequired + predef UsedCut + ld a, [wActionResultOrTookBattleTurn] + and a + jp z, .loop + jp CloseTextDisplay +.surf + bit 4, a ; does the player have the Soul Badge? + jp z, .newBadgeRequired + callba IsSurfingAllowed + ld hl, wd728 + bit 1, [hl] + res 1, [hl] + jp z, .loop + ld a, SURFBOARD + ld [wcf91], a + ld [wPseudoItemID], a + call UseItem + ld a, [wActionResultOrTookBattleTurn] + and a + jp z, .loop + call GBPalWhiteOutWithDelay3 + jp .goBackToMap +.strength + bit 3, a ; does the player have the Rainbow Badge? + jp z, .newBadgeRequired + predef PrintStrengthTxt + call GBPalWhiteOutWithDelay3 + jp .goBackToMap +.flash + bit 0, a ; does the player have the Boulder Badge? + jp z, .newBadgeRequired + xor a + ld [wMapPalOffset], a + ld hl, .flashLightsAreaText + call PrintText + call GBPalWhiteOutWithDelay3 + jp .goBackToMap +.flashLightsAreaText + TX_FAR _FlashLightsAreaText + db "@" +.dig + ld a, ESCAPE_ROPE + ld [wcf91], a + ld [wPseudoItemID], a + call UseItem + ld a, [wActionResultOrTookBattleTurn] + and a + jp z, .loop + call GBPalWhiteOutWithDelay3 + jp .goBackToMap +.teleport + call CheckIfInOutsideMap + jr z, .canTeleport + ld a, [wWhichPokemon] + ld hl, wPartyMonNicks + call GetPartyMonName + ld hl, .cannotUseTeleportNowText + call PrintText + jp .loop +.canTeleport + ld hl, .warpToLastPokemonCenterText + call PrintText + ld hl, wd732 + set 3, [hl] + set 6, [hl] + ld hl, wd72e + set 1, [hl] + res 4, [hl] + ld c, 60 + call DelayFrames + call GBPalWhiteOutWithDelay3 + jp .goBackToMap +.warpToLastPokemonCenterText + TX_FAR _WarpToLastPokemonCenterText + db "@" +.cannotUseTeleportNowText + TX_FAR _CannotUseTeleportNowText + db "@" +.cannotFlyHereText + TX_FAR _CannotFlyHereText + db "@" +.softboiled + ld hl, wPartyMon1MaxHP + ld a, [wWhichPokemon] + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld a, [hli] + ld [H_DIVIDEND], a + ld a, [hl] + ld [H_DIVIDEND + 1], a + ld a, 5 + ld [H_DIVISOR], a + ld b, 2 ; number of bytes + call Divide + ld bc, wPartyMon1HP - wPartyMon1MaxHP + add hl, bc + ld a, [hld] + ld b, a + ld a, [H_QUOTIENT + 3] + sub b + ld b, [hl] + ld a, [H_QUOTIENT + 2] + sbc b + jp nc, .notHealthyEnough + ld a, [wPartyAndBillsPCSavedMenuItem] + push af + ld a, POTION + ld [wcf91], a + ld [wPseudoItemID], a + call UseItem + pop af + ld [wPartyAndBillsPCSavedMenuItem], a + jp .loop +.notHealthyEnough ; if current HP is less than 1/5 of max HP + ld hl, .notHealthyEnoughText + call PrintText + jp .loop +.notHealthyEnoughText + TX_FAR _NotHealthyEnoughText + db "@" +.goBackToMap + call RestoreScreenTilesAndReloadTilePatterns + jp CloseTextDisplay +.newBadgeRequired + ld hl, .newBadgeRequiredText + call PrintText + jp .loop +.newBadgeRequiredText + TX_FAR _NewBadgeRequiredText + db "@" + +; writes a blank tile to all possible menu cursor positions on the party menu +ErasePartyMenuCursors:: + coord hl, 0, 1 + ld bc, 2 * 20 ; menu cursor positions are 2 rows apart + ld a, 6 ; 6 menu cursor positions +.loop + ld [hl], " " + add hl, bc + dec a + jr nz, .loop + ret + +ItemMenuLoop: + call LoadScreenTilesFromBuffer2DisableBGTransfer ; restore saved screen + call RunDefaultPaletteCommand + +StartMenu_Item:: + ld a, [wLinkState] + dec a ; is the player in the Colosseum or Trade Centre? + jr nz, .notInCableClubRoom + ld hl, CannotUseItemsHereText + 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) + xor a + ld [wPrintItemPrices], a + ld a, ITEMLISTMENU + ld [wListMenuID], a + ld a, [wBagSavedMenuItem] + ld [wCurrentMenuItem], a + call DisplayListMenuID + ld a, [wCurrentMenuItem] + ld [wBagSavedMenuItem], a + jr nc, .choseItem +.exitMenu + call LoadScreenTilesFromBuffer2 ; restore saved screen + call LoadTextBoxTilePatterns + call UpdateSprites + jp RedisplayStartMenu +.choseItem +; erase menu cursor (blank each tile in front of an item name) + ld a, " " + Coorda 5, 4 + Coorda 5, 6 + Coorda 5, 8 + Coorda 5, 10 + call PlaceUnfilledArrowMenuCursor + xor a + ld [wMenuItemToSwap], a + ld a, [wcf91] + cp BICYCLE + jp z, .useOrTossItem +.notBicycle1 + ld a, USE_TOSS_MENU_TEMPLATE + ld [wTextBoxID], a + call DisplayTextBoxID + ld hl, wTopMenuItemY + ld a, 11 + ld [hli], a ; top menu item Y + ld a, 14 + ld [hli], a ; top menu item X + xor a + ld [hli], a ; current menu item ID + inc hl + inc a ; a = 1 + ld [hli], a ; max menu item ID + ld a, A_BUTTON | B_BUTTON + ld [hli], a ; menu watched keys + xor a + ld [hl], a ; old menu item id + call HandleMenuInput + call PlaceUnfilledArrowMenuCursor + bit 1, a ; was the B button pressed? + jr z, .useOrTossItem + jp ItemMenuLoop +.useOrTossItem ; if the player made the choice to use or toss the item + ld a, [wcf91] + ld [wd11e], a + call GetItemName + call CopyStringToCF4B ; copy name to wcf4b + ld a, [wcf91] + cp BICYCLE + jr nz, .notBicycle2 + ld a, [wd732] + bit 5, a + jr z, .useItem_closeMenu + ld hl, CannotGetOffHereText + call PrintText + jp ItemMenuLoop +.notBicycle2 + ld a, [wCurrentMenuItem] + and a + jr nz, .tossItem +; use item + ld [wPseudoItemID], a ; a must be 0 due to above conditional jump + ld a, [wcf91] + cp HM_01 + jr nc, .useItem_partyMenu + ld hl, UsableItems_CloseMenu + ld de, 1 + call IsInArray + jr c, .useItem_closeMenu + ld a, [wcf91] + ld hl, UsableItems_PartyMenu + ld de, 1 + call IsInArray + jr c, .useItem_partyMenu + call UseItem + jp ItemMenuLoop +.useItem_closeMenu + xor a + ld [wPseudoItemID], a + call UseItem + ld a, [wActionResultOrTookBattleTurn] + and a + jp z, ItemMenuLoop + jp CloseStartMenu +.useItem_partyMenu + ld a, [wUpdateSpritesEnabled] + push af + call UseItem + ld a, [wActionResultOrTookBattleTurn] + cp $02 + jp z, .partyMenuNotDisplayed + call GBPalWhiteOutWithDelay3 + call RestoreScreenTilesAndReloadTilePatterns + pop af + ld [wUpdateSpritesEnabled], a + jp StartMenu_Item +.partyMenuNotDisplayed + pop af + ld [wUpdateSpritesEnabled], a + jp ItemMenuLoop +.tossItem + call IsKeyItem + ld a, [wIsKeyItem] + and a + jr nz, .skipAskingQuantity + ld a, [wcf91] + call IsItemHM + jr c, .skipAskingQuantity + call DisplayChooseQuantityMenu + inc a + jr z, .tossZeroItems +.skipAskingQuantity + ld hl, wNumBagItems + call TossItem +.tossZeroItems + jp ItemMenuLoop + +CannotUseItemsHereText: + TX_FAR _CannotUseItemsHereText + db "@" + +CannotGetOffHereText: + TX_FAR _CannotGetOffHereText + db "@" + +INCLUDE "data/party_items.asm" + +INCLUDE "data/overworld_items.asm" + +StartMenu_TrainerInfo:: + call GBPalWhiteOut + call ClearScreen + call UpdateSprites + ld a, [hTilesetType] + push af + xor a + ld [hTilesetType], a + call DrawTrainerInfo + predef DrawBadges ; draw badges + ld b, SET_PAL_TRAINER_CARD + call RunPaletteCommand + call GBPalNormal + call WaitForTextScrollButtonPress ; wait for button press + call GBPalWhiteOut + call LoadFontTilePatterns + call LoadScreenTilesFromBuffer2 ; restore saved screen + call RunDefaultPaletteCommand + call ReloadMapData + call LoadGBPal + pop af + ld [hTilesetType], a + jp RedisplayStartMenu + +; loads tile patterns and draws everything except for gym leader faces / badges +DrawTrainerInfo: + ld de, RedPicFront + lb bc, BANK(RedPicFront), $01 + predef DisplayPicCenteredOrUpperRight + call DisableLCD + coord hl, 0, 2 + ld a, " " + call TrainerInfo_DrawVerticalLine + coord hl, 1, 2 + call TrainerInfo_DrawVerticalLine + ld hl, vChars2 + $70 + ld de, vChars2 + ld bc, $70 * 4 + call CopyData + ld hl, TrainerInfoTextBoxTileGraphics ; trainer info text box tile patterns + ld de, vChars2 + $770 + ld bc, $0080 + push bc + call TrainerInfo_FarCopyData + ld hl, BlankLeaderNames + ld de, vChars2 + $600 + ld bc, $0170 + call TrainerInfo_FarCopyData + pop bc + ld hl, BadgeNumbersTileGraphics ; badge number tile patterns + ld de, vChars1 + $580 + call TrainerInfo_FarCopyData + ld hl, GymLeaderFaceAndBadgeTileGraphics ; gym leader face and badge tile patterns + ld de, vChars2 + $200 + ld bc, $0400 + ld a, $03 + call FarCopyData2 + ld hl, TextBoxGraphics + ld de, $00d0 + add hl, de ; hl = colon tile pattern + ld de, vChars1 + $560 + ld bc, $0010 + ld a, $04 + push bc + call FarCopyData2 + pop bc + ld hl, TrainerInfoTextBoxTileGraphics + $80 ; background tile pattern + ld de, vChars1 + $570 + call TrainerInfo_FarCopyData + call EnableLCD + ld hl, wTrainerInfoTextBoxWidthPlus1 + ld a, 18 + 1 + ld [hli], a + dec a + ld [hli], a + ld [hl], 1 + coord hl, 0, 0 + call TrainerInfo_DrawTextBox + ld hl, wTrainerInfoTextBoxWidthPlus1 + ld a, 16 + 1 + ld [hli], a + dec a + ld [hli], a + ld [hl], 3 + coord hl, 1, 10 + call TrainerInfo_DrawTextBox + coord hl, 0, 10 + ld a, $d7 + call TrainerInfo_DrawVerticalLine + coord hl, 19, 10 + call TrainerInfo_DrawVerticalLine + coord hl, 6, 9 + ld de, TrainerInfo_BadgesText + call PlaceString + coord hl, 2, 2 + ld de, TrainerInfo_NameMoneyTimeText + call PlaceString + coord hl, 7, 2 + ld de, wPlayerName + call PlaceString + coord hl, 8, 4 + ld de, wPlayerMoney + ld c, $e3 + call PrintBCDNumber + coord hl, 9, 6 + ld de, wPlayTimeHours ; hours + lb bc, LEFT_ALIGN | 1, 3 + call PrintNumber + ld [hl], $d6 ; colon tile ID + inc hl + ld de, wPlayTimeMinutes ; minutes + lb bc, LEADING_ZEROES | 1, 2 + jp PrintNumber + +TrainerInfo_FarCopyData: + ld a, BANK(TrainerInfoTextBoxTileGraphics) + jp FarCopyData2 + +TrainerInfo_NameMoneyTimeText: + db "NAME/" + next "MONEY/" + next "TIME/@" + +; $76 is a circle tile +TrainerInfo_BadgesText: + db $76,"BADGES",$76,"@" + +; draws a text box on the trainer info screen +; height is always 6 +; INPUT: +; hl = destination address +; [wTrainerInfoTextBoxWidthPlus1] = width +; [wTrainerInfoTextBoxWidth] = width - 1 +; [wTrainerInfoTextBoxNextRowOffset] = distance from the end of a text box row to the start of the next +TrainerInfo_DrawTextBox: + ld a, $79 ; upper left corner tile ID + lb de, $7a, $7b ; top edge and upper right corner tile ID's + call TrainerInfo_DrawHorizontalEdge ; draw top edge + call TrainerInfo_NextTextBoxRow + ld a, [wTrainerInfoTextBoxWidthPlus1] + ld e, a + ld d, 0 + ld c, 6 ; height of the text box +.loop + ld [hl], $7c ; left edge tile ID + add hl, de + ld [hl], $78 ; right edge tile ID + call TrainerInfo_NextTextBoxRow + dec c + jr nz, .loop + ld a, $7d ; lower left corner tile ID + lb de, $77, $7e ; bottom edge and lower right corner tile ID's + +TrainerInfo_DrawHorizontalEdge: + ld [hli], a ; place left corner tile + ld a, [wTrainerInfoTextBoxWidth] + ld c, a + ld a, d +.loop + ld [hli], a ; place edge tile + dec c + jr nz, .loop + ld a, e + ld [hl], a ; place right corner tile + ret + +TrainerInfo_NextTextBoxRow: + ld a, [wTrainerInfoTextBoxNextRowOffset] ; distance to the start of the next row +.loop + inc hl + dec a + jr nz, .loop + ret + +; draws a vertical line +; INPUT: +; hl = address of top tile in the line +; a = tile ID +TrainerInfo_DrawVerticalLine: + ld de, SCREEN_WIDTH + ld c, 8 +.loop + ld [hl], a + add hl, de + dec c + jr nz, .loop + ret + +StartMenu_SaveReset:: + ld a, [wd72e] + bit 6, a ; is the player using the link feature? + jp nz, Init + predef SaveSAV ; save the game + call LoadScreenTilesFromBuffer2 ; restore saved screen + jp HoldTextDisplayOpen + +StartMenu_Option:: + xor a + ld [H_AUTOBGTRANSFERENABLED], a + call ClearScreen + call UpdateSprites + callab DisplayOptionMenu + call LoadScreenTilesFromBuffer2 ; restore saved screen + call LoadTextBoxTilePatterns + call UpdateSprites + jp RedisplayStartMenu + +SwitchPartyMon:: + call SwitchPartyMon_InitVarOrSwapData ; swap data + ld a, [wSwappedMenuItem] + call SwitchPartyMon_ClearGfx + ld a, [wCurrentMenuItem] + call SwitchPartyMon_ClearGfx + jp RedrawPartyMenu_ + +SwitchPartyMon_ClearGfx: + push af + coord hl, 0, 0 + ld bc, SCREEN_WIDTH * 2 + call AddNTimes + ld c, SCREEN_WIDTH * 2 + ld a, " " +.clearMonBGLoop ; clear the mon's row in the party menu + ld [hli], a + dec c + jr nz, .clearMonBGLoop + pop af + ld hl, wOAMBuffer + ld bc, $10 + call AddNTimes + ld de, $4 + ld c, e +.clearMonOAMLoop + ld [hl], $a0 + add hl, de + dec c + jr nz, .clearMonOAMLoop + call WaitForSoundToFinish + ld a, SFX_SWAP + jp PlaySound + +SwitchPartyMon_InitVarOrSwapData: +; This is used to initialise [wMenuItemToSwap] and to actually swap the data. + ld a, [wMenuItemToSwap] + and a ; has [wMenuItemToSwap] been initialised yet? + jr nz, .pickedMonsToSwap +; If not, initialise [wMenuItemToSwap] so that it matches the current mon. + ld a, [wWhichPokemon] + inc a ; [wMenuItemToSwap] counts from 1 + ld [wMenuItemToSwap], a + ret +.pickedMonsToSwap + xor a + ld [wPartyMenuTypeOrMessageID], a + ld a, [wMenuItemToSwap] + dec a + ld b, a + ld a, [wCurrentMenuItem] + ld [wSwappedMenuItem], a + cp b ; swapping a mon with itself? + jr nz, .swappingDifferentMons +; can't swap a mon with itself + xor a + ld [wMenuItemToSwap], a + ld [wPartyMenuTypeOrMessageID], a + ret +.swappingDifferentMons + ld a, b + ld [wMenuItemToSwap], a + push hl + push de + ld hl, wPartySpecies + ld d, h + ld e, l + ld a, [wCurrentMenuItem] + add l + ld l, a + jr nc, .noCarry + inc h +.noCarry + ld a, [wMenuItemToSwap] + add e + ld e, a + jr nc, .noCarry2 + inc d +.noCarry2 + ld a, [hl] + ld [hSwapTemp], a + ld a, [de] + ld [hl], a + ld a, [hSwapTemp] + ld [de], a + ld hl, wPartyMons + ld bc, wPartyMon2 - wPartyMon1 + ld a, [wCurrentMenuItem] + call AddNTimes + push hl + ld de, wSwitchPartyMonTempBuffer + ld bc, wPartyMon2 - wPartyMon1 + call CopyData + ld hl, wPartyMons + ld bc, wPartyMon2 - wPartyMon1 + ld a, [wMenuItemToSwap] + call AddNTimes + pop de + push hl + ld bc, wPartyMon2 - wPartyMon1 + call CopyData + pop de + ld hl, wSwitchPartyMonTempBuffer + ld bc, wPartyMon2 - wPartyMon1 + call CopyData + ld hl, wPartyMonOT + ld a, [wCurrentMenuItem] + call SkipFixedLengthTextEntries + push hl + ld de, wSwitchPartyMonTempBuffer + ld bc, NAME_LENGTH + call CopyData + ld hl, wPartyMonOT + ld a, [wMenuItemToSwap] + call SkipFixedLengthTextEntries + pop de + push hl + ld bc, NAME_LENGTH + call CopyData + pop de + ld hl, wSwitchPartyMonTempBuffer + ld bc, NAME_LENGTH + call CopyData + ld hl, wPartyMonNicks + ld a, [wCurrentMenuItem] + call SkipFixedLengthTextEntries + push hl + ld de, wSwitchPartyMonTempBuffer + ld bc, NAME_LENGTH + call CopyData + ld hl, wPartyMonNicks + ld a, [wMenuItemToSwap] + call SkipFixedLengthTextEntries + pop de + push hl + ld bc, NAME_LENGTH + call CopyData + pop de + ld hl, wSwitchPartyMonTempBuffer + ld bc, NAME_LENGTH + call CopyData + ld a, [wMenuItemToSwap] + ld [wSwappedMenuItem], a + xor a + ld [wMenuItemToSwap], a + ld [wPartyMenuTypeOrMessageID], a + pop de + pop hl + ret diff --git a/engine/menus/swap_items.asm b/engine/menus/swap_items.asm new file mode 100644 index 00000000..826fe60b --- /dev/null +++ b/engine/menus/swap_items.asm @@ -0,0 +1,149 @@ +HandleItemListSwapping:: + ld a, [wListMenuID] + cp ITEMLISTMENU + jp nz, DisplayListMenuIDLoop ; only rearrange item list menus + push hl + ld hl, wListPointer + ld a, [hli] + ld h, [hl] + ld l, a + inc hl ; hl = beginning of list entries + ld a, [wCurrentMenuItem] + ld b, a + ld a, [wListScrollOffset] + add b + add a + ld c, a + ld b, 0 + add hl, bc ; hl = address of currently selected item entry + ld a, [hl] + pop hl + inc a + jp z, DisplayListMenuIDLoop ; ignore attempts to swap the Cancel menu item + ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1) + and a ; has the first item to swap already been chosen? + jr nz, .swapItems +; if not, set the currently selected item as the first item + ld a, [wCurrentMenuItem] + inc a + ld b, a + ld a, [wListScrollOffset] ; index of top (visible) menu item within the list + add b + ld [wMenuItemToSwap], a ; ID of item chosen for swapping (counts from 1) + ld c, 20 + call DelayFrames + jp DisplayListMenuIDLoop +.swapItems + ld a, [wCurrentMenuItem] + inc a + ld b, a + ld a, [wListScrollOffset] + add b + ld b, a + ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1) + cp b ; is the currently selected item the same as the first item to swap? + jp z, DisplayListMenuIDLoop ; ignore attempts to swap an item with itself + dec a + ld [wMenuItemToSwap], a ; ID of item chosen for swapping (counts from 1) + ld c, 20 + call DelayFrames + push hl + push de + ld hl, wListPointer + ld a, [hli] + ld h, [hl] + ld l, a + inc hl ; hl = beginning of list entries + ld d, h + ld e, l ; de = beginning of list entries + ld a, [wCurrentMenuItem] + ld b, a + ld a, [wListScrollOffset] + add b + add a + ld c, a + ld b, 0 + add hl, bc ; hl = address of currently selected item entry + ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1) + add a + add e + ld e, a + jr nc, .noCarry + inc d +.noCarry ; de = address of first item to swap + ld a, [de] + ld b, a + ld a, [hli] + cp b + jr z, .swapSameItemType +.swapDifferentItems + ld [$ff95], a ; [$ff95] = second item ID + ld a, [hld] + ld [$ff96], a ; [$ff96] = second item quantity + ld a, [de] + ld [hli], a ; put first item ID in second item slot + inc de + ld a, [de] + ld [hl], a ; put first item quantity in second item slot + ld a, [$ff96] + ld [de], a ; put second item quantity in first item slot + dec de + ld a, [$ff95] + ld [de], a ; put second item ID in first item slot + xor a + ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped + pop de + pop hl + jp DisplayListMenuIDLoop +.swapSameItemType + inc de + ld a, [hl] + ld b, a + ld a, [de] + add b ; a = sum of both item quantities + cp 100 ; is the sum too big for one item slot? + jr c, .combineItemSlots +; swap enough items from the first slot to max out the second slot if they can't be combined + sub 99 + ld [de], a + ld a, 99 + ld [hl], a + jr .done +.combineItemSlots + ld [hl], a ; put the sum in the second item slot + ld hl, wListPointer + ld a, [hli] + ld h, [hl] + ld l, a + dec [hl] ; decrease the number of items + ld a, [hl] + ld [wListCount], a ; update number of items variable + cp 1 + jr nz, .skipSettingMaxMenuItemID + ld [wMaxMenuItem], a ; if the number of items is only one now, update the max menu item ID +.skipSettingMaxMenuItemID + dec de + ld h, d + ld l, e + inc hl + inc hl ; hl = address of item after first item to swap +.moveItemsUpLoop ; erase the first item slot and move up all the following item slots to fill the gap + ld a, [hli] + ld [de], a + inc de + inc a ; reached the $ff terminator? + jr z, .afterMovingItemsUp + ld a, [hli] + ld [de], a + inc de + jr .moveItemsUpLoop +.afterMovingItemsUp + xor a + ld [wListScrollOffset], a + ld [wCurrentMenuItem], a +.done + xor a + ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped + pop de + pop hl + jp DisplayListMenuIDLoop diff --git a/engine/menus/text_box.asm b/engine/menus/text_box.asm new file mode 100644 index 00000000..00045959 --- /dev/null +++ b/engine/menus/text_box.asm @@ -0,0 +1,767 @@ +; function to draw various text boxes +DisplayTextBoxID_:: + ld a, [wTextBoxID] + cp TWO_OPTION_MENU + jp z, DisplayTwoOptionMenu + ld c, a + ld hl, TextBoxFunctionTable + ld de, 3 + call SearchTextBoxTable + jr c, .functionTableMatch + ld hl, TextBoxCoordTable + ld de, 5 + call SearchTextBoxTable + jr c, .coordTableMatch + ld hl, TextBoxTextAndCoordTable + ld de, 9 + call SearchTextBoxTable + jr c, .textAndCoordTableMatch +.done + ret +.functionTableMatch + ld a, [hli] + ld h, [hl] + ld l, a ; hl = address of function + ld de, .done + push de + jp hl ; jump to the function +.coordTableMatch + call GetTextBoxIDCoords + call GetAddressOfScreenCoords + call TextBoxBorder + ret +.textAndCoordTableMatch + call GetTextBoxIDCoords + push hl + call GetAddressOfScreenCoords + call TextBoxBorder + pop hl + call GetTextBoxIDText + ld a, [wd730] + push af + ld a, [wd730] + set 6, a ; no pauses between printing each letter + ld [wd730], a + call PlaceString + pop af + ld [wd730], a + call UpdateSprites + ret + +; function to search a table terminated with $ff for a byte matching c in increments of de +; sets carry flag if a match is found and clears carry flag if not +SearchTextBoxTable: + dec de +.loop + ld a, [hli] + cp $ff + jr z, .notFound + cp c + jr z, .found + add hl, de + jr .loop +.found + scf +.notFound + ret + +; function to load coordinates from the TextBoxCoordTable or the TextBoxTextAndCoordTable +; INPUT: +; hl = address of coordinates +; OUTPUT: +; b = height +; c = width +; d = row of upper left corner +; e = column of upper left corner +GetTextBoxIDCoords: + ld a, [hli] ; column of upper left corner + ld e, a + ld a, [hli] ; row of upper left corner + ld d, a + ld a, [hli] ; column of lower right corner + sub e + dec a + ld c, a ; c = width + ld a, [hli] ; row of lower right corner + sub d + dec a + ld b, a ; b = height + ret + +; function to load a text address and text coordinates from the TextBoxTextAndCoordTable +GetTextBoxIDText: + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a ; de = address of text + push de ; save text address + ld a, [hli] + ld e, a ; column of upper left corner of text + ld a, [hl] + ld d, a ; row of upper left corner of text + call GetAddressOfScreenCoords + pop de ; restore text address + ret + +; function to point hl to the screen coordinates +; INPUT: +; d = row +; e = column +; OUTPUT: +; hl = address of upper left corner of text box +GetAddressOfScreenCoords: + push bc + coord hl, 0, 0 + ld bc, 20 +.loop ; loop to add d rows to the base address + ld a, d + and a + jr z, .addedRows + add hl, bc + dec d + jr .loop +.addedRows + pop bc + add hl, de + ret + +; Format: +; 00: text box ID +; 01-02: function address +TextBoxFunctionTable: + dbw MONEY_BOX, DisplayMoneyBox + dbw BUY_SELL_QUIT_MENU, DoBuySellQuitMenu + dbw FIELD_MOVE_MON_MENU, DisplayFieldMoveMonMenu + db $ff ; terminator + +; Format: +; 00: text box ID +; 01: column of upper left corner +; 02: row of upper left corner +; 03: column of lower right corner +; 04: row of lower right corner +TextBoxCoordTable: + db MESSAGE_BOX, 0, 12, 19, 17 + db $03, 0, 0, 19, 14 + db $07, 0, 0, 11, 6 + db LIST_MENU_BOX, 4, 2, 19, 12 + db $10, 7, 0, 19, 17 + db MON_SPRITE_POPUP, 6, 4, 14, 13 + db $ff ; terminator + +; Format: +; 00: text box ID +; 01: column of upper left corner +; 02: row of upper left corner +; 03: column of lower right corner +; 04: row of lower right corner +; 05-06: address of text +; 07: column of beginning of text +; 08: row of beginning of text +; table of window positions and corresponding text [key, start column, start row, end column, end row, text pointer [2 bytes], text column, text row] +TextBoxTextAndCoordTable: + db JP_MOCHIMONO_MENU_TEMPLATE + db 0,0,14,17 ; text box coordinates + dw JapaneseMochimonoText + db 3,0 ; text coordinates + + db USE_TOSS_MENU_TEMPLATE + db 13,10,19,14 ; text box coordinates + dw UseTossText + db 15,11 ; text coordinates + + db JP_SAVE_MESSAGE_MENU_TEMPLATE + db 0,0,7,5 ; text box coordinates + dw JapaneseSaveMessageText + db 2,2 ; text coordinates + + db JP_SPEED_OPTIONS_MENU_TEMPLATE + db 0,6,5,10 ; text box coordinates + dw JapaneseSpeedOptionsText + db 2,7 ; text coordinates + + db BATTLE_MENU_TEMPLATE + db 8,12,19,17 ; text box coordinates + dw BattleMenuText + db 10,14 ; text coordinates + + db SAFARI_BATTLE_MENU_TEMPLATE + db 0,12,19,17 ; text box coordinates + dw SafariZoneBattleMenuText + db 2,14 ; text coordinates + + db SWITCH_STATS_CANCEL_MENU_TEMPLATE + db 11,11,19,17 ; text box coordinates + dw SwitchStatsCancelText + db 13,12 ; text coordinates + + db BUY_SELL_QUIT_MENU_TEMPLATE + db 0,0,10,6 ; text box coordinates + dw BuySellQuitText + db 2,1 ; text coordinates + + db MONEY_BOX_TEMPLATE + db 11,0,19,2 ; text box coordinates + dw MoneyText + db 13,0 ; text coordinates + + db JP_AH_MENU_TEMPLATE + db 7,6,11,10 ; text box coordinates + dw JapaneseAhText + db 8,8 ; text coordinates + + db JP_POKEDEX_MENU_TEMPLATE + db 11,8,19,17 ; text box coordinates + dw JapanesePokedexMenu + db 12,10 ; text coordinates + +; note that there is no terminator + +BuySellQuitText: + db "BUY" + next "SELL" + next "QUIT@@" + +UseTossText: + db "USE" + next "TOSS@" + +JapaneseSaveMessageText: + db "きろく" + next "メッセージ@" + +JapaneseSpeedOptionsText: + db "はやい" + next "おそい@" + +MoneyText: + db "MONEY@" + +JapaneseMochimonoText: + db "もちもの@" + +JapaneseMainMenuText: + db "つづきから" + next "さいしょから@" + +BattleMenuText: + db "FIGHT ",$E1,$E2 + next "ITEM RUN@" + +SafariZoneBattleMenuText: + db "BALL× BAIT" + next "THROW ROCK RUN@" + +SwitchStatsCancelText: + db "SWITCH" + next "STATS" + next "CANCEL@" + +JapaneseAhText: + db "アッ!@" + +JapanesePokedexMenu: + db "データをみる" + next "なきごえ" + next "ぶんぷをみる" + next "キャンセル@" + +DisplayMoneyBox: + ld hl, wd730 + set 6, [hl] + ld a, MONEY_BOX_TEMPLATE + ld [wTextBoxID], a + call DisplayTextBoxID + coord hl, 13, 1 + ld b, 1 + ld c, 6 + call ClearScreenArea + coord hl, 12, 1 + ld de, wPlayerMoney + ld c, $a3 + call PrintBCDNumber + ld hl, wd730 + res 6, [hl] + ret + +CurrencyString: + db " ¥@" + +DoBuySellQuitMenu: + ld a, [wd730] + set 6, a ; no printing delay + ld [wd730], a + xor a + ld [wChosenMenuItem], a + ld a, BUY_SELL_QUIT_MENU_TEMPLATE + ld [wTextBoxID], a + call DisplayTextBoxID + ld a, A_BUTTON | B_BUTTON + ld [wMenuWatchedKeys], a + ld a, $2 + ld [wMaxMenuItem], a + ld a, $1 + ld [wTopMenuItemY], a + ld a, $1 + ld [wTopMenuItemX], a + xor a + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + ld [wMenuWatchMovingOutOfBounds], a + ld a, [wd730] + res 6, a ; turn on the printing delay + ld [wd730], a + call HandleMenuInput + call PlaceUnfilledArrowMenuCursor + bit 0, a ; was A pressed? + jr nz, .pressedA + bit 1, a ; was B pressed? (always true since only A/B are watched) + jr z, .pressedA + ld a, CANCELLED_MENU + ld [wMenuExitMethod], a + jr .quit +.pressedA + ld a, CHOSE_MENU_ITEM + ld [wMenuExitMethod], a + ld a, [wCurrentMenuItem] + ld [wChosenMenuItem], a + ld b, a + ld a, [wMaxMenuItem] + cp b + jr z, .quit + ret +.quit + ld a, CANCELLED_MENU + ld [wMenuExitMethod], a + ld a, [wCurrentMenuItem] + ld [wChosenMenuItem], a + scf + ret + +; displays a menu with two options to choose from +; b = Y of upper left corner of text region +; c = X of upper left corner of text region +; hl = address where the text box border should be drawn +DisplayTwoOptionMenu: + push hl + ld a, [wd730] + set 6, a ; no printing delay + ld [wd730], a + +; pointless because both values are overwritten before they are read + xor a + ld [wChosenMenuItem], a + ld [wMenuExitMethod], a + + ld a, A_BUTTON | B_BUTTON + ld [wMenuWatchedKeys], a + ld a, $1 + ld [wMaxMenuItem], a + ld a, b + ld [wTopMenuItemY], a + ld a, c + ld [wTopMenuItemX], a + xor a + ld [wLastMenuItem], a + ld [wMenuWatchMovingOutOfBounds], a + push hl + ld hl, wTwoOptionMenuID + bit 7, [hl] ; select second menu item by default? + res 7, [hl] + jr z, .storeCurrentMenuItem + inc a +.storeCurrentMenuItem + ld [wCurrentMenuItem], a + pop hl + push hl + push hl + call TwoOptionMenu_SaveScreenTiles + ld a, [wTwoOptionMenuID] + ld hl, TwoOptionMenuStrings + ld e, a + ld d, $0 + ld a, $5 +.menuStringLoop + add hl, de + dec a + jr nz, .menuStringLoop + ld a, [hli] + ld c, a + ld a, [hli] + ld b, a + ld e, l + ld d, h + pop hl + push de + ld a, [wTwoOptionMenuID] + cp TRADE_CANCEL_MENU + jr nz, .notTradeCancelMenu + call CableClub_TextBoxBorder + jr .afterTextBoxBorder +.notTradeCancelMenu + call TextBoxBorder +.afterTextBoxBorder + call UpdateSprites + pop hl + ld a, [hli] + and a ; put blank line before first menu item? + ld bc, 20 + 2 + jr z, .noBlankLine + ld bc, 2 * 20 + 2 +.noBlankLine + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + 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 + call HandleMenuInput + pop hl + bit 1, a ; A button pressed? + jr nz, .choseSecondMenuItem ; automatically choose the second option if B is pressed +.pressedAButton + ld a, [wCurrentMenuItem] + ld [wChosenMenuItem], a + and a + jr nz, .choseSecondMenuItem +; chose first menu item + ld a, CHOSE_FIRST_ITEM + ld [wMenuExitMethod], a + ld c, 15 + call DelayFrames + call TwoOptionMenu_RestoreScreenTiles + and a + ret +.choseSecondMenuItem + ld a, 1 + ld [wCurrentMenuItem], a + ld [wChosenMenuItem], a + ld a, CHOSE_SECOND_ITEM + ld [wMenuExitMethod], a + ld c, 15 + call DelayFrames + call TwoOptionMenu_RestoreScreenTiles + scf + ret + +; Some of the wider/taller two option menus will not have the screen areas +; they cover be fully saved/restored by the two functions below. +; The bottom and right edges of the menu may remain after the function returns. + +TwoOptionMenu_SaveScreenTiles: + ld de, wBuffer + lb bc, 5, 6 +.loop + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .loop + push bc + ld bc, SCREEN_WIDTH - 6 + add hl, bc + pop bc + ld c, $6 + dec b + jr nz, .loop + ret + +TwoOptionMenu_RestoreScreenTiles: + ld de, wBuffer + lb bc, 5, 6 +.loop + ld a, [de] + inc de + ld [hli], a + dec c + jr nz, .loop + push bc + ld bc, SCREEN_WIDTH - 6 + add hl, bc + pop bc + ld c, 6 + dec b + jr nz, .loop + call UpdateSprites + ret + +; Format: +; 00: byte width +; 01: byte height +; 02: byte put blank line before first menu item +; 03: word text pointer +TwoOptionMenuStrings: + db 4,3,0 + dw .YesNoMenu + db 6,3,0 + dw .NorthWestMenu + db 6,3,0 + dw .SouthEastMenu + db 6,3,0 + dw .YesNoMenu + db 6,3,0 + dw .NorthEastMenu + db 7,3,0 + dw .TradeCancelMenu + db 7,4,1 + dw .HealCancelMenu + db 4,3,0 + dw .NoYesMenu + +.NoYesMenu + db "NO" + next "YES@" +.YesNoMenu + db "YES" + next "NO@" +.NorthWestMenu + db "NORTH" + next "WEST@" +.SouthEastMenu + db "SOUTH" + next "EAST@" +.NorthEastMenu + db "NORTH" + next "EAST@" +.TradeCancelMenu + db "TRADE" + next "CANCEL@" +.HealCancelMenu + db "HEAL" + next "CANCEL@" + +DisplayFieldMoveMonMenu: + xor a + ld hl, wFieldMoves + ld [hli], a ; wFieldMoves + ld [hli], a ; wFieldMoves + 1 + ld [hli], a ; wFieldMoves + 2 + ld [hli], a ; wFieldMoves + 3 + ld [hli], a ; wNumFieldMoves + ld [hl], 12 ; wFieldMovesLeftmostXCoord + call GetMonFieldMoves + ld a, [wNumFieldMoves] + and a + jr nz, .fieldMovesExist + +; no field moves + coord hl, 11, 11 + ld b, 5 + ld c, 7 + call TextBoxBorder + call UpdateSprites + ld a, 12 + ld [hFieldMoveMonMenuTopMenuItemX], a + coord hl, 13, 12 + ld de, PokemonMenuEntries + jp PlaceString + +.fieldMovesExist + push af + +; Calculate the text box position and dimensions based on the leftmost X coord +; of the field move names before adjusting for the number of field moves. + coord hl, 0, 11 + ld a, [wFieldMovesLeftmostXCoord] + dec a + ld e, a + ld d, 0 + add hl, de + ld b, 5 + ld a, 18 + sub e + ld c, a + pop af + +; For each field move, move the top of the text box up 2 rows while the leaving +; the bottom of the text box at the bottom of the screen. + ld de, -SCREEN_WIDTH * 2 +.textBoxHeightLoop + add hl, de + inc b + inc b + dec a + jr nz, .textBoxHeightLoop + +; Make space for an extra blank row above the top field move. + ld de, -SCREEN_WIDTH + add hl, de + inc b + + call TextBoxBorder + call UpdateSprites + +; Calculate the position of the first field move name to print. + coord hl, 0, 12 + ld a, [wFieldMovesLeftmostXCoord] + inc a + ld e, a + ld d, 0 + add hl, de + ld de, -SCREEN_WIDTH * 2 + ld a, [wNumFieldMoves] +.calcFirstFieldMoveYLoop + add hl, de + dec a + jr nz, .calcFirstFieldMoveYLoop + + xor a + ld [wNumFieldMoves], a + ld de, wFieldMoves +.printNamesLoop + push hl + ld hl, FieldMoveNames + ld a, [de] + and a + jr z, .donePrintingNames + inc de + ld b, a ; index of name +.skipNamesLoop ; skip past names before the name we want + dec b + jr z, .reachedName +.skipNameLoop ; skip past current name + ld a, [hli] + cp "@" + jr nz, .skipNameLoop + jr .skipNamesLoop +.reachedName + ld b, h + ld c, l + pop hl + push de + ld d, b + ld e, c + call PlaceString + ld bc, SCREEN_WIDTH * 2 + add hl, bc + pop de + jr .printNamesLoop + +.donePrintingNames + pop hl + ld a, [wFieldMovesLeftmostXCoord] + ld [hFieldMoveMonMenuTopMenuItemX], a + coord hl, 0, 12 + ld a, [wFieldMovesLeftmostXCoord] + inc a + ld e, a + ld d, 0 + add hl, de + ld de, PokemonMenuEntries + jp PlaceString + +FieldMoveNames: + db "CUT@" + db "FLY@" + db "@" + db "SURF@" + db "STRENGTH@" + db "FLASH@" + db "DIG@" + db "TELEPORT@" + db "SOFTBOILED@" + +PokemonMenuEntries: + db "STATS" + next "SWITCH" + next "CANCEL@" + +GetMonFieldMoves: + ld a, [wWhichPokemon] + ld hl, wPartyMon1Moves + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld d, h + ld e, l + ld c, NUM_MOVES + 1 + ld hl, wFieldMoves +.loop + push hl +.nextMove + dec c + jr z, .done + ld a, [de] ; move ID + and a + jr z, .done + ld b, a + inc de + ld hl, FieldMoveDisplayData +.fieldMoveLoop + ld a, [hli] + cp $ff + jr z, .nextMove ; if the move is not a field move + cp b + jr z, .foundFieldMove + inc hl + inc hl + jr .fieldMoveLoop +.foundFieldMove + ld a, b + ld [wLastFieldMoveID], a + ld a, [hli] ; field move name index + ld b, [hl] ; field move leftmost X coordinate + pop hl + ld [hli], a ; store name index in wFieldMoves + ld a, [wNumFieldMoves] + inc a + ld [wNumFieldMoves], a + ld a, [wFieldMovesLeftmostXCoord] + cp b + jr c, .skipUpdatingLeftmostXCoord + ld a, b + ld [wFieldMovesLeftmostXCoord], a +.skipUpdatingLeftmostXCoord + ld a, [wLastFieldMoveID] + ld b, a + jr .loop +.done + pop hl + ret + +; Format: [Move id], [name index], [leftmost tile] +; Move id = id of move +; Name index = index of name in FieldMoveNames +; Leftmost tile = -1 + tile column in which the first letter of the move's name should be displayed +; "SOFTBOILED" is $08 because it has 4 more letters than "SURF", for example, whose value is $0C +FieldMoveDisplayData: + db CUT, $01, $0C + db FLY, $02, $0C + db $B4, $03, $0C ; unused field move + db SURF, $04, $0C + db STRENGTH, $05, $0A + db FLASH, $06, $0C + db DIG, $07, $0C + db TELEPORT, $08, $0A + db SOFTBOILED, $09, $08 + db $ff ; list terminator diff --git a/engine/mon_party_sprites.asm b/engine/mon_party_sprites.asm deleted file mode 100755 index d2913715..00000000 --- a/engine/mon_party_sprites.asm +++ /dev/null @@ -1,295 +0,0 @@ -AnimatePartyMon_ForceSpeed1: - xor a - ld [wCurrentMenuItem], a - ld b, a - inc a - jr GetAnimationSpeed - -; wPartyMenuHPBarColors contains the party mon's health bar colors -; 0: green -; 1: yellow -; 2: red -AnimatePartyMon:: - ld hl, wPartyMenuHPBarColors - ld a, [wCurrentMenuItem] - ld c, a - ld b, 0 - add hl, bc - ld a, [hl] - -GetAnimationSpeed: - ld c, a - ld hl, PartyMonSpeeds - add hl, bc - ld a, [wOnSGB] - xor $1 - add [hl] - ld c, a - add a - ld b, a - ld a, [wAnimCounter] - and a - jr z, .resetSprites - cp c - jr z, .animateSprite -.incTimer - inc a - cp b - jr nz, .skipResetTimer - xor a ; reset timer -.skipResetTimer - ld [wAnimCounter], a - jp DelayFrame -.resetSprites - push bc - ld hl, wMonPartySpritesSavedOAM - ld de, wOAMBuffer - ld bc, $60 - call CopyData - pop bc - xor a - jr .incTimer -.animateSprite - push bc - ld hl, wOAMBuffer + $02 ; OAM tile id - ld bc, $10 - ld a, [wCurrentMenuItem] - call AddNTimes - ld c, $40 ; amount to increase the tile id by - ld a, [hl] - cp $4 ; tile ID for ICON_BALL - jr z, .editCoords - cp $8 ; tile ID for ICON_HELIX - jr nz, .editTileIDS -; ICON_BALL and ICON_HELIX only shake up and down -.editCoords - dec hl - dec hl ; dec hl to the OAM y coord - ld c, $1 ; amount to increase the y coord by -; otherwise, load a second sprite frame -.editTileIDS - ld b, $4 - ld de, $4 -.loop - ld a, [hl] - add c - ld [hl], a - add hl, de - dec b - jr nz, .loop - pop bc - ld a, c - jr .incTimer - -; Party mon animations cycle between 2 frames. -; The members of the PartyMonSpeeds array specify the number of V-blanks -; that each frame lasts for green HP, yellow HP, and red HP in order. -; On the naming screen, the yellow HP speed is always used. -PartyMonSpeeds: - db 5, 16, 32 - -LoadMonPartySpriteGfx: -; Load mon party sprite tile patterns into VRAM during V-blank. - ld hl, MonPartySpritePointers - ld a, $1c - -LoadAnimSpriteGfx: -; Load animated sprite tile patterns into VRAM during V-blank. hl is the address -; of an array of structures that contain arguments for CopyVideoData and a is -; the number of structures in the array. - ld bc, $0 -.loop - push af - push bc - push hl - add hl, bc - ld a, [hli] - ld e, a - ld a, [hli] - ld d, a - ld a, [hli] - ld c, a - ld a, [hli] - ld b, a - ld a, [hli] - ld h, [hl] - ld l, a - call CopyVideoData - pop hl - pop bc - ld a, $6 - add c - ld c, a - pop af - dec a - jr nz, .loop - ret - -LoadMonPartySpriteGfxWithLCDDisabled: -; Load mon party sprite tile patterns into VRAM immediately by disabling the -; LCD. - call DisableLCD - ld hl, MonPartySpritePointers - ld a, $1c - ld bc, $0 -.loop - push af - push bc - push hl - add hl, bc - ld a, [hli] - ld e, a - ld a, [hli] - ld d, a - push de - ld a, [hli] - ld c, a - swap c - ld b, $0 - ld a, [hli] - ld e, [hl] - inc hl - ld d, [hl] - pop hl - call FarCopyData2 - pop hl - pop bc - ld a, $6 - add c - ld c, a - pop af - dec a - jr nz, .loop - jp EnableLCD - -INCLUDE "data/mon_party_sprite_pointers.asm" - -WriteMonPartySpriteOAMByPartyIndex: -; Write OAM blocks for the party mon in [hPartyMonIndex]. - push hl - push de - push bc - ld a, [hPartyMonIndex] - ld hl, wPartySpecies - ld e, a - ld d, 0 - add hl, de - ld a, [hl] - call GetPartyMonSpriteID - ld [wOAMBaseTile], a - call WriteMonPartySpriteOAM - pop bc - pop de - pop hl - ret - -WriteMonPartySpriteOAMBySpecies: -; Write OAM blocks for the party sprite of the species in -; [wMonPartySpriteSpecies]. - xor a - ld [hPartyMonIndex], a - ld a, [wMonPartySpriteSpecies] - call GetPartyMonSpriteID - ld [wOAMBaseTile], a - jr WriteMonPartySpriteOAM - -UnusedPartyMonSpriteFunction: -; This function is unused and doesn't appear to do anything useful. It looks -; like it may have been intended to load the tile patterns and OAM data for -; the mon party sprite associated with the species in [wcf91]. -; However, its calculations are off and it loads garbage data. - ld a, [wcf91] - call GetPartyMonSpriteID - push af - ld hl, vSprites - call .LoadTilePatterns - pop af - add $54 - ld hl, vSprites + $40 - call .LoadTilePatterns - xor a - ld [wMonPartySpriteSpecies], a - jr WriteMonPartySpriteOAMBySpecies - -.LoadTilePatterns - push hl - add a - ld c, a - ld b, 0 - ld hl, MonPartySpritePointers - add hl, bc - add hl, bc - add hl, bc - ld a, [hli] - ld e, a - ld a, [hli] - ld d, a - ld a, [hli] - ld c, a - ld a, [hli] - ld b, a - pop hl - jp CopyVideoData - -WriteMonPartySpriteOAM: -; Write the OAM blocks for the first animation frame into the OAM buffer and -; make a copy at wMonPartySpritesSavedOAM. - push af - ld c, $10 - ld h, wOAMBuffer / $100 - ld a, [hPartyMonIndex] - swap a - ld l, a - add $10 - ld b, a - pop af - cp ICON_HELIX << 2 - jr z, .helix - call WriteSymmetricMonPartySpriteOAM - jr .makeCopy -.helix - call WriteAsymmetricMonPartySpriteOAM -; Make a copy of the OAM buffer with the first animation frame written so that -; we can flip back to it from the second frame by copying it back. -.makeCopy - ld hl, wOAMBuffer - ld de, wMonPartySpritesSavedOAM - ld bc, $60 - jp CopyData - -GetPartyMonSpriteID: - ld [wd11e], a - predef IndexToPokedex - ld a, [wd11e] - ld c, a - dec a - srl a - ld hl, MonPartyData - ld e, a - ld d, 0 - add hl, de - ld a, [hl] - bit 0, c - jr nz, .skipSwap - swap a ; use lower nybble if pokedex num is even -.skipSwap - and $f0 - srl a - srl a - ret - -INCLUDE "data/mon_party_sprites.asm" - -INC_FRAME_1 EQUS "0, $20" -INC_FRAME_2 EQUS "$20, $20" - -BugIconFrame1: INCBIN "gfx/icons/bug.2bpp", INC_FRAME_1 -PlantIconFrame1: INCBIN "gfx/icons/plant.2bpp", INC_FRAME_1 -BugIconFrame2: INCBIN "gfx/icons/bug.2bpp", INC_FRAME_2 -PlantIconFrame2: INCBIN "gfx/icons/plant.2bpp", INC_FRAME_2 -SnakeIconFrame1: INCBIN "gfx/icons/snake.2bpp", INC_FRAME_1 -QuadrupedIconFrame1: INCBIN "gfx/icons/quadruped.2bpp", INC_FRAME_1 -SnakeIconFrame2: INCBIN "gfx/icons/snake.2bpp", INC_FRAME_2 -QuadrupedIconFrame2: INCBIN "gfx/icons/quadruped.2bpp", INC_FRAME_2 - -TradeBubbleIconGFX: INCBIN "gfx/trade/bubble.2bpp" diff --git a/engine/movie/clear_save.asm b/engine/movie/clear_save.asm new file mode 100755 index 00000000..b47cd6c4 --- /dev/null +++ b/engine/movie/clear_save.asm @@ -0,0 +1,23 @@ +DoClearSaveDialogue: + call ClearScreen + call RunDefaultPaletteCommand + call LoadFontTilePatterns + call LoadTextBoxTilePatterns + ld hl, ClearSaveDataText + call PrintText + coord hl, 14, 7 + lb bc, 8, 15 + ld a, NO_YES_MENU + ld [wTwoOptionMenuID], a + ld a, TWO_OPTION_MENU + ld [wTextBoxID], a + call DisplayTextBoxID + ld a, [wCurrentMenuItem] + and a + jp z, Init + callba ClearSAV + jp Init + +ClearSaveDataText: + TX_FAR _ClearSaveDataText + db "@" diff --git a/engine/movie/credits.asm b/engine/movie/credits.asm new file mode 100755 index 00000000..f820aae3 --- /dev/null +++ b/engine/movie/credits.asm @@ -0,0 +1,270 @@ +HallOfFamePC: + callba AnimateHallOfFame + call ClearScreen + ld c, 100 + call DelayFrames + call DisableLCD + ld hl, vFont + ld bc, $800 / 2 + call ZeroMemory + ld hl, vChars2 + $600 + ld bc, $200 / 2 + call ZeroMemory + ld hl, vChars2 + $7e0 + ld bc, $10 + ld a, $ff + call FillMemory + coord hl, 0, 0 + call FillFourRowsWithBlack + coord hl, 0, 14 + call FillFourRowsWithBlack + ld a, %11000000 + ld [rBGP], a + call EnableLCD + ld a, $ff + call PlaySoundWaitForCurrent + ld c, BANK(Music_Credits) + ld a, MUSIC_CREDITS + call PlayMusic + ld c, 128 + call DelayFrames + xor a + ld [wUnusedCD3D], a ; not read + ld [wNumCreditsMonsDisplayed], a + jp Credits + +FadeInCreditsText: + ld hl, HoFGBPalettes + ld b, 4 +.loop + ld a, [hli] + ld [rBGP], a + ld c, 5 + call DelayFrames + dec b + jr nz, .loop + ret + +DisplayCreditsMon: + xor a + ld [H_AUTOBGTRANSFERENABLED], a + call SaveScreenTilesToBuffer1 + call FillMiddleOfScreenWithWhite + + ; display the next monster from CreditsMons + ld hl, wNumCreditsMonsDisplayed + ld c, [hl] ; how many monsters have we displayed so far? + inc [hl] + ld b, 0 + ld hl, CreditsMons + add hl, bc ; go that far in the list of monsters and get the next one + ld a, [hl] + ld [wcf91], a + ld [wd0b5], a + coord hl, 8, 6 + call GetMonHeader + call LoadFrontSpriteByMonIndex + ld hl, vBGMap0 + $c + call CreditsCopyTileMapToVRAM + xor a + ld [H_AUTOBGTRANSFERENABLED], a + call LoadScreenTilesFromBuffer1 + ld hl, vBGMap0 + call CreditsCopyTileMapToVRAM + ld a, $A7 + ld [rWX], a + ld hl, vBGMap1 + call CreditsCopyTileMapToVRAM + call FillMiddleOfScreenWithWhite + ld a, %11111100 ; make the mon a black silhouette + ld [rBGP], a + +; scroll the mon left by one tile 7 times + ld bc, 7 +.scrollLoop1 + call 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 ScrollCreditsMonLeft + ld a, [rWX] + sub 8 + ld [rWX], a + dec c + jr nz, .scrollLoop2 + + xor a + ld [hWY], a + ld a, %11000000 + ld [rBGP], a + ret + +INCLUDE "data/credit_mons.asm" + +ScrollCreditsMonLeft: + ld h, b + ld l, $20 + call ScrollCreditsMonLeft_SetSCX + ld h, $0 + ld l, $70 + call ScrollCreditsMonLeft_SetSCX + ld a, b + add $8 + ld b, a + ret + +ScrollCreditsMonLeft_SetSCX: + ld a, [rLY] + cp l + jr nz, ScrollCreditsMonLeft_SetSCX + ld a, h + ld [rSCX], a +.loop + ld a, [rLY] + cp h + jr z, .loop + ret + +HoFGBPalettes: + db %11000000 + db %11010000 + db %11100000 + db %11110000 + +CreditsCopyTileMapToVRAM: + ld a, l + ld [H_AUTOBGTRANSFERDEST], a + ld a, h + ld [H_AUTOBGTRANSFERDEST + 1], a + ld a, 1 + ld [H_AUTOBGTRANSFERENABLED], a + jp Delay3 + +ZeroMemory: +; zero bc bytes at hl + ld [hl], 0 + inc hl + inc hl + dec bc + ld a, b + or c + jr nz, ZeroMemory + ret + +FillFourRowsWithBlack: + ld bc, SCREEN_WIDTH * 4 + ld a, $7e + jp FillMemory + +FillMiddleOfScreenWithWhite: + coord hl, 0, 4 + ld bc, SCREEN_WIDTH * 10 + ld a, " " + jp FillMemory + +Credits: + ld de, CreditsOrder + push de +.nextCreditsScreen + pop de + coord hl, 9, 6 + push hl + call FillMiddleOfScreenWithWhite + pop hl +.nextCreditsCommand + ld a, [de] + inc de + push de + cp $ff + jr z, .fadeInTextAndShowMon + cp $fe + jr z, .showTextAndShowMon + cp $fd + jr z, .fadeInText + cp $fc + jr z, .showText + cp $fb + jr z, .showCopyrightText + cp $fa + jr z, .showTheEnd + push hl + push hl + ld hl, CreditsTextPointers + add a + ld c, a + ld b, 0 + add hl, bc + ld e, [hl] + inc hl + ld d, [hl] + ld a, [de] + inc de + ld c, a + ld b, $ff + pop hl + add hl, bc + call PlaceString + pop hl + ld bc, SCREEN_WIDTH * 2 + add hl, bc + pop de + jr .nextCreditsCommand +.fadeInTextAndShowMon + call FadeInCreditsText + ld c, 90 + jr .next1 +.showTextAndShowMon + ld c, 110 +.next1 + call DelayFrames + call DisplayCreditsMon + jr .nextCreditsScreen +.fadeInText + call FadeInCreditsText + ld c, 120 + jr .next2 +.showText + ld c, 140 +.next2 + call DelayFrames + jr .nextCreditsScreen +.showCopyrightText + push de + callba LoadCopyrightTiles + pop de + pop de + jr .nextCreditsCommand +.showTheEnd + ld c, 16 + call DelayFrames + call FillMiddleOfScreenWithWhite + pop de + ld de, TheEndGfx + ld hl, vChars2 + $600 + lb bc, BANK(TheEndGfx), (TheEndGfxEnd - TheEndGfx) / $10 + call CopyVideoData + coord hl, 4, 8 + ld de, TheEndTextString + call PlaceString + coord hl, 4, 9 + inc de + call PlaceString + jp FadeInCreditsText + +TheEndTextString: +; "T H E E N D" + db $60," ",$62," ",$64," ",$64," ",$66," ",$68,"@" + db $61," ",$63," ",$65," ",$65," ",$67," ",$69,"@" + +INCLUDE "data/credits_order.asm" + +INCLUDE "text/credits_text.asm" + +TheEndGfx: + INCBIN "gfx/intro_credits/the_end.2bpp" +TheEndGfxEnd: diff --git a/engine/movie/evolution.asm b/engine/movie/evolution.asm new file mode 100755 index 00000000..731735c5 --- /dev/null +++ b/engine/movie/evolution.asm @@ -0,0 +1,160 @@ +EvolveMon: + push hl + push de + push bc + ld a, [wcf91] + push af + ld a, [wd0b5] + push af + xor a + ld [wLowHealthAlarm], a + ld [wChannelSoundIDs + Ch5], a + dec a + ld [wNewSoundID], a + call PlaySound + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + ld a, SFX_TINK + call PlaySound + call Delay3 + xor a + ld [H_AUTOBGTRANSFERENABLED], a + ld [hTilesetType], a + ld a, [wEvoOldSpecies] + ld [wWholeScreenPaletteMonSpecies], a + ld c, 0 + call EvolutionSetWholeScreenPalette + ld a, [wEvoNewSpecies] + ld [wcf91], a + ld [wd0b5], a + call Evolution_LoadPic + ld de, vFrontPic + ld hl, vBackPic + ld bc, 7 * 7 + call CopyVideoData + ld a, [wEvoOldSpecies] + ld [wcf91], a + ld [wd0b5], a + call Evolution_LoadPic + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + ld a, [wEvoOldSpecies] + call PlayCry + call WaitForSoundToFinish + ld c, BANK(Music_SafariZone) + ld a, MUSIC_SAFARI_ZONE + call PlayMusic + ld c, 80 + call DelayFrames + ld c, 1 ; set PAL_BLACK instead of mon palette + call EvolutionSetWholeScreenPalette + lb bc, $1, $10 +.animLoop + push bc + call Evolution_CheckForCancel + jr c, .evolutionCancelled + call Evolution_BackAndForthAnim + pop bc + inc b + dec c + dec c + jr nz, .animLoop + xor a + ld [wEvoCancelled], a + ld a, $31 + ld [wEvoMonTileOffset], a + call Evolution_ChangeMonPic ; show the new species pic + ld a, [wEvoNewSpecies] +.done + ld [wWholeScreenPaletteMonSpecies], a + ld a, $ff + ld [wNewSoundID], a + call PlaySound + ld a, [wWholeScreenPaletteMonSpecies] + call PlayCry + ld c, 0 + call EvolutionSetWholeScreenPalette + pop af + ld [wd0b5], a + pop af + ld [wcf91], a + pop bc + pop de + pop hl + ld a, [wEvoCancelled] + and a + ret z + scf + ret +.evolutionCancelled + pop bc + ld a, 1 + ld [wEvoCancelled], a + ld a, [wEvoOldSpecies] + jr .done + +EvolutionSetWholeScreenPalette: + ld b, SET_PAL_POKEMON_WHOLE_SCREEN + jp RunPaletteCommand + +Evolution_LoadPic: + call GetMonHeader + coord hl, 7, 2 + jp LoadFlippedFrontSpriteByMonIndex + +Evolution_BackAndForthAnim: +; show the mon change back and forth between the new and old species b times + ld a, $31 + ld [wEvoMonTileOffset], a + call Evolution_ChangeMonPic + ld a, -$31 + ld [wEvoMonTileOffset], a + call Evolution_ChangeMonPic + dec b + jr nz, Evolution_BackAndForthAnim + ret + +Evolution_ChangeMonPic: + push bc + xor a + ld [H_AUTOBGTRANSFERENABLED], a + coord hl, 7, 2 + lb bc, 7, 7 + ld de, SCREEN_WIDTH - 7 +.loop + push bc +.innerLoop + ld a, [wEvoMonTileOffset] + add [hl] + ld [hli], a + dec c + jr nz, .innerLoop + pop bc + add hl, de + dec b + jr nz, .loop + ld a, 1 + ld [H_AUTOBGTRANSFERENABLED], a + call Delay3 + pop bc + ret + +Evolution_CheckForCancel: + call DelayFrame + push bc + call JoypadLowSensitivity + ld a, [hJoy5] + pop bc + and B_BUTTON + jr nz, .pressedB +.notAllowedToCancel + dec c + jr nz, Evolution_CheckForCancel + and a + ret +.pressedB + ld a, [wForceEvolution] + and a + jr nz, .notAllowedToCancel + scf + ret diff --git a/engine/movie/gamefreak.asm b/engine/movie/gamefreak.asm new file mode 100755 index 00000000..78e48384 --- /dev/null +++ b/engine/movie/gamefreak.asm @@ -0,0 +1,243 @@ +LoadShootingStarGraphics: + ld a, $f9 + ld [rOBP0], a + ld a, $a4 + ld [rOBP1], a + ld de, AnimationTileset2 + $30 ; star tile (top left quadrant) + ld hl, vChars1 + $200 + lb bc, BANK(AnimationTileset2), $01 + call CopyVideoData + ld de, AnimationTileset2 + $130 ; star tile (bottom left quadrant) + ld hl, vChars1 + $210 + lb bc, BANK(AnimationTileset2), $01 + call CopyVideoData + ld de, FallingStar + ld hl, vChars1 + $220 + lb bc, BANK(FallingStar), (FallingStarEnd - FallingStar) / $10 + call CopyVideoData + ld hl, GameFreakLogoOAMData + ld de, wOAMBuffer + $60 + ld bc, GameFreakLogoOAMDataEnd - GameFreakLogoOAMData + call CopyData + ld hl, GameFreakShootingStarOAMData + ld de, wOAMBuffer + ld bc, GameFreakShootingStarOAMDataEnd - GameFreakShootingStarOAMData + jp CopyData + +AnimateShootingStar: + call LoadShootingStarGraphics + ld a, SFX_SHOOTING_STAR + call PlaySound + +; Move the big star down and left across the screen. + ld hl, wOAMBuffer + lb bc, $a0, $4 +.bigStarLoop + push hl + push bc +.bigStarInnerLoop + ld a, [hl] ; Y + add 4 + ld [hli], a + ld a, [hl] ; X + add -4 + ld [hli], a + inc hl + inc hl + dec c + jr nz, .bigStarInnerLoop + ld c, 1 + call CheckForUserInterruption + pop bc + pop hl + ret c + ld a, [hl] + cp 80 + jr nz, .next + jr .bigStarLoop +.next + cp b + jr nz, .bigStarLoop + +; Clear big star OAM. + ld hl, wOAMBuffer + ld c, 4 + ld de, 4 +.clearOAMLoop + ld [hl], 160 + add hl, de + dec c + jr nz, .clearOAMLoop + +; Make Gamefreak logo flash. + ld b, 3 +.flashLogoLoop + ld hl, rOBP0 + rrc [hl] + rrc [hl] + ld c, 10 + call CheckForUserInterruption + ret c + dec b + jr nz, .flashLogoLoop + +; Copy 24 instances of the small stars OAM data. +; Note that their coordinates put them off-screen. + ld de, wOAMBuffer + ld a, 24 +.initSmallStarsOAMLoop + push af + ld hl, SmallStarsOAM + ld bc, SmallStarsOAMEnd - SmallStarsOAM + call CopyData + pop af + dec a + jr nz, .initSmallStarsOAMLoop + +; Animate the small stars falling from the Gamefreak logo. + xor a + ld [wMoveDownSmallStarsOAMCount], a + ld hl, SmallStarsWaveCoordsPointerTable + ld c, 6 +.smallStarsLoop + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + push bc + push hl + ld hl, wOAMBuffer + $50 + ld c, 4 +.smallStarsInnerLoop ; introduce new wave of 4 small stars OAM entries + ld a, [de] + cp $ff + jr z, .next2 + ld [hli], a ; Y + inc de + ld a, [de] + ld [hli], a ; X + inc de + inc hl + inc hl + dec c + jr nz, .smallStarsInnerLoop + ld a, [wMoveDownSmallStarsOAMCount] + cp 24 + jr z, .next2 + add 6 ; should be 4, but the extra 2 aren't visible on screen + ld [wMoveDownSmallStarsOAMCount], a +.next2 + call MoveDownSmallStars + push af + +; shift the existing OAM entries down to make room for the next wave + ld hl, wOAMBuffer + $10 + ld de, wOAMBuffer + ld bc, $50 + call CopyData + + pop af + pop hl + pop bc + ret c + dec c + jr nz, .smallStarsLoop + and a + ret + +SmallStarsOAM: + db $00,$00,$A2,$90 +SmallStarsOAMEnd: + +SmallStarsWaveCoordsPointerTable: + dw SmallStarsWave1Coords + dw SmallStarsWave2Coords + dw SmallStarsWave3Coords + dw SmallStarsWave4Coords + dw SmallStarsEmptyWave + dw SmallStarsEmptyWave + +; The stars that fall from the Gamefreak logo come in 4 waves of 4 OAM entries. +; These arrays contain the Y and X coordinates of each OAM entry. + +SmallStarsWave1Coords: + db $68,$30 + db $68,$40 + db $68,$58 + db $68,$78 + +SmallStarsWave2Coords: + db $68,$38 + db $68,$48 + db $68,$60 + db $68,$70 + +SmallStarsWave3Coords: + db $68,$34 + db $68,$4C + db $68,$54 + db $68,$64 + +SmallStarsWave4Coords: + db $68,$3C + db $68,$5C + db $68,$6C + db $68,$74 + +SmallStarsEmptyWave: + db $FF + +MoveDownSmallStars: + ld b, 8 +.loop + ld hl, wOAMBuffer + $5c + ld a, [wMoveDownSmallStarsOAMCount] + ld de, -4 + ld c, a +.innerLoop + inc [hl] ; Y + add hl, de + dec c + jr nz, .innerLoop +; Toggle the palette so that the lower star in the small stars tile blinks in +; and out. + ld a, [rOBP1] + xor %10100000 + ld [rOBP1], a + + ld c, 3 + call CheckForUserInterruption + ret c + dec b + jr nz, .loop + ret + +GameFreakLogoOAMData: + db $48,$50,$8D,$00 + db $48,$58,$8E,$00 + db $50,$50,$8F,$00 + db $50,$58,$90,$00 + db $58,$50,$91,$00 + db $58,$58,$92,$00 + db $60,$30,$80,$00 + db $60,$38,$81,$00 + db $60,$40,$82,$00 + db $60,$48,$83,$00 + db $60,$50,$93,$00 + db $60,$58,$84,$00 + db $60,$60,$85,$00 + db $60,$68,$83,$00 + db $60,$70,$81,$00 + db $60,$78,$86,$00 +GameFreakLogoOAMDataEnd: + +GameFreakShootingStarOAMData: + db $00,$A0,$A0,$10 + db $00,$A8,$A0,$30 + db $08,$A0,$A1,$10 + db $08,$A8,$A1,$30 +GameFreakShootingStarOAMDataEnd: + +FallingStar: + INCBIN "gfx/intro_credits/falling_star.2bpp" +FallingStarEnd: diff --git a/engine/movie/hall_of_fame.asm b/engine/movie/hall_of_fame.asm new file mode 100755 index 00000000..3c9b1723 --- /dev/null +++ b/engine/movie/hall_of_fame.asm @@ -0,0 +1,288 @@ +AnimateHallOfFame: + call HoFFadeOutScreenAndMusic + call ClearScreen + ld c, 100 + call DelayFrames + call LoadFontTilePatterns + call LoadTextBoxTilePatterns + call DisableLCD + ld hl, vBGMap0 + ld bc, $800 + ld a, " " + call FillMemory + call EnableLCD + ld hl, rLCDC + set 3, [hl] + xor a + ld hl, wHallOfFame + ld bc, HOF_TEAM + call FillMemory + xor a + ld [wUpdateSpritesEnabled], a + ld [hTilesetType], a + ld [wSpriteFlipped], a + ld [wLetterPrintingDelayFlags], a ; no delay + ld [wHoFMonOrPlayer], a ; mon + inc a + ld [H_AUTOBGTRANSFERENABLED], a + ld hl, wNumHoFTeams + ld a, [hl] + inc a + jr z, .skipInc ; don't wrap around to 0 + inc [hl] +.skipInc + ld a, $90 + ld [hWY], a + ld c, BANK(Music_HallOfFame) + ld a, MUSIC_HALL_OF_FAME + call PlayMusic + ld hl, wPartySpecies + ld c, $ff +.partyMonLoop + ld a, [hli] + cp $ff + jr z, .doneShowingParty + inc c + push hl + push bc + ld [wHoFMonSpecies], a + ld a, c + ld [wHoFPartyMonIndex], a + ld hl, wPartyMon1Level + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld a, [hl] + ld [wHoFMonLevel], a + call HoFShowMonOrPlayer + call HoFDisplayAndRecordMonInfo + ld c, 80 + call DelayFrames + coord hl, 2, 13 + ld b, 3 + ld c, 14 + call TextBoxBorder + coord hl, 4, 15 + ld de, HallOfFameText + call PlaceString + ld c, 180 + call DelayFrames + call GBFadeOutToWhite + pop bc + pop hl + jr .partyMonLoop +.doneShowingParty + ld a, c + inc a + ld hl, wHallOfFame + ld bc, HOF_MON + call AddNTimes + ld [hl], $ff + call SaveHallOfFameTeams + xor a + ld [wHoFMonSpecies], a + inc a + ld [wHoFMonOrPlayer], a ; player + call HoFShowMonOrPlayer + call HoFDisplayPlayerStats + call HoFFadeOutScreenAndMusic + xor a + ld [hWY], a + ld hl, rLCDC + res 3, [hl] + ret + +HallOfFameText: + db "HALL OF FAME@" + +HoFShowMonOrPlayer: + call ClearScreen + ld a, $d0 + ld [hSCY], a + ld a, $c0 + ld [hSCX], a + ld a, [wHoFMonSpecies] + ld [wcf91], a + ld [wd0b5], a + ld [wBattleMonSpecies2], a + ld [wWholeScreenPaletteMonSpecies], a + ld a, [wHoFMonOrPlayer] + and a + jr z, .showMon +; show player + call HoFLoadPlayerPics + jr .next1 +.showMon + coord hl, 12, 5 + call GetMonHeader + call LoadFrontSpriteByMonIndex + predef LoadMonBackPic +.next1 + ld b, SET_PAL_POKEMON_WHOLE_SCREEN + ld c, 0 + call RunPaletteCommand + ld a, %11100100 + ld [rBGP], a + ld c, $31 ; back pic + call HoFLoadMonPlayerPicTileIDs + ld d, $a0 + ld e, 4 + ld a, [wOnSGB] + and a + jr z, .next2 + sla e ; scroll more slowly on SGB +.next2 + call .ScrollPic ; scroll back pic left + xor a + ld [hSCY], a + ld c, a ; front pic + call HoFLoadMonPlayerPicTileIDs + ld d, 0 + ld e, -4 +; scroll front pic right + +.ScrollPic + call DelayFrame + ld a, [hSCX] + add e + ld [hSCX], a + cp d + jr nz, .ScrollPic + ret + +HoFDisplayAndRecordMonInfo: + ld a, [wHoFPartyMonIndex] + ld hl, wPartyMonNicks + call GetPartyMonName + call HoFDisplayMonInfo + jp HoFRecordMonInfo + +HoFDisplayMonInfo: + coord hl, 0, 2 + ld b, 9 + ld c, 10 + call TextBoxBorder + coord hl, 2, 6 + ld de, HoFMonInfoText + call PlaceString + coord hl, 1, 4 + ld de, wcd6d + call PlaceString + ld a, [wHoFMonLevel] + coord hl, 8, 7 + call PrintLevelCommon + ld a, [wHoFMonSpecies] + ld [wd0b5], a + coord hl, 3, 9 + predef PrintMonType + ld a, [wHoFMonSpecies] + jp PlayCry + +HoFMonInfoText: + db "LEVEL/" + next "TYPE1/" + next "TYPE2/@" + +HoFLoadPlayerPics: + ld de, RedPicFront + ld a, BANK(RedPicFront) + call UncompressSpriteFromDE + ld hl, sSpriteBuffer1 + ld de, sSpriteBuffer0 + ld bc, $310 + call CopyData + ld de, vFrontPic + call InterlaceMergeSpriteBuffers + ld de, RedPicBack + ld a, BANK(RedPicBack) + call UncompressSpriteFromDE + predef ScaleSpriteByTwo + ld de, vBackPic + call InterlaceMergeSpriteBuffers + ld c, $1 + +HoFLoadMonPlayerPicTileIDs: +; c = base tile ID + ld b, 0 + coord hl, 12, 5 + predef_jump CopyTileIDsFromList + +HoFDisplayPlayerStats: + SetEvent EVENT_HALL_OF_FAME_DEX_RATING + predef DisplayDexRating + coord hl, 0, 4 + ld b, 6 + ld c, 10 + call TextBoxBorder + coord hl, 5, 0 + ld b, 2 + ld c, 9 + call TextBoxBorder + coord hl, 7, 2 + ld de, wPlayerName + call PlaceString + coord hl, 1, 6 + ld de, HoFPlayTimeText + call PlaceString + coord hl, 5, 7 + ld de, wPlayTimeHours + lb bc, 1, 3 + call PrintNumber + ld [hl], $6d + inc hl + ld de, wPlayTimeMinutes + lb bc, LEADING_ZEROES | 1, 2 + call PrintNumber + coord hl, 1, 9 + ld de, HoFMoneyText + call PlaceString + coord hl, 4, 10 + ld de, wPlayerMoney + ld c, $a3 + call PrintBCDNumber + ld hl, DexSeenOwnedText + call HoFPrintTextAndDelay + ld hl, DexRatingText + call HoFPrintTextAndDelay + ld hl, wDexRatingText + +HoFPrintTextAndDelay: + call PrintText + ld c, 120 + jp DelayFrames + +HoFPlayTimeText: + db "PLAY TIME@" + +HoFMoneyText: + db "MONEY@" + +DexSeenOwnedText: + TX_FAR _DexSeenOwnedText + db "@" + +DexRatingText: + TX_FAR _DexRatingText + db "@" + +HoFRecordMonInfo: + ld hl, wHallOfFame + ld bc, HOF_MON + ld a, [wHoFPartyMonIndex] + call AddNTimes + ld a, [wHoFMonSpecies] + ld [hli], a + ld a, [wHoFMonLevel] + ld [hli], a + ld e, l + ld d, h + ld hl, wcd6d + ld bc, NAME_LENGTH + jp CopyData + +HoFFadeOutScreenAndMusic: + ld a, 10 + ld [wAudioFadeOutCounterReloadValue], a + ld [wAudioFadeOutCounter], a + ld a, $ff + ld [wAudioFadeOutControl], a + jp GBFadeOutToWhite diff --git a/engine/movie/init_player_data.asm b/engine/movie/init_player_data.asm new file mode 100644 index 00000000..c576e65a --- /dev/null +++ b/engine/movie/init_player_data.asm @@ -0,0 +1,55 @@ +InitPlayerData: +InitPlayerData2: + + call Random + ld a, [hRandomSub] + ld [wPlayerID], a + + call Random + ld a, [hRandomAdd] + ld [wPlayerID + 1], a + + ld a, $ff + ld [wUnusedD71B], a + + ld hl, wPartyCount + call InitializeEmptyList + ld hl, wNumInBox + call InitializeEmptyList + ld hl, wNumBagItems + call InitializeEmptyList + ld hl, wNumBoxItems + call InitializeEmptyList + +START_MONEY EQU $3000 + ld hl, wPlayerMoney + 1 + ld a, START_MONEY / $100 + ld [hld], a + xor a + ld [hli], a + inc hl + ld [hl], a + + ld [wMonDataLocation], a + + ld hl, wObtainedBadges + ld [hli], a + + ld [hl], a + + ld hl, wPlayerCoins + ld [hli], a + ld [hl], a + + ld hl, wGameProgressFlags + ld bc, wGameProgressFlagsEnd - wGameProgressFlags + call FillMemory ; clear all game progress flags + + jp InitializeMissableObjectsFlags + +InitializeEmptyList: + xor a ; count + ld [hli], a + dec a ; terminator + ld [hl], a + ret diff --git a/engine/movie/intro.asm b/engine/movie/intro.asm new file mode 100755 index 00000000..9a13c96f --- /dev/null +++ b/engine/movie/intro.asm @@ -0,0 +1,470 @@ +const_value = -1 + const MOVE_NIDORINO_RIGHT + const MOVE_GENGAR_RIGHT + const MOVE_GENGAR_LEFT + +ANIMATION_END EQU 80 + +const_value = 3 + const GENGAR_INTRO_TILES1 + const GENGAR_INTRO_TILES2 + const GENGAR_INTRO_TILES3 + +PlayIntro: + xor a + ld [hJoyHeld], a + inc a + ld [H_AUTOBGTRANSFERENABLED], a + call PlayShootingStar + call PlayIntroScene + call GBFadeOutToWhite + xor a + ld [hSCX], a + ld [H_AUTOBGTRANSFERENABLED], a + call ClearSprites + call DelayFrame + ret + +PlayIntroScene: + ld b, SET_PAL_NIDORINO_INTRO + call RunPaletteCommand + ldPal a, BLACK, DARK_GRAY, LIGHT_GRAY, WHITE + ld [rBGP], a + ld [rOBP0], a + ld [rOBP1], a + xor a + ld [hSCX], a + ld b, GENGAR_INTRO_TILES1 + call IntroCopyTiles + ld a, 0 + ld [wBaseCoordX], a + ld a, 80 + ld [wBaseCoordY], a + lb bc, 6, 6 + call InitIntroNidorinoOAM + lb de, 80 / 2, MOVE_NIDORINO_RIGHT + call IntroMoveMon + ret c + +; hip + ld a, SFX_INTRO_HIP + call PlaySound + xor a + ld [wIntroNidorinoBaseTile], a + ld de, IntroNidorinoAnimation1 + call AnimateIntroNidorino +; hop + ld a, SFX_INTRO_HOP + call PlaySound + ld de, IntroNidorinoAnimation2 + call AnimateIntroNidorino + ld c, 10 + call CheckForUserInterruption + ret c + +; hip + ld a, SFX_INTRO_HIP + call PlaySound + ld de, IntroNidorinoAnimation1 + call AnimateIntroNidorino +; hop + ld a, SFX_INTRO_HOP + call PlaySound + ld de, IntroNidorinoAnimation2 + call AnimateIntroNidorino + ld c, 30 + call CheckForUserInterruption + ret c + +; raise + ld b, GENGAR_INTRO_TILES2 + call IntroCopyTiles + ld a, SFX_INTRO_RAISE + call PlaySound + lb de, 8 / 2, MOVE_GENGAR_LEFT + call IntroMoveMon + ld c, 30 + call CheckForUserInterruption + ret c + +; slash + ld b, GENGAR_INTRO_TILES3 + call IntroCopyTiles + ld a, SFX_INTRO_CRASH + call PlaySound + lb de, 16 / 2, MOVE_GENGAR_RIGHT + call IntroMoveMon +; hip + ld a, SFX_INTRO_HIP + call PlaySound + ld a, (FightIntroFrontMon2 - FightIntroFrontMon) / BYTES_PER_TILE + ld [wIntroNidorinoBaseTile], a + ld de, IntroNidorinoAnimation3 + call AnimateIntroNidorino + ld c, 30 + call CheckForUserInterruption + ret c + + lb de, 8 / 2, MOVE_GENGAR_LEFT + call IntroMoveMon + ld b, GENGAR_INTRO_TILES1 + call IntroCopyTiles + ld c, 60 + call CheckForUserInterruption + ret c + +; hip + ld a, SFX_INTRO_HIP + call PlaySound + xor a + ld [wIntroNidorinoBaseTile], a + ld de, IntroNidorinoAnimation4 + call AnimateIntroNidorino +; hop + ld a, SFX_INTRO_HOP + call PlaySound + ld de, IntroNidorinoAnimation5 + call AnimateIntroNidorino + ld c, 20 + call CheckForUserInterruption + ret c + + ld a, (FightIntroFrontMon2 - FightIntroFrontMon) / BYTES_PER_TILE + ld [wIntroNidorinoBaseTile], a + ld de, IntroNidorinoAnimation6 + call AnimateIntroNidorino + ld c, 30 + call CheckForUserInterruption + ret c + +; lunge + ld a, SFX_INTRO_LUNGE + call PlaySound + ld a, (FightIntroFrontMon3 - FightIntroFrontMon) / BYTES_PER_TILE + ld [wIntroNidorinoBaseTile], a + ld de, IntroNidorinoAnimation7 + jp AnimateIntroNidorino + +AnimateIntroNidorino: + ld a, [de] + cp ANIMATION_END + ret z + ld [wBaseCoordY], a + inc de + ld a, [de] + ld [wBaseCoordX], a + push de + ld c, 6 * 6 + call UpdateIntroNidorinoOAM + ld c, 5 + call DelayFrames + pop de + inc de + jr AnimateIntroNidorino + +UpdateIntroNidorinoOAM: + ld hl, wOAMBuffer + ld a, [wIntroNidorinoBaseTile] + ld d, a +.loop + ld a, [wBaseCoordY] + add [hl] + ld [hli], a ; Y + ld a, [wBaseCoordX] + add [hl] + ld [hli], a ; X + ld a, d + ld [hli], a ; tile + inc hl + inc d + dec c + jr nz, .loop + ret + +InitIntroNidorinoOAM: + ld hl, wOAMBuffer + ld d, 0 +.loop + push bc + ld a, [wBaseCoordY] + ld e, a +.innerLoop + ld a, e + add 8 + ld e, a + ld [hli], a ; Y + ld a, [wBaseCoordX] + ld [hli], a ; X + ld a, d + ld [hli], a ; tile + ld a, OAM_BEHIND_BG + ld [hli], a ; attributes + inc d + dec c + jr nz, .innerLoop + ld a, [wBaseCoordX] + add 8 + ld [wBaseCoordX], a + pop bc + dec b + jr nz, .loop + ret + +IntroClearScreen: + ld hl, vBGMap1 + ld bc, BG_MAP_WIDTH * SCREEN_HEIGHT + jr IntroClearCommon + +IntroClearMiddleOfScreen: +; clear the area of the tile map between the black bars on the top and bottom + coord hl, 0, 4 + ld bc, SCREEN_WIDTH * 10 + +IntroClearCommon: + ld [hl], 0 + inc hl + dec bc + ld a, b + or c + jr nz, IntroClearCommon + ret + +IntroPlaceBlackTiles: + ld a, 1 +.loop + ld [hli], a + dec c + jr nz, .loop + ret + +IntroMoveMon: +; d = number of times to move the mon (2 pixels each time) + ld a, e + cp MOVE_NIDORINO_RIGHT + jr z, .moveNidorinoRight + cp MOVE_GENGAR_LEFT + jr z, .moveGengarLeft +; move Gengar right + ld a, [hSCX] + dec a + dec a + jr .next +.moveNidorinoRight + push de + ld a, 2 + ld [wBaseCoordX], a + xor a + ld [wBaseCoordY], a + ld c, 6 * 6 + call UpdateIntroNidorinoOAM + pop de +.moveGengarLeft + ld a, [hSCX] + inc a + inc a +.next + ld [hSCX], a + push de + ld c, 2 + call CheckForUserInterruption + pop de + ret c + dec d + jr nz, IntroMoveMon + ret + +IntroCopyTiles: + coord hl, 13, 7 + +CopyTileIDsFromList_ZeroBaseTileID: + ld c, 0 + predef_jump CopyTileIDsFromList + +PlayMoveSoundB: +; unused + predef GetMoveSoundB + ld a, b + jp PlaySound + +LoadIntroGraphics: + ld hl, FightIntroBackMon + ld de, vChars2 + ld bc, FightIntroBackMonEnd - FightIntroBackMon + ld a, BANK(FightIntroBackMon) + call FarCopyData2 + ld hl, GameFreakIntro + ld de, vChars2 + (FightIntroBackMonEnd - FightIntroBackMon) + ld bc, GameFreakIntroEnd - GameFreakIntro + ld a, BANK(GameFreakIntro) + call FarCopyData2 + ld hl, GameFreakIntro + ld de, vChars1 + ld bc, GameFreakIntroEnd - GameFreakIntro + ld a, BANK(GameFreakIntro) + call FarCopyData2 + ld hl, FightIntroFrontMon + ld de, vChars0 + ld bc, FightIntroFrontMonEnd - FightIntroFrontMon + ld a, BANK(FightIntroFrontMon) + jp FarCopyData2 + +PlayShootingStar: + ld b, SET_PAL_GAME_FREAK_INTRO + call RunPaletteCommand + callba LoadCopyrightAndTextBoxTiles + ldPal a, BLACK, DARK_GRAY, LIGHT_GRAY, WHITE + ld [rBGP], a + ld c, 180 + call DelayFrames + call ClearScreen + call DisableLCD + xor a + ld [wCurOpponent], a + call IntroDrawBlackBars + call LoadIntroGraphics + call EnableLCD + ld hl, rLCDC + res 5, [hl] + set 3, [hl] + ld c, 64 + call DelayFrames + callba AnimateShootingStar + push af + pop af + jr c, .next ; skip the delay if the user interrupted the animation + 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 + +IntroDrawBlackBars: +; clear the screen and draw black bars on the top and bottom + call IntroClearScreen + coord hl, 0, 0 + ld c, SCREEN_WIDTH * 4 + call IntroPlaceBlackTiles + coord hl, 0, 14 + ld c, SCREEN_WIDTH * 4 + call IntroPlaceBlackTiles + ld hl, vBGMap1 + ld c, BG_MAP_WIDTH * 4 + call IntroPlaceBlackTiles + ld hl, vBGMap1 + BG_MAP_WIDTH * 14 + ld c, BG_MAP_WIDTH * 4 + jp IntroPlaceBlackTiles + +EmptyFunc4: + ret + +IntroNidorinoAnimation0: + db 0, 0 + db ANIMATION_END + +IntroNidorinoAnimation1: +; This is a sequence of pixel movements for part of the Nidorino animation. This +; list describes how Nidorino should hop. +; First byte is y movement, second byte is x movement + db 0, 0 + db -2, 2 + db -1, 2 + db 1, 2 + db 2, 2 + db ANIMATION_END + +IntroNidorinoAnimation2: +; This is a sequence of pixel movements for part of the Nidorino animation. +; First byte is y movement, second byte is x movement + db 0, 0 + db -2, -2 + db -1, -2 + db 1, -2 + db 2, -2 + db ANIMATION_END + +IntroNidorinoAnimation3: +; This is a sequence of pixel movements for part of the Nidorino animation. +; First byte is y movement, second byte is x movement + db 0, 0 + db -12, 6 + db -8, 6 + db 8, 6 + db 12, 6 + db ANIMATION_END + +IntroNidorinoAnimation4: +; This is a sequence of pixel movements for part of the Nidorino animation. +; First byte is y movement, second byte is x movement + db 0, 0 + db -8, -4 + db -4, -4 + db 4, -4 + db 8, -4 + db ANIMATION_END + +IntroNidorinoAnimation5: +; This is a sequence of pixel movements for part of the Nidorino animation. +; First byte is y movement, second byte is x movement + db 0, 0 + db -8, 4 + db -4, 4 + db 4, 4 + db 8, 4 + db ANIMATION_END + +IntroNidorinoAnimation6: +; This is a sequence of pixel movements for part of the Nidorino animation. +; First byte is y movement, second byte is x movement + db 0, 0 + db 2, 0 + db 2, 0 + db 0, 0 + db ANIMATION_END + +IntroNidorinoAnimation7: +; This is a sequence of pixel movements for part of the Nidorino animation. +; First byte is y movement, second byte is x movement + db -8, -16 + db -7, -14 + db -6, -12 + db -4, -10 + db ANIMATION_END + +GameFreakIntro: + INCBIN "gfx/intro_credits/gamefreak_presents.2bpp" + INCBIN "gfx/intro_credits/gamefreak_logo.2bpp" + ds 16, $00 ; blank tile +GameFreakIntroEnd: + +FightIntroBackMon: + INCBIN "gfx/intro_credits/gengar.2bpp" +FightIntroBackMonEnd: + +FightIntroFrontMon: + +IF DEF(_RED) + INCBIN "gfx/intro_credits/red_nidorino_1.2bpp" +FightIntroFrontMon2: + INCBIN "gfx/intro_credits/red_nidorino_2.2bpp" +FightIntroFrontMon3: + INCBIN "gfx/intro_credits/red_nidorino_3.2bpp" +ENDC + +IF DEF(_BLUE) + INCBIN "gfx/intro_credits/blue_jigglypuff_1.2bpp" +FightIntroFrontMon2: + INCBIN "gfx/intro_credits/blue_jigglypuff_2.2bpp" +FightIntroFrontMon3: + INCBIN "gfx/intro_credits/blue_jigglypuff_3.2bpp" +ENDC + +FightIntroFrontMonEnd: + + ds 16, $00 ; blank tile diff --git a/engine/movie/oak_speech.asm b/engine/movie/oak_speech.asm new file mode 100755 index 00000000..b1acfb65 --- /dev/null +++ b/engine/movie/oak_speech.asm @@ -0,0 +1,233 @@ +SetDefaultNames: + ld a, [wLetterPrintingDelayFlags] + push af + ld a, [wOptions] + push af + ld a, [wd732] + push af + ld hl, wPlayerName + ld bc, wBoxDataEnd - wPlayerName + xor a + call FillMemory + ld hl, wSpriteStateData1 + ld bc, $200 + xor a + call FillMemory + pop af + ld [wd732], a + pop af + ld [wOptions], a + pop af + ld [wLetterPrintingDelayFlags], a + ld a, [wOptionsInitialized] + and a + call z, InitOptions + ld hl, NintenText + ld de, wPlayerName + ld bc, NAME_LENGTH + call CopyData + ld hl, SonyText + ld de, wRivalName + ld bc, NAME_LENGTH + jp CopyData + +OakSpeech: + ld a, $FF + call PlaySound ; stop music + ld a, BANK(Music_Routes2) + ld c, a + ld a, MUSIC_ROUTES2 + call PlayMusic + call ClearScreen + call LoadTextBoxTilePatterns + call SetDefaultNames + predef InitPlayerData2 + ld hl, wNumBoxItems + ld a, POTION + ld [wcf91], a + ld a, 1 + ld [wItemQuantity], a + call AddItemToInventory ; give one potion + ld a, [wDefaultMap] + ld [wDestinationMap], a + call SpecialWarpIn + xor a + ld [hTilesetType], a + ld a, [wd732] + bit 1, a ; possibly a debug mode bit + jp nz, .skipChoosingNames + ld de, ProfOakPic + lb bc, Bank(ProfOakPic), $00 + call IntroDisplayPicCenteredOrUpperRight + call FadeInIntroPic + ld hl, OakSpeechText1 + call PrintText + call GBFadeOutToWhite + call ClearScreen + ld a, NIDORINO + ld [wd0b5], a + ld [wcf91], a + call GetMonHeader + coord hl, 6, 4 + call LoadFlippedFrontSpriteByMonIndex + call MovePicLeft + ld hl, OakSpeechText2 + call PrintText + call GBFadeOutToWhite + call ClearScreen + ld de, RedPicFront + lb bc, Bank(RedPicFront), $00 + call IntroDisplayPicCenteredOrUpperRight + call MovePicLeft + ld hl, IntroducePlayerText + call PrintText + call ChoosePlayerName + call GBFadeOutToWhite + call ClearScreen + ld de, Rival1Pic + lb bc, Bank(Rival1Pic), $00 + call IntroDisplayPicCenteredOrUpperRight + call FadeInIntroPic + ld hl, IntroduceRivalText + call PrintText + call ChooseRivalName +.skipChoosingNames + call GBFadeOutToWhite + call ClearScreen + ld de, RedPicFront + lb bc, Bank(RedPicFront), $00 + call IntroDisplayPicCenteredOrUpperRight + call GBFadeInFromWhite + ld a, [wd72d] + and a + jr nz, .next + ld hl, OakSpeechText3 + call PrintText +.next + ld a, [H_LOADEDROMBANK] + push af + ld a, SFX_SHRINK + call PlaySound + pop af + ld [H_LOADEDROMBANK], a + ld [MBC1RomBank], a + ld c, 4 + call DelayFrames + ld de, RedSprite + ld hl, vSprites + lb bc, BANK(RedSprite), $0C + call CopyVideoData + ld de, ShrinkPic1 + lb bc, BANK(ShrinkPic1), $00 + call IntroDisplayPicCenteredOrUpperRight + ld c, 4 + call DelayFrames + ld de, ShrinkPic2 + lb bc, BANK(ShrinkPic2), $00 + call IntroDisplayPicCenteredOrUpperRight + call ResetPlayerSpriteData + ld a, [H_LOADEDROMBANK] + push af + ld a, BANK(Music_PalletTown) + ld [wAudioROMBank], a + ld [wAudioSavedROMBank], a + ld a, 10 + ld [wAudioFadeOutControl], a + ld a, $FF + ld [wNewSoundID], a + call PlaySound ; stop music + pop af + ld [H_LOADEDROMBANK], a + ld [MBC1RomBank], a + ld c, 20 + call DelayFrames + coord hl, 6, 5 + ld b, 7 + ld c, 7 + call ClearScreenArea + call LoadTextBoxTilePatterns + ld a, 1 + ld [wUpdateSpritesEnabled], a + ld c, 50 + call DelayFrames + call GBFadeOutToWhite + jp ClearScreen +OakSpeechText1: + TX_FAR _OakSpeechText1 + db "@" +OakSpeechText2: + TX_FAR _OakSpeechText2A + TX_CRY_NIDORINA + TX_FAR _OakSpeechText2B + db "@" +IntroducePlayerText: + TX_FAR _IntroducePlayerText + db "@" +IntroduceRivalText: + TX_FAR _IntroduceRivalText + db "@" +OakSpeechText3: + TX_FAR _OakSpeechText3 + db "@" + +FadeInIntroPic: + ld hl, IntroFadePalettes + ld b, 6 +.next + ld a, [hli] + ld [rBGP], a + ld c, 10 + call DelayFrames + dec b + jr nz, .next + ret + +IntroFadePalettes: + db %01010100 + db %10101000 + db %11111100 + db %11111000 + db %11110100 + db %11100100 + +MovePicLeft: + ld a, 119 + ld [rWX], a + call DelayFrame + + ld a, %11100100 + ld [rBGP], a +.next + call DelayFrame + ld a, [rWX] + sub 8 + cp $FF + ret z + ld [rWX], a + jr .next + +DisplayPicCenteredOrUpperRight: + call GetPredefRegisters +IntroDisplayPicCenteredOrUpperRight: +; b = bank +; de = address of compressed pic +; c: 0 = centred, non-zero = upper-right + push bc + ld a, b + call UncompressSpriteFromDE + ld hl, sSpriteBuffer1 + ld de, sSpriteBuffer0 + ld bc, $310 + call CopyData + ld de, vFrontPic + call InterlaceMergeSpriteBuffers + pop bc + ld a, c + and a + coord hl, 15, 1 + jr nz, .next + coord hl, 6, 4 +.next + xor a + ld [hStartTileID], a + predef_jump CopyUncompressedPicToTilemap diff --git a/engine/movie/oak_speech2.asm b/engine/movie/oak_speech2.asm new file mode 100755 index 00000000..fdc9ffa3 --- /dev/null +++ b/engine/movie/oak_speech2.asm @@ -0,0 +1,219 @@ +ChoosePlayerName: + call OakSpeechSlidePicRight + ld de, DefaultNamesPlayer + call DisplayIntroNameTextBox + ld a, [wCurrentMenuItem] + and a + jr z, .customName + ld hl, DefaultNamesPlayerList + call GetDefaultName + ld de, wPlayerName + call OakSpeechSlidePicLeft + jr .done +.customName + ld hl, wPlayerName + xor a ; NAME_PLAYER_SCREEN + ld [wNamingScreenType], a + call DisplayNamingScreen + ld a, [wcf4b] + cp "@" + jr z, .customName + call ClearScreen + call Delay3 + ld de, RedPicFront + ld b, BANK(RedPicFront) + call IntroDisplayPicCenteredOrUpperRight +.done + ld hl, YourNameIsText + jp PrintText + +YourNameIsText: + TX_FAR _YourNameIsText + db "@" + +ChooseRivalName: + call OakSpeechSlidePicRight + ld de, DefaultNamesRival + call DisplayIntroNameTextBox + ld a, [wCurrentMenuItem] + and a + jr z, .customName + ld hl, DefaultNamesRivalList + call GetDefaultName + ld de, wRivalName + call OakSpeechSlidePicLeft + jr .done +.customName + ld hl, wRivalName + ld a, NAME_RIVAL_SCREEN + ld [wNamingScreenType], a + call DisplayNamingScreen + ld a, [wcf4b] + cp "@" + jr z, .customName + call ClearScreen + call Delay3 + ld de, Rival1Pic + ld b, $13 + call IntroDisplayPicCenteredOrUpperRight +.done + ld hl, HisNameIsText + jp PrintText + +HisNameIsText: + TX_FAR _HisNameIsText + db "@" + +OakSpeechSlidePicLeft: + push de + coord hl, 0, 0 + lb bc, 12, 11 + call ClearScreenArea ; clear the name list text box + ld c, 10 + call DelayFrames + pop de + ld hl, wcd6d + ld bc, NAME_LENGTH + call CopyData + call Delay3 + coord hl, 12, 4 + lb de, 6, 6 * SCREEN_WIDTH + 5 + ld a, $ff + jr OakSpeechSlidePicCommon + +OakSpeechSlidePicRight: + coord hl, 5, 4 + lb de, 6, 6 * SCREEN_WIDTH + 5 + xor a + +OakSpeechSlidePicCommon: + push hl + push de + push bc + ld [hSlideDirection], a + ld a, d + ld [hSlideAmount], a + ld a, e + ld [hSlidingRegionSize], a + ld c, a + ld a, [hSlideDirection] + and a + jr nz, .next +; If sliding right, point hl to the end of the pic's tiles. + ld d, 0 + add hl, de +.next + ld d, h + ld e, l +.loop + xor a + ld [H_AUTOBGTRANSFERENABLED], a + ld a, [hSlideDirection] + and a + jr nz, .slideLeft +; sliding right + ld a, [hli] + ld [hld], a + dec hl + jr .next2 +.slideLeft + ld a, [hld] + ld [hli], a + inc hl +.next2 + dec c + jr nz, .loop + ld a, [hSlideDirection] + and a + jr z, .next3 +; 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 + ld [hl], a +.next3 + ld a, 1 + ld [H_AUTOBGTRANSFERENABLED], a + call Delay3 + ld a, [hSlidingRegionSize] + ld c, a + ld h, d + ld l, e + ld a, [hSlideDirection] + and a + jr nz, .slideLeft2 + inc hl + jr .next4 +.slideLeft2 + dec hl +.next4 + ld d, h + ld e, l + ld a, [hSlideAmount] + dec a + ld [hSlideAmount], a + jr nz, .loop + pop bc + pop de + pop hl + ret + +DisplayIntroNameTextBox: + push de + coord hl, 0, 0 + ld b, $a + ld c, $9 + call TextBoxBorder + coord hl, 3, 0 + ld de, .namestring + call PlaceString + pop de + coord hl, 2, 2 + call PlaceString + call UpdateSprites + xor a + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + inc a + ld [wTopMenuItemX], a + ld [wMenuWatchedKeys], a ; A_BUTTON + inc a + ld [wTopMenuItemY], a + inc a + ld [wMaxMenuItem], a + jp HandleMenuInput + +.namestring + db "NAME@" + +INCLUDE "text/player_names.asm" + +GetDefaultName: +; a = name index +; hl = name list + ld b, a + ld c, 0 +.loop + ld d, h + ld e, l +.innerLoop + ld a, [hli] + cp "@" + jr nz, .innerLoop + ld a, b + cp c + jr z, .foundName + inc c + jr .loop +.foundName + ld h, d + ld l, e + ld de, wcd6d + ld bc, $14 + jp CopyData + +INCLUDE "text/player_names_list.asm" + +TextTerminator_6b20: + db "@" diff --git a/engine/movie/titlescreen.asm b/engine/movie/titlescreen.asm new file mode 100755 index 00000000..c30f83a9 --- /dev/null +++ b/engine/movie/titlescreen.asm @@ -0,0 +1,403 @@ +; 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 + call CopyFixedLengthText + ld hl, SonyText + ld de, wRivalName + call CopyFixedLengthText + xor a + ld [hWY], a + ld [wLetterPrintingDelayFlags], a + ld hl, wd732 + ld [hli], a + ld [hli], a + ld [hl], a + ld a, BANK(Music_TitleScreen) + ld [wAudioROMBank], a + ld [wAudioSavedROMBank], a + +DisplayTitleScreen: + call GBPalWhiteOut + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + xor a + ld [hTilesetType], a + ld [hSCX], a + ld a, $40 + ld [hSCY], a + ld a, $90 + ld [hWY], a + call ClearScreen + call DisableLCD + call LoadFontTilePatterns + ld hl, NintendoCopyrightLogoGraphics + ld de, vTitleLogo2 + $100 + ld bc, $50 + ld a, BANK(NintendoCopyrightLogoGraphics) + call FarCopyData2 + ld hl, GamefreakLogoGraphics + ld de, vTitleLogo2 + $100 + $50 + ld bc, $90 + ld a, BANK(GamefreakLogoGraphics) + call FarCopyData2 + ld hl, PokemonLogoGraphics + ld de, vTitleLogo + ld bc, $600 + ld a, BANK(PokemonLogoGraphics) + call FarCopyData2 ; first chunk + ld hl, PokemonLogoGraphics+$600 + ld de, vTitleLogo2 + ld bc, $100 + ld a, BANK(PokemonLogoGraphics) + call FarCopyData2 ; second chunk + ld hl, Version_GFX + ld de, vChars2 + $600 - (Version_GFXEnd - Version_GFX - $50) + ld bc, Version_GFXEnd - Version_GFX + ld a, BANK(Version_GFX) + call FarCopyDataDouble + call ClearBothBGMaps + +; place tiles for pokemon logo (except for the last row) + coord hl, 2, 1 + ld a, $80 + ld de, SCREEN_WIDTH + ld c, 6 +.pokemonLogoTileLoop + ld b, $10 + push hl +.pokemonLogoTileRowLoop ; place tiles for one row + ld [hli], a + inc a + dec b + jr nz, .pokemonLogoTileRowLoop + pop hl + add hl, de + dec c + jr nz, .pokemonLogoTileLoop + +; place tiles for the last row of the pokemon logo + coord hl, 2, 7 + ld a, $31 + ld b, $10 +.pokemonLogoLastTileRowLoop + ld [hli], a + inc a + dec b + jr nz, .pokemonLogoLastTileRowLoop + + call DrawPlayerCharacter + +; put a pokeball in the player's hand + ld hl, wOAMBuffer + $28 + ld a, $74 + ld [hl], a + +; place tiles for title screen copyright + coord hl, 2, 17 + ld de, .tileScreenCopyrightTiles + ld b, $10 +.tileScreenCopyrightTilesLoop + ld a, [de] + ld [hli], a + inc de + dec b + jr nz, .tileScreenCopyrightTilesLoop + + jr .next + +.tileScreenCopyrightTiles + db $41,$42,$43,$42,$44,$42,$45,$46,$47,$48,$49,$4A,$4B,$4C,$4D,$4E ; ©'95.'96.'98 GAME FREAK inc. + +.next + call SaveScreenTilesToBuffer2 + call LoadScreenTilesFromBuffer2 + call EnableLCD +IF DEF(_RED) + ld a, CHARMANDER ; which Pokemon to show first on the title screen +ENDC +IF DEF(_BLUE) + ld a, SQUIRTLE ; which Pokemon to show first on the title screen +ENDC + + ld [wTitleMonSpecies], a + call LoadTitleMonSprite + ld a, (vBGMap0 + $300) / $100 + call TitleScreenCopyTileMapToVRAM + call SaveScreenTilesToBuffer1 + ld a, $40 + ld [hWY], a + call LoadScreenTilesFromBuffer2 + ld a, vBGMap0 / $100 + call TitleScreenCopyTileMapToVRAM + ld b, SET_PAL_TITLE_SCREEN + call RunPaletteCommand + call GBPalNormal + ld a, %11100100 + ld [rOBP0], a + +; make pokemon logo bounce up and down + ld bc, hSCY ; background scroll Y + ld hl, .TitleScreenPokemonLogoYScrolls +.bouncePokemonLogoLoop + ld a, [hli] + and a + jr z, .finishedBouncingPokemonLogo + ld d, a + cp -3 + jr nz, .skipPlayingSound + ld a, SFX_INTRO_CRASH + call PlaySound +.skipPlayingSound + ld a, [hli] + ld e, a + call .ScrollTitleScreenPokemonLogo + jr .bouncePokemonLogoLoop + +.TitleScreenPokemonLogoYScrolls: +; Controls the bouncing effect of the Pokemon logo on the title screen + db -4,16 ; y scroll amount, number of times to scroll + db 3,4 + db -3,4 + db 2,2 + db -2,2 + db 1,2 + db -1,2 + db 0 ; terminate list with 0 + +.ScrollTitleScreenPokemonLogo: +; Scrolls the Pokemon logo on the title screen to create the bouncing effect +; Scrolls d pixels e times + call DelayFrame + ld a, [bc] ; background scroll Y + add d + ld [bc], a + dec e + jr nz, .ScrollTitleScreenPokemonLogo + ret + +.finishedBouncingPokemonLogo + call LoadScreenTilesFromBuffer1 + ld c, 36 + call DelayFrames + ld a, SFX_INTRO_WHOOSH + call PlaySound + +; scroll game version in from the right + call PrintGameVersionOnTitleScreen + ld a, SCREEN_HEIGHT_PIXELS + ld [hWY], a + ld d, 144 +.scrollTitleScreenGameVersionLoop + ld h, d + ld l, 64 + call ScrollTitleScreenGameVersion + ld h, 0 + ld l, 80 + call ScrollTitleScreenGameVersion + ld a, d + add 4 + ld d, a + and a + jr nz, .scrollTitleScreenGameVersionLoop + + ld a, vBGMap1 / $100 + call TitleScreenCopyTileMapToVRAM + call LoadScreenTilesFromBuffer2 + call PrintGameVersionOnTitleScreen + call Delay3 + call WaitForSoundToFinish + ld a, MUSIC_TITLE_SCREEN + ld [wNewSoundID], a + call PlaySound + xor a + ld [wUnusedCC5B], a + +; Keep scrolling in new mons indefinitely until the user performs input. +.awaitUserInterruptionLoop + ld c, 200 + call CheckForUserInterruption + jr c, .finishedWaiting + call TitleScreenScrollInMon + ld c, 1 + call CheckForUserInterruption + jr c, .finishedWaiting + callba TitleScreenAnimateBallIfStarterOut + call TitleScreenPickNewMon + jr .awaitUserInterruptionLoop + +.finishedWaiting + ld a, [wTitleMonSpecies] + call PlayCry + call WaitForSoundToFinish + call GBPalWhiteOutWithDelay3 + call ClearSprites + xor a + ld [hWY], a + inc a + ld [H_AUTOBGTRANSFERENABLED], a + call ClearScreen + ld a, vBGMap0 / $100 + call TitleScreenCopyTileMapToVRAM + ld a, vBGMap1 / $100 + call TitleScreenCopyTileMapToVRAM + call Delay3 + call LoadGBPal + ld a, [hJoyHeld] + ld b, a + and D_UP | SELECT | B_BUTTON + cp D_UP | SELECT | B_BUTTON + jp z, .doClearSaveDialogue + jp MainMenu + +.doClearSaveDialogue + jpba DoClearSaveDialogue + +TitleScreenPickNewMon: + ld a, vBGMap0 / $100 + call TitleScreenCopyTileMapToVRAM + +.loop +; Keep looping until a mon different from the current one is picked. + call Random + and $f + ld c, a + ld b, 0 + ld hl, TitleMons + add hl, bc + ld a, [hl] + ld hl, wTitleMonSpecies + +; Can't be the same as before. + cp [hl] + jr z, .loop + + ld [hl], a + call LoadTitleMonSprite + + ld a, $90 + ld [hWY], a + ld d, 1 ; scroll out + callba TitleScroll + ret + +TitleScreenScrollInMon: + ld d, 0 ; scroll in + callba TitleScroll + xor a + ld [hWY], a + ret + +ScrollTitleScreenGameVersion: +.wait + ld a, [rLY] + cp l + jr nz, .wait + + ld a, h + ld [rSCX], a + +.wait2 + ld a, [rLY] + cp h + jr z, .wait2 + ret + +DrawPlayerCharacter: + ld hl, PlayerCharacterTitleGraphics + ld de, vSprites + ld bc, PlayerCharacterTitleGraphicsEnd - PlayerCharacterTitleGraphics + ld a, BANK(PlayerCharacterTitleGraphics) + call FarCopyData2 + call ClearSprites + xor a + ld [wPlayerCharacterOAMTile], a + ld hl, wOAMBuffer + ld de, $605a + ld b, 7 +.loop + push de + ld c, 5 +.innerLoop + ld a, d + ld [hli], a ; Y + ld a, e + ld [hli], a ; X + add 8 + ld e, a + ld a, [wPlayerCharacterOAMTile] + ld [hli], a ; tile + 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 + +ClearBothBGMaps: + ld hl, vBGMap0 + ld bc, $400 * 2 + ld a, " " + jp FillMemory + +LoadTitleMonSprite: + ld [wcf91], a + ld [wd0b5], a + coord hl, 5, 10 + call GetMonHeader + jp LoadFrontSpriteByMonIndex + +TitleScreenCopyTileMapToVRAM: + ld [H_AUTOBGTRANSFERDEST + 1], a + jp Delay3 + +LoadCopyrightAndTextBoxTiles: + xor a + ld [hWY], a + call ClearScreen + call LoadTextBoxTilePatterns + +LoadCopyrightTiles: + ld de, NintendoCopyrightLogoGraphics + ld hl, vChars2 + $600 + lb bc, BANK(NintendoCopyrightLogoGraphics), (GamefreakLogoGraphicsEnd - NintendoCopyrightLogoGraphics) / $10 + call CopyVideoData + coord hl, 2, 7 + ld de, CopyrightTextString + jp PlaceString + +CopyrightTextString: + db $60,$61,$62,$61,$63,$61,$64,$7F,$65,$66,$67,$68,$69,$6A ; ©'95.'96.'98 Nintendo + next $60,$61,$62,$61,$63,$61,$64,$7F,$6B,$6C,$6D,$6E,$6F,$70,$71,$72 ; ©'95.'96.'98 Creatures inc. + next $60,$61,$62,$61,$63,$61,$64,$7F,$73,$74,$75,$76,$77,$78,$79,$7A,$7B ; ©'95.'96.'98 GAME FREAK inc. + db "@" + +INCLUDE "data/title_mons.asm" + +; prints version text (red, blue) +PrintGameVersionOnTitleScreen: + coord hl, 7, 8 + ld de, VersionOnTitleScreenText + jp PlaceString + +; 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 + +NintenText: db "NINTEN@" +SonyText: db "SONY@" diff --git a/engine/movie/titlescreen2.asm b/engine/movie/titlescreen2.asm new file mode 100755 index 00000000..2346fcc5 --- /dev/null +++ b/engine/movie/titlescreen2.asm @@ -0,0 +1,120 @@ +TitleScroll_WaitBall: +; Wait around for the TitleBall animation to play out. +; hi: speed +; lo: duration + db $05, $05, 0 + +TitleScroll_In: +; Scroll a TitleMon in from the right. +; hi: speed +; lo: duration + db $a2, $94, $84, $63, $52, $31, $11, 0 + +TitleScroll_Out: +; Scroll a TitleMon out to the left. +; hi: speed +; lo: duration + db $12, $22, $32, $42, $52, $62, $83, $93, 0 + +TitleScroll: + ld a, d + + ld bc, TitleScroll_In + ld d, $88 + ld e, 0 ; don't animate titleball + + and a + jr nz, .ok + + ld bc, TitleScroll_Out + ld d, $00 + ld e, 0 ; don't animate titleball +.ok + +_TitleScroll: + ld a, [bc] + and a + ret z + + inc bc + push bc + + ld b, a + and $f + ld c, a + ld a, b + and $f0 + swap a + ld b, a + +.loop + ld h, d + ld l, $48 + call .ScrollBetween + + ld h, $00 + ld l, $88 + call .ScrollBetween + + ld a, d + add b + ld d, a + + call GetTitleBallY + dec c + jr nz, .loop + + pop bc + jr _TitleScroll + +.ScrollBetween: +.wait + ld a, [rLY] ; rLY + cp l + jr nz, .wait + + ld a, h + ld [rSCX], a + +.wait2 + ld a, [rLY] ; rLY + cp h + jr z, .wait2 + ret + +TitleBallYTable: +; OBJ y-positions for the Poke Ball held by Red in the title screen. +; This is really two 0-terminated lists. Initiated with an index of 1. + db 0, $71, $6f, $6e, $6d, $6c, $6d, $6e, $6f, $71, $74, 0 + +TitleScreenAnimateBallIfStarterOut: +; Animate the TitleBall if a starter just got scrolled out. + ld a, [wTitleMonSpecies] + cp STARTER1 + jr z, .ok + cp STARTER2 + jr z, .ok + cp STARTER3 + ret nz +.ok + ld e, 1 ; animate titleball + ld bc, TitleScroll_WaitBall + ld d, 0 + jp _TitleScroll + +GetTitleBallY: +; Get position e from TitleBallYTable + push de + push hl + xor a + ld d, a + ld hl, TitleBallYTable + add hl, de + ld a, [hl] + pop hl + pop de + and a + ret z + ld [wOAMBuffer + $28], a + inc e + ret diff --git a/engine/movie/trade.asm b/engine/movie/trade.asm new file mode 100755 index 00000000..8bc8e3bc --- /dev/null +++ b/engine/movie/trade.asm @@ -0,0 +1,853 @@ +InternalClockTradeAnim: +; Do the trading animation with the player's gameboy on the left. +; In-game trades and internally clocked link cable trades use this. + ld a, [wTradedPlayerMonSpecies] + ld [wLeftGBMonSpecies], a + ld a, [wTradedEnemyMonSpecies] + ld [wRightGBMonSpecies], a + ld de, InternalClockTradeFuncSequence + jr TradeAnimCommon + +ExternalClockTradeAnim: +; Do the trading animation with the player's gameboy on the right. +; Externally clocked link cable trades use this. + ld a, [wTradedEnemyMonSpecies] + ld [wLeftGBMonSpecies], a + ld a, [wTradedPlayerMonSpecies] + ld [wRightGBMonSpecies], a + ld de, ExternalClockTradeFuncSequence + +TradeAnimCommon: + ld a, [wOptions] + push af + ld a, [hSCY] + push af + ld a, [hSCX] + push af + xor a + ld [wOptions], a + ld [hSCY], a + ld [hSCX], a + push de +.loop + pop de + ld a, [de] + cp $ff + jr z, .done + inc de + push de + ld hl, TradeFuncPointerTable + add a + ld c, a + ld b, $0 + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld de, .loop + push de + jp hl ; call trade func, which will return to the top of the loop +.done + pop af + ld [hSCX], a + pop af + ld [hSCY], a + pop af + ld [wOptions], a + ret + +addtradefunc: MACRO +\1TradeFunc:: + dw \1 + ENDM + +tradefunc: MACRO + db (\1TradeFunc - TradeFuncPointerTable) / 2 + ENDM + +; The functions in the sequences below are executed in order by TradeFuncCommon. +; They are from opposite perspectives. The external clock one makes use of +; Trade_SwapNames to swap the player and enemy names for some functions. + +InternalClockTradeFuncSequence: + tradefunc LoadTradingGFXAndMonNames + tradefunc Trade_ShowPlayerMon + tradefunc Trade_DrawOpenEndOfLinkCable + tradefunc Trade_AnimateBallEnteringLinkCable + tradefunc Trade_AnimLeftToRight + tradefunc Trade_Delay100 + tradefunc Trade_ShowClearedWindow + tradefunc PrintTradeWentToText + tradefunc PrintTradeForSendsText + tradefunc PrintTradeFarewellText + tradefunc Trade_AnimRightToLeft + tradefunc Trade_ShowClearedWindow + tradefunc Trade_DrawOpenEndOfLinkCable + tradefunc Trade_ShowEnemyMon + tradefunc Trade_Delay100 + tradefunc Trade_Cleanup + db $FF + +ExternalClockTradeFuncSequence: + tradefunc LoadTradingGFXAndMonNames + tradefunc Trade_ShowClearedWindow + tradefunc PrintTradeWillTradeText + tradefunc PrintTradeFarewellText + tradefunc Trade_SwapNames + tradefunc Trade_AnimLeftToRight + tradefunc Trade_SwapNames + tradefunc Trade_ShowClearedWindow + tradefunc Trade_DrawOpenEndOfLinkCable + tradefunc Trade_ShowEnemyMon + tradefunc Trade_SlideTextBoxOffScreen + tradefunc Trade_ShowPlayerMon + tradefunc Trade_DrawOpenEndOfLinkCable + tradefunc Trade_AnimateBallEnteringLinkCable + tradefunc Trade_SwapNames + tradefunc Trade_AnimRightToLeft + tradefunc Trade_SwapNames + tradefunc Trade_Delay100 + tradefunc Trade_ShowClearedWindow + tradefunc PrintTradeWentToText + tradefunc Trade_Cleanup + db $FF + +TradeFuncPointerTable: + addtradefunc LoadTradingGFXAndMonNames + addtradefunc Trade_ShowPlayerMon + addtradefunc Trade_DrawOpenEndOfLinkCable + addtradefunc Trade_AnimateBallEnteringLinkCable + addtradefunc Trade_ShowEnemyMon + addtradefunc Trade_AnimLeftToRight + addtradefunc Trade_AnimRightToLeft + addtradefunc Trade_Delay100 + addtradefunc Trade_ShowClearedWindow + addtradefunc PrintTradeWentToText + addtradefunc PrintTradeForSendsText + addtradefunc PrintTradeFarewellText + addtradefunc PrintTradeTakeCareText + addtradefunc PrintTradeWillTradeText + addtradefunc Trade_Cleanup + addtradefunc Trade_SlideTextBoxOffScreen + addtradefunc Trade_SwapNames + +Trade_Delay100: + ld c, 100 + jp DelayFrames + +Trade_CopyTileMapToVRAM: + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + call Delay3 + xor a + ld [H_AUTOBGTRANSFERENABLED], a + ret + +Trade_Delay80: + ld c, 80 + jp DelayFrames + +Trade_ClearTileMap: + coord hl, 0, 0 + ld bc, SCREEN_WIDTH * SCREEN_HEIGHT + ld a, " " + jp FillMemory + +LoadTradingGFXAndMonNames: + call Trade_ClearTileMap + call DisableLCD + ld hl, TradingAnimationGraphics + ld de, vChars2 + $310 + ld bc, TradingAnimationGraphicsEnd - TradingAnimationGraphics + ld a, BANK(TradingAnimationGraphics) + call FarCopyData2 + ld hl, TradingAnimationGraphics2 + ld de, vSprites + $7c0 + ld bc, TradingAnimationGraphics2End - TradingAnimationGraphics2 + ld a, BANK(TradingAnimationGraphics2) + call FarCopyData2 + ld hl, vBGMap0 + ld bc, $800 + ld a, " " + call FillMemory + call ClearSprites + ld a, $ff + ld [wUpdateSpritesEnabled], a + ld hl, wd730 + set 6, [hl] ; turn on instant text printing + ld a, [wOnSGB] + and a + ld a, $e4 ; non-SGB OBP0 + jr z, .next + ld a, $f0 ; SGB OBP0 +.next + ld [rOBP0], a + call EnableLCD + xor a + ld [H_AUTOBGTRANSFERENABLED], a + ld a, [wTradedPlayerMonSpecies] + ld [wd11e], a + call GetMonName + ld hl, wcd6d + ld de, wcf4b + ld bc, NAME_LENGTH + call CopyData + ld a, [wTradedEnemyMonSpecies] + ld [wd11e], a + jp GetMonName + +Trade_LoadMonPartySpriteGfx: + ld a, %11010000 + ld [rOBP1], a + jpba LoadMonPartySpriteGfx + +Trade_SwapNames: + ld hl, wPlayerName + ld de, wBuffer + ld bc, NAME_LENGTH + call CopyData + ld hl, wLinkEnemyTrainerName + ld de, wPlayerName + ld bc, NAME_LENGTH + call CopyData + ld hl, wBuffer + ld de, wLinkEnemyTrainerName + ld bc, NAME_LENGTH + jp CopyData + +Trade_Cleanup: + xor a + call LoadGBPal + ld hl, wd730 + res 6, [hl] ; turn off instant text printing + ret + +Trade_ShowPlayerMon: + ld a, %10101011 + ld [rLCDC], a + ld a, $50 + ld [hWY], a + ld a, $86 + ld [rWX], a + ld [hSCX], a + xor a + ld [H_AUTOBGTRANSFERENABLED], a + coord hl, 4, 0 + ld b, 6 + ld c, 10 + call TextBoxBorder + call Trade_PrintPlayerMonInfoText + ld b, vBGMap0 / $100 + call CopyScreenTileBufferToVRAM + call ClearScreen + ld a, [wTradedPlayerMonSpecies] + call Trade_LoadMonSprite + ld a, $7e +.slideScreenLoop + push af + call DelayFrame + pop af + ld [rWX], a + ld [hSCX], a + dec a + dec a + and a + jr nz, .slideScreenLoop + call Trade_Delay80 + ld a, TRADE_BALL_POOF_ANIM + call Trade_ShowAnimation + ld a, TRADE_BALL_DROP_ANIM + call Trade_ShowAnimation ; clears mon pic + ld a, [wTradedPlayerMonSpecies] + call PlayCry + xor a + ld [H_AUTOBGTRANSFERENABLED], a + ret + +Trade_DrawOpenEndOfLinkCable: + call Trade_ClearTileMap + ld b, vBGMap0 / $100 + call CopyScreenTileBufferToVRAM + ld b, SET_PAL_GENERIC + call RunPaletteCommand + +; This function call is pointless. It just copies blank tiles to VRAM that was +; already filled with blank tiles. + ld hl, vBGMap1 + $8c + call Trade_CopyCableTilesOffScreen + + ld a, $a0 + ld [hSCX], a + call DelayFrame + ld a, %10001011 + ld [rLCDC], a + coord hl, 6, 2 + ld b, $7 ; open end of link cable tile ID list index + call CopyTileIDsFromList_ZeroBaseTileID + call Trade_CopyTileMapToVRAM + ld a, SFX_HEAL_HP + call PlaySound + ld c, 20 +.loop + ld a, [hSCX] + add 4 + ld [hSCX], a + dec c + jr nz, .loop + ret + +Trade_AnimateBallEnteringLinkCable: + ld a, TRADE_BALL_SHAKE_ANIM + call Trade_ShowAnimation + ld c, 10 + call DelayFrames + ld a, %11100100 + ld [rOBP0], a + xor a + ld [wLinkCableAnimBulgeToggle], a + lb bc, $20, $60 +.moveBallInsideLinkCableLoop + push bc + xor a + ld de, Trade_BallInsideLinkCableOAM + call WriteOAMBlock + ld a, [wLinkCableAnimBulgeToggle] + xor $1 + ld [wLinkCableAnimBulgeToggle], a + add $7e + ld hl, wOAMBuffer + $02 + ld de, 4 + ld c, e +.cycleLinkCableBulgeTile + ld [hl], a + add hl, de + dec c + jr nz, .cycleLinkCableBulgeTile + call Delay3 + pop bc + ld a, c + add $4 + ld c, a + cp $a0 + jr nc, .ballSpriteReachedEdgeOfScreen + ld a, SFX_TINK + call PlaySound + jr .moveBallInsideLinkCableLoop +.ballSpriteReachedEdgeOfScreen + call ClearSprites + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + call ClearScreen + ld b, $98 + call CopyScreenTileBufferToVRAM + call Delay3 + xor a + ld [H_AUTOBGTRANSFERENABLED], a + ret + +Trade_BallInsideLinkCableOAM: + db $7E,$00,$7E,$20 + db $7E,$40,$7E,$60 + +Trade_ShowEnemyMon: + ld a, TRADE_BALL_TILT_ANIM + call Trade_ShowAnimation + call Trade_ShowClearedWindow + coord hl, 4, 10 + ld b, 6 + ld c, 10 + call TextBoxBorder + call Trade_PrintEnemyMonInfoText + call Trade_CopyTileMapToVRAM + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + ld a, [wTradedEnemyMonSpecies] + call Trade_LoadMonSprite + ld a, TRADE_BALL_POOF_ANIM + call Trade_ShowAnimation + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + ld a, [wTradedEnemyMonSpecies] + call PlayCry + call Trade_Delay100 + coord hl, 4, 10 + lb bc, 8, 12 + call ClearScreenArea + jp PrintTradeTakeCareText + +Trade_AnimLeftToRight: +; Animates the mon moving from the left GB to the right one. + call Trade_InitGameboyTransferGfx + ld a, $1 + ld [wTradedMonMovingRight], a + ld a, %11100100 + ld [rOBP0], a + ld a, $54 + ld [wBaseCoordX], a + ld a, $1c + ld [wBaseCoordY], a + ld a, [wLeftGBMonSpecies] + ld [wMonPartySpriteSpecies], a + call Trade_WriteCircledMonOAM + call Trade_DrawLeftGameboy + call Trade_CopyTileMapToVRAM + call Trade_DrawCableAcrossScreen + ld hl, vBGMap1 + $8c + call Trade_CopyCableTilesOffScreen + ld b, $6 + call Trade_AnimMonMoveHorizontal + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + call Trade_DrawCableAcrossScreen + ld b, $4 + call Trade_AnimMonMoveHorizontal + call Trade_DrawRightGameboy + ld b, $6 + call Trade_AnimMonMoveHorizontal + xor a + ld [H_AUTOBGTRANSFERENABLED], a + call Trade_AnimMonMoveVertical + jp ClearSprites + +Trade_AnimRightToLeft: +; Animates the mon moving from the right GB to the left one. + call Trade_InitGameboyTransferGfx + xor a + ld [wTradedMonMovingRight], a + ld a, $64 + ld [wBaseCoordX], a + ld a, $44 + ld [wBaseCoordY], a + ld a, [wRightGBMonSpecies] + ld [wMonPartySpriteSpecies], a + call Trade_WriteCircledMonOAM + call Trade_DrawRightGameboy + call Trade_CopyTileMapToVRAM + call Trade_DrawCableAcrossScreen + ld hl, vBGMap1 + $94 + call Trade_CopyCableTilesOffScreen + call Trade_AnimMonMoveVertical + ld b, $6 + call Trade_AnimMonMoveHorizontal + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + call Trade_DrawCableAcrossScreen + ld b, $4 + call Trade_AnimMonMoveHorizontal + call Trade_DrawLeftGameboy + ld b, $6 + call Trade_AnimMonMoveHorizontal + xor a + ld [H_AUTOBGTRANSFERENABLED], a + jp ClearSprites + +Trade_InitGameboyTransferGfx: +; Initialises the graphics for showing a mon moving between gameboys. + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + call ClearScreen + xor a + ld [H_AUTOBGTRANSFERENABLED], a + call Trade_LoadMonPartySpriteGfx + call DelayFrame + ld a, %10101011 + ld [rLCDC], a + xor a + ld [hSCX], a + ld a, $90 + ld [hWY], a + ret + +Trade_DrawLeftGameboy: + call Trade_ClearTileMap + +; draw link cable + coord hl, 11, 4 + ld a, $5d + ld [hli], a + ld a, $5e + ld c, 8 +.loop + ld [hli], a + dec c + jr nz, .loop + +; draw gameboy pic + coord hl, 5, 3 + ld b, $6 + call CopyTileIDsFromList_ZeroBaseTileID + +; draw text box with player name below gameboy pic + coord hl, 4, 12 + ld b, 2 + ld c, 7 + call TextBoxBorder + coord hl, 5, 14 + ld de, wPlayerName + call PlaceString + + jp DelayFrame + +Trade_DrawRightGameboy: + call Trade_ClearTileMap + +; draw horizontal segment of link cable + coord hl, 0, 4 + ld a, $5e + ld c, $e +.loop + ld [hli], a + dec c + jr nz, .loop + +; draw vertical segment of link cable + ld a, $5f + ld [hl], a + ld de, SCREEN_WIDTH + add hl, de + ld a, $61 + ld [hl], a + add hl, de + ld [hl], a + add hl, de + ld [hl], a + add hl, de + ld [hl], a + add hl, de + ld a, $60 + ld [hld], a + ld a, $5d + ld [hl], a + +; draw gameboy pic + coord hl, 7, 8 + ld b, $6 + call CopyTileIDsFromList_ZeroBaseTileID + +; draw text box with enemy name above link cable + coord hl, 6, 0 + ld b, 2 + ld c, 7 + call TextBoxBorder + coord hl, 7, 2 + ld de, wLinkEnemyTrainerName + call PlaceString + + jp DelayFrame + +Trade_DrawCableAcrossScreen: +; Draws the link cable across the screen. + call Trade_ClearTileMap + coord hl, 0, 4 + ld a, $5e + ld c, SCREEN_WIDTH +.loop + ld [hli], a + dec c + jr nz, .loop + ret + +Trade_CopyCableTilesOffScreen: +; This is used to copy the link cable tiles off screen so that the cable +; continues when the screen is scrolled. + push hl + coord hl, 0, 4 + call CopyToRedrawRowOrColumnSrcTiles + pop hl + ld a, h + ld [hRedrawRowOrColumnDest + 1], a + ld a, l + ld [hRedrawRowOrColumnDest], a + ld a, REDRAW_ROW + ld [hRedrawRowOrColumnMode], a + ld c, 10 + jp DelayFrames + +Trade_AnimMonMoveHorizontal: +; Animates the mon going through the link cable horizontally over a distance of +; b 16-pixel units. + ld a, [wTradedMonMovingRight] + ld e, a + ld d, $8 +.scrollLoop + ld a, e + dec a + jr z, .movingRight +; moving left + ld a, [hSCX] + sub $2 + jr .next +.movingRight + ld a, [hSCX] + add $2 +.next + ld [hSCX], a + call DelayFrame + dec d + jr nz, .scrollLoop + call Trade_AnimCircledMon + dec b + jr nz, Trade_AnimMonMoveHorizontal + ret + +Trade_AnimCircledMon: +; Cycles between the two animation frames of the mon party sprite, cycles +; between a circle and an oval around the mon sprite, and makes the cable flash. + push de + push bc + push hl + ld a, [rBGP] + xor $3c ; make link cable flash + ld [rBGP], a + ld hl, wOAMBuffer + $02 + ld de, $4 + ld c, $14 +.loop + ld a, [hl] + xor $40 + ld [hl], a + add hl, de + dec c + jr nz, .loop + pop hl + pop bc + pop de + ret + +Trade_WriteCircledMonOAM: + callba WriteMonPartySpriteOAMBySpecies + call Trade_WriteCircleOAM + +Trade_AddOffsetsToOAMCoords: + ld hl, wOAMBuffer + ld c, $14 +.loop + ld a, [wBaseCoordY] + add [hl] + ld [hli], a + ld a, [wBaseCoordX] + add [hl] + ld [hli], a + inc hl + inc hl + dec c + jr nz, .loop + ret + +Trade_AnimMonMoveVertical: +; Animates the mon going through the link cable vertically as well as +; horizontally for a bit. The last bit of horizontal movement (when moving +; right) or the first bit of horizontal movement (when moving left) are done +; here instead of Trade_AnimMonMoveHorizontal because this function moves the +; sprite itself rather than scrolling the screen around the sprite. Moving the +; sprite itself is necessary because the vertical segment of the link cable is +; to the right of the screen position that the mon sprite has when +; Trade_AnimMonMoveHorizontal is executing. + ld a, [wTradedMonMovingRight] + and a + jr z, .movingLeft +; moving right + lb bc, 4, 0 ; move right + call .doAnim + lb bc, 0, 10 ; move down + jr .doAnim +.movingLeft + lb bc, 0, -10 ; move up + call .doAnim + lb bc, -4, 0 ; move left +.doAnim + ld a, b + ld [wBaseCoordX], a + ld a, c + ld [wBaseCoordY], a + ld d, $4 +.loop + call Trade_AddOffsetsToOAMCoords + call Trade_AnimCircledMon + ld c, 8 + call DelayFrames + dec d + jr nz, .loop + ret + +Trade_WriteCircleOAM: +; Writes the OAM blocks for the circle around the traded mon as it passes +; the link cable. + ld hl, Trade_CircleOAMPointers + ld c, $4 + xor a +.loop + push bc + ld e, [hl] + inc hl + ld d, [hl] + inc hl + ld c, [hl] + inc hl + ld b, [hl] + inc hl + push hl + inc a + push af + call WriteOAMBlock + pop af + pop hl + pop bc + dec c + jr nz, .loop + ret + +Trade_CircleOAMPointers: + dw Trade_CircleOAM0 + db $08,$08 + dw Trade_CircleOAM1 + db $18,$08 + dw Trade_CircleOAM2 + db $08,$18 + dw Trade_CircleOAM3 + db $18,$18 + +Trade_CircleOAM0: + db $38,$10,$39,$10 + db $3A,$10,$3B,$10 + +Trade_CircleOAM1: + db $39,$30,$38,$30 + db $3B,$30,$3A,$30 + +Trade_CircleOAM2: + db $3A,$50,$3B,$50 + db $38,$50,$39,$50 + +Trade_CircleOAM3: + db $3B,$70,$3A,$70 + db $39,$70,$38,$70 + +; a = species +Trade_LoadMonSprite: + ld [wcf91], a + ld [wd0b5], a + ld [wWholeScreenPaletteMonSpecies], a + ld b, SET_PAL_POKEMON_WHOLE_SCREEN + ld c, 0 + call RunPaletteCommand + ld a, [H_AUTOBGTRANSFERENABLED] + xor $1 + ld [H_AUTOBGTRANSFERENABLED], a + call GetMonHeader + coord hl, 7, 2 + call LoadFlippedFrontSpriteByMonIndex + ld c, 10 + jp DelayFrames + +Trade_ShowClearedWindow: +; clears the window and covers the BG entirely with the window + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + call ClearScreen + ld a, %11100011 + ld [rLCDC], a + ld a, $7 + ld [rWX], a + xor a + ld [hWY], a + ld a, $90 + ld [hSCX], a + ret + +Trade_SlideTextBoxOffScreen: +; Slides the window right until it's off screen. The window usually just has +; a text box at the bottom when this is called. However, when this is called +; after Trade_ShowEnemyMon in the external clock sequence, there is a mon pic +; above the text box and it is also scrolled off the screen. + ld c, 50 + call DelayFrames +.loop + call DelayFrame + ld a, [rWX] + inc a + inc a + ld [rWX], a + cp $a1 + jr nz, .loop + call Trade_ClearTileMap + ld c, 10 + call DelayFrames + ld a, $7 + ld [rWX], a + ret + +PrintTradeWentToText: + ld hl, TradeWentToText + call PrintText + ld c, 200 + call DelayFrames + jp Trade_SlideTextBoxOffScreen + +TradeWentToText: + TX_FAR _TradeWentToText + db "@" + +PrintTradeForSendsText: + ld hl, TradeForText + call PrintText + call Trade_Delay80 + ld hl, TradeSendsText + call PrintText + jp Trade_Delay80 + +TradeForText: + TX_FAR _TradeForText + db "@" + +TradeSendsText: + TX_FAR _TradeSendsText + db "@" + +PrintTradeFarewellText: + ld hl, TradeWavesFarewellText + call PrintText + call Trade_Delay80 + ld hl, TradeTransferredText + call PrintText + call Trade_Delay80 + jp Trade_SlideTextBoxOffScreen + +TradeWavesFarewellText: + TX_FAR _TradeWavesFarewellText + db "@" + +TradeTransferredText: + TX_FAR _TradeTransferredText + db "@" + +PrintTradeTakeCareText: + ld hl, TradeTakeCareText + call PrintText + jp Trade_Delay80 + +TradeTakeCareText: + TX_FAR _TradeTakeCareText + db "@" + +PrintTradeWillTradeText: + ld hl, TradeWillTradeText + call PrintText + call Trade_Delay80 + ld hl, TradeforText + call PrintText + jp Trade_Delay80 + +TradeWillTradeText: + TX_FAR _TradeWillTradeText + db "@" + +TradeforText: + TX_FAR _TradeforText + db "@" + +Trade_ShowAnimation: + ld [wAnimationID], a + xor a + ld [wAnimationType], a + predef_jump MoveAnimation diff --git a/engine/movie/trade2.asm b/engine/movie/trade2.asm new file mode 100755 index 00000000..2c79e077 --- /dev/null +++ b/engine/movie/trade2.asm @@ -0,0 +1,48 @@ +Trade_PrintPlayerMonInfoText: + coord hl, 5, 0 + ld de, Trade_MonInfoText + call PlaceString + ld a, [wTradedPlayerMonSpecies] + ld [wd11e], a + predef IndexToPokedex + coord hl, 9, 0 + ld de, wd11e + lb bc, LEADING_ZEROES | 1, 3 + call PrintNumber + coord hl, 5, 2 + ld de, wcf4b + call PlaceString + coord hl, 8, 4 + ld de, wTradedPlayerMonOT + call PlaceString + coord hl, 8, 6 + ld de, wTradedPlayerMonOTID + lb bc, LEADING_ZEROES | 2, 5 + jp PrintNumber + +Trade_PrintEnemyMonInfoText: + coord hl, 5, 10 + ld de, Trade_MonInfoText + call PlaceString + ld a, [wTradedEnemyMonSpecies] + ld [wd11e], a + predef IndexToPokedex + coord hl, 9, 10 + ld de, wd11e + lb bc, LEADING_ZEROES | 1, 3 + call PrintNumber + coord hl, 5, 12 + ld de, wcd6d + call PlaceString + coord hl, 8, 14 + ld de, wTradedEnemyMonOT + call PlaceString + coord hl, 8, 16 + ld de, wTradedEnemyMonOTID + lb bc, LEADING_ZEROES | 2, 5 + jp PrintNumber + +Trade_MonInfoText: + db "──№⠄",$4E + next "OT/" + next $73,"№⠄","@" diff --git a/engine/multiply_divide.asm b/engine/multiply_divide.asm deleted file mode 100755 index 6cdc6c87..00000000 --- a/engine/multiply_divide.asm +++ /dev/null @@ -1,143 +0,0 @@ -_Multiply:: - ld a, $8 - ld b, a - xor a - ld [H_PRODUCT], a - ld [H_MULTIPLYBUFFER], a - ld [H_MULTIPLYBUFFER+1], a - ld [H_MULTIPLYBUFFER+2], a - ld [H_MULTIPLYBUFFER+3], a -.loop - ld a, [H_MULTIPLIER] - srl a - ld [H_MULTIPLIER], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN) - jr nc, .smallMultiplier - ld a, [H_MULTIPLYBUFFER+3] - ld c, a - ld a, [H_MULTIPLICAND+2] - add c - ld [H_MULTIPLYBUFFER+3], a - ld a, [H_MULTIPLYBUFFER+2] - ld c, a - ld a, [H_MULTIPLICAND+1] - adc c - ld [H_MULTIPLYBUFFER+2], a - ld a, [H_MULTIPLYBUFFER+1] - ld c, a - ld a, [H_MULTIPLICAND] ; (aliases: H_MULTIPLICAND) - adc c - ld [H_MULTIPLYBUFFER+1], a - ld a, [H_MULTIPLYBUFFER] - ld c, a - ld a, [H_PRODUCT] ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT) - adc c - ld [H_MULTIPLYBUFFER], a -.smallMultiplier - dec b - jr z, .done - ld a, [H_MULTIPLICAND+2] - sla a - ld [H_MULTIPLICAND+2], a - ld a, [H_MULTIPLICAND+1] - rl a - ld [H_MULTIPLICAND+1], a - ld a, [H_MULTIPLICAND] - rl a - ld [H_MULTIPLICAND], a - ld a, [H_PRODUCT] - rl a - ld [H_PRODUCT], a - jr .loop -.done - ld a, [H_MULTIPLYBUFFER+3] - ld [H_PRODUCT+3], a - ld a, [H_MULTIPLYBUFFER+2] - ld [H_PRODUCT+2], a - ld a, [H_MULTIPLYBUFFER+1] - ld [H_PRODUCT+1], a - ld a, [H_MULTIPLYBUFFER] - ld [H_PRODUCT], a - ret - -_Divide:: - xor a - ld [H_DIVIDEBUFFER], a - ld [H_DIVIDEBUFFER+1], a - ld [H_DIVIDEBUFFER+2], a - ld [H_DIVIDEBUFFER+3], a - ld [H_DIVIDEBUFFER+4], a - ld a, $9 - ld e, a -.asm_37db3 - ld a, [H_DIVIDEBUFFER] - ld c, a - ld a, [H_DIVIDEND+1] ; (aliases: H_MULTIPLICAND) - sub c - ld d, a - ld a, [H_DIVISOR] ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN) - ld c, a - ld a, [H_DIVIDEND] ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT) - sbc c - jr c, .asm_37dce - ld [H_DIVIDEND], a ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT) - ld a, d - ld [H_DIVIDEND+1], a ; (aliases: H_MULTIPLICAND) - ld a, [H_DIVIDEBUFFER+4] - inc a - ld [H_DIVIDEBUFFER+4], a - jr .asm_37db3 -.asm_37dce - ld a, b - cp $1 - jr z, .asm_37e18 - ld a, [H_DIVIDEBUFFER+4] - sla a - ld [H_DIVIDEBUFFER+4], a - ld a, [H_DIVIDEBUFFER+3] - rl a - ld [H_DIVIDEBUFFER+3], a - ld a, [H_DIVIDEBUFFER+2] - rl a - ld [H_DIVIDEBUFFER+2], a - ld a, [H_DIVIDEBUFFER+1] - rl a - ld [H_DIVIDEBUFFER+1], a - dec e - jr nz, .asm_37e04 - ld a, $8 - ld e, a - ld a, [H_DIVIDEBUFFER] - ld [H_DIVISOR], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN) - xor a - ld [H_DIVIDEBUFFER], a - ld a, [H_DIVIDEND+1] ; (aliases: H_MULTIPLICAND) - ld [H_DIVIDEND], a ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT) - ld a, [H_DIVIDEND+2] - ld [H_DIVIDEND+1], a ; (aliases: H_MULTIPLICAND) - ld a, [H_DIVIDEND+3] - ld [H_DIVIDEND+2], a -.asm_37e04 - ld a, e - cp $1 - jr nz, .asm_37e0a - dec b -.asm_37e0a - ld a, [H_DIVISOR] ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN) - srl a - ld [H_DIVISOR], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN) - ld a, [H_DIVIDEBUFFER] - rr a - ld [H_DIVIDEBUFFER], a - jr .asm_37db3 -.asm_37e18 - ld a, [H_DIVIDEND+1] ; (aliases: H_MULTIPLICAND) - ld [H_REMAINDER], a ; (aliases: H_DIVISOR, H_MULTIPLIER, H_POWEROFTEN) - ld a, [H_DIVIDEBUFFER+4] - ld [H_QUOTIENT+3], a - ld a, [H_DIVIDEBUFFER+3] - ld [H_QUOTIENT+2], a - ld a, [H_DIVIDEBUFFER+2] - ld [H_QUOTIENT+1], a ; (aliases: H_MULTIPLICAND) - ld a, [H_DIVIDEBUFFER+1] - ld [H_DIVIDEND], a ; (aliases: H_PRODUCT, H_PASTLEADINGZEROES, H_QUOTIENT) - ret diff --git a/engine/oak_speech.asm b/engine/oak_speech.asm deleted file mode 100755 index b1acfb65..00000000 --- a/engine/oak_speech.asm +++ /dev/null @@ -1,233 +0,0 @@ -SetDefaultNames: - ld a, [wLetterPrintingDelayFlags] - push af - ld a, [wOptions] - push af - ld a, [wd732] - push af - ld hl, wPlayerName - ld bc, wBoxDataEnd - wPlayerName - xor a - call FillMemory - ld hl, wSpriteStateData1 - ld bc, $200 - xor a - call FillMemory - pop af - ld [wd732], a - pop af - ld [wOptions], a - pop af - ld [wLetterPrintingDelayFlags], a - ld a, [wOptionsInitialized] - and a - call z, InitOptions - ld hl, NintenText - ld de, wPlayerName - ld bc, NAME_LENGTH - call CopyData - ld hl, SonyText - ld de, wRivalName - ld bc, NAME_LENGTH - jp CopyData - -OakSpeech: - ld a, $FF - call PlaySound ; stop music - ld a, BANK(Music_Routes2) - ld c, a - ld a, MUSIC_ROUTES2 - call PlayMusic - call ClearScreen - call LoadTextBoxTilePatterns - call SetDefaultNames - predef InitPlayerData2 - ld hl, wNumBoxItems - ld a, POTION - ld [wcf91], a - ld a, 1 - ld [wItemQuantity], a - call AddItemToInventory ; give one potion - ld a, [wDefaultMap] - ld [wDestinationMap], a - call SpecialWarpIn - xor a - ld [hTilesetType], a - ld a, [wd732] - bit 1, a ; possibly a debug mode bit - jp nz, .skipChoosingNames - ld de, ProfOakPic - lb bc, Bank(ProfOakPic), $00 - call IntroDisplayPicCenteredOrUpperRight - call FadeInIntroPic - ld hl, OakSpeechText1 - call PrintText - call GBFadeOutToWhite - call ClearScreen - ld a, NIDORINO - ld [wd0b5], a - ld [wcf91], a - call GetMonHeader - coord hl, 6, 4 - call LoadFlippedFrontSpriteByMonIndex - call MovePicLeft - ld hl, OakSpeechText2 - call PrintText - call GBFadeOutToWhite - call ClearScreen - ld de, RedPicFront - lb bc, Bank(RedPicFront), $00 - call IntroDisplayPicCenteredOrUpperRight - call MovePicLeft - ld hl, IntroducePlayerText - call PrintText - call ChoosePlayerName - call GBFadeOutToWhite - call ClearScreen - ld de, Rival1Pic - lb bc, Bank(Rival1Pic), $00 - call IntroDisplayPicCenteredOrUpperRight - call FadeInIntroPic - ld hl, IntroduceRivalText - call PrintText - call ChooseRivalName -.skipChoosingNames - call GBFadeOutToWhite - call ClearScreen - ld de, RedPicFront - lb bc, Bank(RedPicFront), $00 - call IntroDisplayPicCenteredOrUpperRight - call GBFadeInFromWhite - ld a, [wd72d] - and a - jr nz, .next - ld hl, OakSpeechText3 - call PrintText -.next - ld a, [H_LOADEDROMBANK] - push af - ld a, SFX_SHRINK - call PlaySound - pop af - ld [H_LOADEDROMBANK], a - ld [MBC1RomBank], a - ld c, 4 - call DelayFrames - ld de, RedSprite - ld hl, vSprites - lb bc, BANK(RedSprite), $0C - call CopyVideoData - ld de, ShrinkPic1 - lb bc, BANK(ShrinkPic1), $00 - call IntroDisplayPicCenteredOrUpperRight - ld c, 4 - call DelayFrames - ld de, ShrinkPic2 - lb bc, BANK(ShrinkPic2), $00 - call IntroDisplayPicCenteredOrUpperRight - call ResetPlayerSpriteData - ld a, [H_LOADEDROMBANK] - push af - ld a, BANK(Music_PalletTown) - ld [wAudioROMBank], a - ld [wAudioSavedROMBank], a - ld a, 10 - ld [wAudioFadeOutControl], a - ld a, $FF - ld [wNewSoundID], a - call PlaySound ; stop music - pop af - ld [H_LOADEDROMBANK], a - ld [MBC1RomBank], a - ld c, 20 - call DelayFrames - coord hl, 6, 5 - ld b, 7 - ld c, 7 - call ClearScreenArea - call LoadTextBoxTilePatterns - ld a, 1 - ld [wUpdateSpritesEnabled], a - ld c, 50 - call DelayFrames - call GBFadeOutToWhite - jp ClearScreen -OakSpeechText1: - TX_FAR _OakSpeechText1 - db "@" -OakSpeechText2: - TX_FAR _OakSpeechText2A - TX_CRY_NIDORINA - TX_FAR _OakSpeechText2B - db "@" -IntroducePlayerText: - TX_FAR _IntroducePlayerText - db "@" -IntroduceRivalText: - TX_FAR _IntroduceRivalText - db "@" -OakSpeechText3: - TX_FAR _OakSpeechText3 - db "@" - -FadeInIntroPic: - ld hl, IntroFadePalettes - ld b, 6 -.next - ld a, [hli] - ld [rBGP], a - ld c, 10 - call DelayFrames - dec b - jr nz, .next - ret - -IntroFadePalettes: - db %01010100 - db %10101000 - db %11111100 - db %11111000 - db %11110100 - db %11100100 - -MovePicLeft: - ld a, 119 - ld [rWX], a - call DelayFrame - - ld a, %11100100 - ld [rBGP], a -.next - call DelayFrame - ld a, [rWX] - sub 8 - cp $FF - ret z - ld [rWX], a - jr .next - -DisplayPicCenteredOrUpperRight: - call GetPredefRegisters -IntroDisplayPicCenteredOrUpperRight: -; b = bank -; de = address of compressed pic -; c: 0 = centred, non-zero = upper-right - push bc - ld a, b - call UncompressSpriteFromDE - ld hl, sSpriteBuffer1 - ld de, sSpriteBuffer0 - ld bc, $310 - call CopyData - ld de, vFrontPic - call InterlaceMergeSpriteBuffers - pop bc - ld a, c - and a - coord hl, 15, 1 - jr nz, .next - coord hl, 6, 4 -.next - xor a - ld [hStartTileID], a - predef_jump CopyUncompressedPicToTilemap diff --git a/engine/oak_speech2.asm b/engine/oak_speech2.asm deleted file mode 100755 index fdc9ffa3..00000000 --- a/engine/oak_speech2.asm +++ /dev/null @@ -1,219 +0,0 @@ -ChoosePlayerName: - call OakSpeechSlidePicRight - ld de, DefaultNamesPlayer - call DisplayIntroNameTextBox - ld a, [wCurrentMenuItem] - and a - jr z, .customName - ld hl, DefaultNamesPlayerList - call GetDefaultName - ld de, wPlayerName - call OakSpeechSlidePicLeft - jr .done -.customName - ld hl, wPlayerName - xor a ; NAME_PLAYER_SCREEN - ld [wNamingScreenType], a - call DisplayNamingScreen - ld a, [wcf4b] - cp "@" - jr z, .customName - call ClearScreen - call Delay3 - ld de, RedPicFront - ld b, BANK(RedPicFront) - call IntroDisplayPicCenteredOrUpperRight -.done - ld hl, YourNameIsText - jp PrintText - -YourNameIsText: - TX_FAR _YourNameIsText - db "@" - -ChooseRivalName: - call OakSpeechSlidePicRight - ld de, DefaultNamesRival - call DisplayIntroNameTextBox - ld a, [wCurrentMenuItem] - and a - jr z, .customName - ld hl, DefaultNamesRivalList - call GetDefaultName - ld de, wRivalName - call OakSpeechSlidePicLeft - jr .done -.customName - ld hl, wRivalName - ld a, NAME_RIVAL_SCREEN - ld [wNamingScreenType], a - call DisplayNamingScreen - ld a, [wcf4b] - cp "@" - jr z, .customName - call ClearScreen - call Delay3 - ld de, Rival1Pic - ld b, $13 - call IntroDisplayPicCenteredOrUpperRight -.done - ld hl, HisNameIsText - jp PrintText - -HisNameIsText: - TX_FAR _HisNameIsText - db "@" - -OakSpeechSlidePicLeft: - push de - coord hl, 0, 0 - lb bc, 12, 11 - call ClearScreenArea ; clear the name list text box - ld c, 10 - call DelayFrames - pop de - ld hl, wcd6d - ld bc, NAME_LENGTH - call CopyData - call Delay3 - coord hl, 12, 4 - lb de, 6, 6 * SCREEN_WIDTH + 5 - ld a, $ff - jr OakSpeechSlidePicCommon - -OakSpeechSlidePicRight: - coord hl, 5, 4 - lb de, 6, 6 * SCREEN_WIDTH + 5 - xor a - -OakSpeechSlidePicCommon: - push hl - push de - push bc - ld [hSlideDirection], a - ld a, d - ld [hSlideAmount], a - ld a, e - ld [hSlidingRegionSize], a - ld c, a - ld a, [hSlideDirection] - and a - jr nz, .next -; If sliding right, point hl to the end of the pic's tiles. - ld d, 0 - add hl, de -.next - ld d, h - ld e, l -.loop - xor a - ld [H_AUTOBGTRANSFERENABLED], a - ld a, [hSlideDirection] - and a - jr nz, .slideLeft -; sliding right - ld a, [hli] - ld [hld], a - dec hl - jr .next2 -.slideLeft - ld a, [hld] - ld [hli], a - inc hl -.next2 - dec c - jr nz, .loop - ld a, [hSlideDirection] - and a - jr z, .next3 -; 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 - ld [hl], a -.next3 - ld a, 1 - ld [H_AUTOBGTRANSFERENABLED], a - call Delay3 - ld a, [hSlidingRegionSize] - ld c, a - ld h, d - ld l, e - ld a, [hSlideDirection] - and a - jr nz, .slideLeft2 - inc hl - jr .next4 -.slideLeft2 - dec hl -.next4 - ld d, h - ld e, l - ld a, [hSlideAmount] - dec a - ld [hSlideAmount], a - jr nz, .loop - pop bc - pop de - pop hl - ret - -DisplayIntroNameTextBox: - push de - coord hl, 0, 0 - ld b, $a - ld c, $9 - call TextBoxBorder - coord hl, 3, 0 - ld de, .namestring - call PlaceString - pop de - coord hl, 2, 2 - call PlaceString - call UpdateSprites - xor a - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - inc a - ld [wTopMenuItemX], a - ld [wMenuWatchedKeys], a ; A_BUTTON - inc a - ld [wTopMenuItemY], a - inc a - ld [wMaxMenuItem], a - jp HandleMenuInput - -.namestring - db "NAME@" - -INCLUDE "text/player_names.asm" - -GetDefaultName: -; a = name index -; hl = name list - ld b, a - ld c, 0 -.loop - ld d, h - ld e, l -.innerLoop - ld a, [hli] - cp "@" - jr nz, .innerLoop - ld a, b - cp c - jr z, .foundName - inc c - jr .loop -.foundName - ld h, d - ld l, e - ld de, wcd6d - ld bc, $14 - jp CopyData - -INCLUDE "text/player_names_list.asm" - -TextTerminator_6b20: - db "@" diff --git a/engine/oam_dma.asm b/engine/oam_dma.asm deleted file mode 100644 index b0d64675..00000000 --- a/engine/oam_dma.asm +++ /dev/null @@ -1,26 +0,0 @@ -WriteDMACodeToHRAM:: -; Since no other memory is available during OAM DMA, -; DMARoutine is copied to HRAM and executed there. - ld c, $ff80 % $100 - ld b, DMARoutineEnd - DMARoutine - ld hl, DMARoutine -.copy - ld a, [hli] - ld [$ff00+c], a - inc c - dec b - jr nz, .copy - ret - -DMARoutine: - ; initiate DMA - ld a, wOAMBuffer / $100 - ld [rDMA], a - - ; wait for DMA to finish - ld a, $28 -.wait - dec a - jr nz, .wait - ret -DMARoutineEnd: diff --git a/engine/overworld/auto_movement.asm b/engine/overworld/auto_movement.asm new file mode 100755 index 00000000..e478c9ad --- /dev/null +++ b/engine/overworld/auto_movement.asm @@ -0,0 +1,292 @@ +PlayerStepOutFromDoor:: + ld hl, wd730 + res 1, [hl] + call IsPlayerStandingOnDoorTile + jr nc, .notStandingOnDoor + ld a, $fc + ld [wJoyIgnore], a + ld hl, wd736 + set 1, [hl] + ld a, $1 + ld [wSimulatedJoypadStatesIndex], a + ld a, D_DOWN + ld [wSimulatedJoypadStatesEnd], a + xor a + ld [wSpriteStateData1 + 2], a + call StartSimulatingJoypadStates + ret +.notStandingOnDoor + xor a + ld [wWastedByteCD3A], a + ld [wSimulatedJoypadStatesIndex], a + ld [wSimulatedJoypadStatesEnd], a + ld hl, wd736 + res 0, [hl] + res 1, [hl] + ld hl, wd730 + res 7, [hl] + ret + +_EndNPCMovementScript:: + ld hl, wd730 + res 7, [hl] + ld hl, wd72e + res 7, [hl] + ld hl, wd736 + res 0, [hl] + res 1, [hl] + xor a + ld [wNPCMovementScriptSpriteOffset], a + ld [wNPCMovementScriptPointerTableNum], a + ld [wNPCMovementScriptFunctionNum], a + ld [wWastedByteCD3A], a + ld [wSimulatedJoypadStatesIndex], a + ld [wSimulatedJoypadStatesEnd], a + ret + +PalletMovementScriptPointerTable:: + dw PalletMovementScript_OakMoveLeft + dw PalletMovementScript_PlayerMoveLeft + dw PalletMovementScript_WaitAndWalkToLab + dw PalletMovementScript_WalkToLab + dw PalletMovementScript_Done + +PalletMovementScript_OakMoveLeft: + ld a, [wXCoord] + sub $a + ld [wNumStepsToTake], a + jr z, .playerOnLeftTile +; The player is on the right tile of the northern path out of Pallet Town and +; Prof. Oak is below. +; Make Prof. Oak step to the left. + ld b, 0 + ld c, a + ld hl, wNPCMovementDirections2 + ld a, NPC_MOVEMENT_LEFT + call FillMemory + ld [hl], $ff + ld a, [wSpriteIndex] + ld [H_SPRITEINDEX], a + ld de, wNPCMovementDirections2 + call MoveSprite + ld a, $1 + ld [wNPCMovementScriptFunctionNum], a + jr .done +; The player is on the left tile of the northern path out of Pallet Town and +; Prof. Oak is below. +; Prof. Oak is already where he needs to be. +.playerOnLeftTile + ld a, $3 + ld [wNPCMovementScriptFunctionNum], a +.done + ld hl, wFlags_D733 + set 1, [hl] + ld a, $fc + ld [wJoyIgnore], a + ret + +PalletMovementScript_PlayerMoveLeft: + ld a, [wd730] + bit 0, a ; is an NPC being moved by a script? + ret nz ; return if Oak is still moving + ld a, [wNumStepsToTake] + ld [wSimulatedJoypadStatesIndex], a + ld [hNPCMovementDirections2Index], a + predef ConvertNPCMovementDirectionsToJoypadMasks + call StartSimulatingJoypadStates + ld a, $2 + ld [wNPCMovementScriptFunctionNum], a + ret + +PalletMovementScript_WaitAndWalkToLab: + ld a, [wSimulatedJoypadStatesIndex] + and a ; is the player done moving left yet? + ret nz + +PalletMovementScript_WalkToLab: + xor a + ld [wOverrideSimulatedJoypadStatesMask], a + ld a, [wSpriteIndex] + swap a + ld [wNPCMovementScriptSpriteOffset], a + xor a + ld [wSpriteStateData2 + $06], a + ld hl, wSimulatedJoypadStatesEnd + ld de, RLEList_PlayerWalkToLab + call DecodeRLEList + dec a + ld [wSimulatedJoypadStatesIndex], a + ld hl, wNPCMovementDirections2 + ld de, RLEList_ProfOakWalkToLab + call DecodeRLEList + ld hl, wd72e + res 7, [hl] + ld hl, wd730 + set 7, [hl] + ld a, $4 + ld [wNPCMovementScriptFunctionNum], a + ret + +RLEList_ProfOakWalkToLab: + db NPC_MOVEMENT_DOWN, $05 + db NPC_MOVEMENT_LEFT, $01 + db NPC_MOVEMENT_DOWN, $05 + db NPC_MOVEMENT_RIGHT, $03 + db NPC_MOVEMENT_UP, $01 + db $E0, $01 ; stand still + db $FF + +RLEList_PlayerWalkToLab: + db D_UP, $02 + db D_RIGHT, $03 + db D_DOWN, $05 + db D_LEFT, $01 + db D_DOWN, $06 + db $FF + +PalletMovementScript_Done: + ld a, [wSimulatedJoypadStatesIndex] + and a + ret nz + ld a, HS_PALLET_TOWN_OAK + ld [wMissableObjectIndex], a + predef HideObject + ld hl, wd730 + res 7, [hl] + ld hl, wd72e + res 7, [hl] + jp EndNPCMovementScript + +PewterMuseumGuyMovementScriptPointerTable:: + dw PewterMovementScript_WalkToMuseum + dw PewterMovementScript_Done + +PewterMovementScript_WalkToMuseum: + ld a, BANK(Music_MuseumGuy) + ld [wAudioROMBank], a + ld [wAudioSavedROMBank], a + ld a, MUSIC_MUSEUM_GUY + ld [wNewSoundID], a + call PlaySound + ld a, [wSpriteIndex] + swap a + ld [wNPCMovementScriptSpriteOffset], a + call StartSimulatingJoypadStates + ld hl, wSimulatedJoypadStatesEnd + ld de, RLEList_PewterMuseumPlayer + call DecodeRLEList + dec a + ld [wSimulatedJoypadStatesIndex], a + xor a + ld [wWhichPewterGuy], a + predef PewterGuys + ld hl, wNPCMovementDirections2 + ld de, RLEList_PewterMuseumGuy + call DecodeRLEList + ld hl, wd72e + res 7, [hl] + ld a, $1 + ld [wNPCMovementScriptFunctionNum], a + ret + +RLEList_PewterMuseumPlayer: + db 0, $01 + db D_UP, $03 + db D_LEFT, $0D + db D_UP, $06 + db $FF + +RLEList_PewterMuseumGuy: + db NPC_MOVEMENT_UP, $06 + db NPC_MOVEMENT_LEFT, $0D + db NPC_MOVEMENT_UP, $03 + db NPC_MOVEMENT_LEFT, $01 + db $FF + +PewterMovementScript_Done: + ld a, [wSimulatedJoypadStatesIndex] + and a + ret nz + ld hl, wd730 + res 7, [hl] + ld hl, wd72e + res 7, [hl] + jp EndNPCMovementScript + +PewterGymGuyMovementScriptPointerTable:: + dw PewterMovementScript_WalkToGym + dw PewterMovementScript_Done + +PewterMovementScript_WalkToGym: + ld a, BANK(Music_MuseumGuy) + ld [wAudioROMBank], a + ld [wAudioSavedROMBank], a + ld a, MUSIC_MUSEUM_GUY + ld [wNewSoundID], a + call PlaySound + ld a, [wSpriteIndex] + swap a + ld [wNPCMovementScriptSpriteOffset], a + xor a + ld [wSpriteStateData2 + $06], a + ld hl, wSimulatedJoypadStatesEnd + ld de, RLEList_PewterGymPlayer + call DecodeRLEList + dec a + ld [wSimulatedJoypadStatesIndex], a + ld a, 1 + ld [wWhichPewterGuy], a + predef PewterGuys + ld hl, wNPCMovementDirections2 + ld de, RLEList_PewterGymGuy + call DecodeRLEList + ld hl, wd72e + res 7, [hl] + ld hl, wd730 + set 7, [hl] + ld a, $1 + ld [wNPCMovementScriptFunctionNum], a + ret + +RLEList_PewterGymPlayer: + db 0, $01 + db D_RIGHT, $02 + db D_DOWN, $05 + db D_LEFT, $0B + db D_UP, $05 + db D_LEFT, $0F + db $FF + +RLEList_PewterGymGuy: + db NPC_MOVEMENT_DOWN, $02 + db NPC_MOVEMENT_LEFT, $0F + db NPC_MOVEMENT_UP, $05 + db NPC_MOVEMENT_LEFT, $0B + db NPC_MOVEMENT_DOWN, $05 + db NPC_MOVEMENT_RIGHT, $03 + db $FF + +FreezeEnemyTrainerSprite:: + ld a, [wCurMap] + cp POKEMON_TOWER_7F + ret z ; the Rockets on Pokemon Tower 7F leave after battling, so don't freeze them + ld hl, RivalIDs + ld a, [wEngagedTrainerClass] + ld b, a +.loop + ld a, [hli] + cp $ff + jr z, .notRival + cp b + ret z ; the rival leaves after battling, so don't freeze him + jr .loop +.notRival + ld a, [wSpriteIndex] + ld [H_SPRITEINDEX], a + jp SetSpriteMovementBytesToFF + +RivalIDs: + db OPP_SONY1 + db OPP_SONY2 + db OPP_SONY3 + db $ff diff --git a/engine/overworld/cable_club_npc.asm b/engine/overworld/cable_club_npc.asm deleted file mode 100755 index bb0f7680..00000000 --- a/engine/overworld/cable_club_npc.asm +++ /dev/null @@ -1,151 +0,0 @@ -CableClubNPC:: - ld hl, CableClubNPCWelcomeText - call PrintText - CheckEvent EVENT_GOT_POKEDEX - jp nz, .receivedPokedex -; if the player hasn't received the pokedex - ld c, 60 - call DelayFrames - ld hl, CableClubNPCMakingPreparationsText - call PrintText - jp .didNotConnect -.receivedPokedex - ld a, $1 - ld [wMenuJoypadPollCount], a - ld a, 90 - ld [wLinkTimeoutCounter], a -.establishConnectionLoop - ld a, [hSerialConnectionStatus] - cp USING_INTERNAL_CLOCK - jr z, .establishedConnection - cp USING_EXTERNAL_CLOCK - jr z, .establishedConnection - ld a, CONNECTION_NOT_ESTABLISHED - ld [hSerialConnectionStatus], a - ld a, ESTABLISH_CONNECTION_WITH_EXTERNAL_CLOCK - ld [rSB], a - xor a - ld [hSerialReceiveData], a - ld a, START_TRANSFER_EXTERNAL_CLOCK - ld [rSC], a - ld a, [wLinkTimeoutCounter] - dec a - ld [wLinkTimeoutCounter], a - jr z, .failedToEstablishConnection - ld a, ESTABLISH_CONNECTION_WITH_INTERNAL_CLOCK - ld [rSB], a - ld a, START_TRANSFER_INTERNAL_CLOCK - ld [rSC], a - call DelayFrame - jr .establishConnectionLoop -.establishedConnection - call Serial_SendZeroByte - call DelayFrame - call Serial_SendZeroByte - ld c, 50 - call DelayFrames - ld hl, CableClubNPCPleaseApplyHereHaveToSaveText - call PrintText - xor a - ld [wMenuJoypadPollCount], a - call YesNoChoice - ld a, $1 - ld [wMenuJoypadPollCount], a - ld a, [wCurrentMenuItem] - and a - jr nz, .choseNo - callab SaveSAVtoSRAM - call WaitForSoundToFinish - ld a, SFX_SAVE - call PlaySoundWaitForCurrent - ld hl, CableClubNPCPleaseWaitText - call PrintText - ld hl, wUnknownSerialCounter - ld a, $3 - ld [hli], a - xor a - ld [hl], a - ld [hSerialReceivedNewData], a - ld [wSerialExchangeNybbleSendData], a - call Serial_SyncAndExchangeNybble - ld hl, wUnknownSerialCounter - ld a, [hli] - inc a - jr nz, .connected - ld a, [hl] - inc a - jr nz, .connected - ld b, 10 -.syncLoop - call DelayFrame - call Serial_SendZeroByte - dec b - jr nz, .syncLoop - call CloseLinkConnection - ld hl, CableClubNPCLinkClosedBecauseOfInactivityText - call PrintText - jr .didNotConnect -.failedToEstablishConnection - ld hl, CableClubNPCAreaReservedFor2FriendsLinkedByCableText - call PrintText - jr .didNotConnect -.choseNo - call CloseLinkConnection - ld hl, CableClubNPCPleaseComeAgainText - call PrintText -.didNotConnect - xor a - ld hl, wUnknownSerialCounter - ld [hli], a - ld [hl], a - ld hl, wd72e - res 6, [hl] - xor a - ld [wMenuJoypadPollCount], a - ret -.connected - xor a - ld [hld], a - ld [hl], a - jpab LinkMenu - -CableClubNPCAreaReservedFor2FriendsLinkedByCableText: - TX_FAR _CableClubNPCAreaReservedFor2FriendsLinkedByCableText - db "@" - -CableClubNPCWelcomeText: - TX_FAR _CableClubNPCWelcomeText - db "@" - -CableClubNPCPleaseApplyHereHaveToSaveText: - TX_FAR _CableClubNPCPleaseApplyHereHaveToSaveText - db "@" - -CableClubNPCPleaseWaitText: - TX_FAR _CableClubNPCPleaseWaitText - TX_DELAY - db "@" - -CableClubNPCLinkClosedBecauseOfInactivityText: - TX_FAR _CableClubNPCLinkClosedBecauseOfInactivityText - db "@" - -CableClubNPCPleaseComeAgainText: - TX_FAR _CableClubNPCPleaseComeAgainText - db "@" - -CableClubNPCMakingPreparationsText: - TX_FAR _CableClubNPCMakingPreparationsText - db "@" - -CloseLinkConnection: - call Delay3 - ld a, CONNECTION_NOT_ESTABLISHED - ld [hSerialConnectionStatus], a - ld a, ESTABLISH_CONNECTION_WITH_EXTERNAL_CLOCK - ld [rSB], a - xor a - ld [hSerialReceiveData], a - ld a, START_TRANSFER_EXTERNAL_CLOCK - ld [rSC], a - ret diff --git a/engine/overworld/card_key.asm b/engine/overworld/card_key.asm deleted file mode 100755 index c77d5fcd..00000000 --- a/engine/overworld/card_key.asm +++ /dev/null @@ -1,112 +0,0 @@ -PrintCardKeyText: - ld hl, SilphCoMapList - ld a, [wCurMap] - ld b, a -.silphCoMapListLoop - ld a, [hli] - cp $ff - ret z - cp b - jr nz, .silphCoMapListLoop - predef GetTileAndCoordsInFrontOfPlayer - ld a, [wTileInFrontOfPlayer] - cp $18 - jr z, .cardKeyDoorInFrontOfPlayer - cp $24 - jr z, .cardKeyDoorInFrontOfPlayer - ld b, a - ld a, [wCurMap] - cp SILPH_CO_11F - ret nz - ld a, b - cp $5e - ret nz -.cardKeyDoorInFrontOfPlayer - ld b, CARD_KEY - call IsItemInBag - jr z, .noCardKey - call GetCoordsInFrontOfPlayer - push de - tx_pre_id CardKeySuccessText - ld [hSpriteIndexOrTextID], a - call PrintPredefTextID - pop de - srl d - ld a, d - ld b, a - ld [wCardKeyDoorY], a - srl e - ld a, e - ld c, a - ld [wCardKeyDoorX], a - ld a, [wCurMap] - cp SILPH_CO_11F - jr nz, .notSilphCo11F - ld a, $3 - jr .replaceCardKeyDoorTileBlock -.notSilphCo11F - ld a, $e -.replaceCardKeyDoorTileBlock - ld [wNewTileBlockID], a - predef ReplaceTileBlock - ld hl, wCurrentMapScriptFlags - set 5, [hl] - ld a, SFX_GO_INSIDE - jp PlaySound -.noCardKey - tx_pre_id CardKeyFailText - ld [hSpriteIndexOrTextID], a - jp PrintPredefTextID - -SilphCoMapList: - 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 $FF - -CardKeySuccessText:: - TX_FAR _CardKeySuccessText1 - TX_SFX_ITEM_1 - TX_FAR _CardKeySuccessText2 - db "@" - -CardKeyFailText:: - TX_FAR _CardKeyFailText - db "@" - -; d = Y -; e = X -GetCoordsInFrontOfPlayer: - ld a, [wYCoord] - ld d, a - ld a, [wXCoord] - ld e, a - ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction - and a - jr nz, .notFacingDown -; facing down - inc d - ret -.notFacingDown - cp SPRITE_FACING_UP - jr nz, .notFacingUp -; facing up - dec d - ret -.notFacingUp - cp SPRITE_FACING_LEFT - jr nz, .notFacingLeft -; facing left - dec e - ret -.notFacingLeft -; facing right - inc e - ret diff --git a/engine/overworld/cinnabar_lab.asm b/engine/overworld/cinnabar_lab.asm deleted file mode 100755 index e642840d..00000000 --- a/engine/overworld/cinnabar_lab.asm +++ /dev/null @@ -1,123 +0,0 @@ -GiveFossilToCinnabarLab:: - ld hl, wd730 - set 6, [hl] - xor a - ld [wCurrentMenuItem], a - ld a, A_BUTTON | B_BUTTON - ld [wMenuWatchedKeys], a - ld a, [wFilteredBagItemsCount] - dec a - ld [wMaxMenuItem], a - ld a, 2 - ld [wTopMenuItemY], a - ld a, 1 - ld [wTopMenuItemX], a - ld a, [wFilteredBagItemsCount] - dec a - ld bc, 2 - ld hl, 3 - call AddNTimes - dec l - ld b, l - ld c, $d - coord hl, 0, 0 - call TextBoxBorder - call UpdateSprites - call PrintFossilsInBag - ld hl, wd730 - res 6, [hl] - call HandleMenuInput - bit 1, a ; pressed B? - jr nz, .cancelledGivingFossil - ld hl, wFilteredBagItems - ld a, [wCurrentMenuItem] - ld d, 0 - ld e, a - add hl, de - ld a, [hl] - ld [$ffdb], a - cp DOME_FOSSIL - jr z, .choseDomeFossil - cp HELIX_FOSSIL - jr z, .choseHelixFossil - ld b, AERODACTYL - jr .fossilSelected -.choseHelixFossil - ld b, OMANYTE - jr .fossilSelected -.choseDomeFossil - ld b, KABUTO -.fossilSelected - ld [wFossilItem], a - ld a, b - ld [wFossilMon], a - call LoadFossilItemAndMonName - ld hl, LabFossil_610ae - call PrintText - call YesNoChoice - ld a, [wCurrentMenuItem] - and a - jr nz, .cancelledGivingFossil - ld hl, LabFossil_610b3 - call PrintText - ld a, [wFossilItem] - ld [hItemToRemoveID], a - callba RemoveItemByID - ld hl, LabFossil_610b8 - call PrintText - SetEvents EVENT_GAVE_FOSSIL_TO_LAB, EVENT_LAB_STILL_REVIVING_FOSSIL - ret -.cancelledGivingFossil - ld hl, LabFossil_610bd - call PrintText - ret - -LabFossil_610ae: - TX_FAR _Lab4Text_610ae - db "@" - -LabFossil_610b3: - TX_FAR _Lab4Text_610b3 - db "@" - -LabFossil_610b8: - TX_FAR _Lab4Text_610b8 - db "@" - -LabFossil_610bd: - TX_FAR _Lab4Text_610bd - db "@" - -PrintFossilsInBag: -; Prints each fossil in the player's bag on a separate line in the menu. - ld hl, wFilteredBagItems - xor a - ld [hItemCounter], a -.loop - ld a, [hli] - cp $ff - ret z - push hl - ld [wd11e], a - call GetItemName - coord hl, 2, 2 - ld a, [hItemCounter] - ld bc, SCREEN_WIDTH * 2 - call AddNTimes - ld de, wcd6d - call PlaceString - ld hl, hItemCounter - inc [hl] - pop hl - jr .loop - -; loads the names of the fossil item and the resulting mon -LoadFossilItemAndMonName:: - ld a, [wFossilMon] - ld [wd11e], a - call GetMonName - call CopyStringToCF4B - ld a, [wFossilItem] - ld [wd11e], a - call GetItemName - ret diff --git a/engine/overworld/dust_smoke.asm b/engine/overworld/dust_smoke.asm new file mode 100755 index 00000000..6c26b712 --- /dev/null +++ b/engine/overworld/dust_smoke.asm @@ -0,0 +1,93 @@ +AnimateBoulderDust: + ld a, $1 + ld [wWhichAnimationOffsets], a ; select the boulder dust offsets + ld a, [wUpdateSpritesEnabled] + push af + ld a, $ff + ld [wUpdateSpritesEnabled], a + ld a, %11100100 + ld [rOBP1], a + call LoadSmokeTileFourTimes + callba WriteCutOrBoulderDustAnimationOAMBlock + ld c, 8 ; number of steps in animation +.loop + push bc + call GetMoveBoulderDustFunctionPointer + ld bc, .returnAddress + push bc + ld c, 4 + jp hl +.returnAddress + ld a, [rOBP1] + xor %01100100 + ld [rOBP1], a + call Delay3 + pop bc + dec c + jr nz, .loop + pop af + ld [wUpdateSpritesEnabled], a + jp LoadPlayerSpriteGraphics + +GetMoveBoulderDustFunctionPointer: + ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction + ld hl, MoveBoulderDustFunctionPointerTable + ld c, a + ld b, $0 + add hl, bc + ld a, [hli] + ld [wCoordAdjustmentAmount], a + ld a, [hli] + ld e, a + ld a, [hli] + ld h, [hl] + ld l, a + push hl + ld hl, wOAMBuffer + $90 + ld d, $0 + add hl, de + ld e, l + ld d, h + pop hl + ret + +MoveBoulderDustFunctionPointerTable: +; facing down + db $FF,$00 + dw AdjustOAMBlockYPos + +; facing up + db $01,$00 + dw AdjustOAMBlockYPos + +; facing left + db $01,$01 + dw AdjustOAMBlockXPos + +; facing right + db $FF,$01 + dw AdjustOAMBlockXPos + +LoadSmokeTileFourTimes:: + ld hl, vChars1 + $7c0 + ld c, $4 +.loop + push bc + push hl + call LoadSmokeTile + pop hl + ld bc, $10 + add hl, bc + pop bc + dec c + jr nz, .loop + ret + +LoadSmokeTile: + ld de, SSAnneSmokePuffTile + lb bc, BANK(SSAnneSmokePuffTile), (SSAnneSmokePuffTileEnd - SSAnneSmokePuffTile) / $10 + jp CopyVideoData + +SSAnneSmokePuffTile: + INCBIN "gfx/overworld/smoke.2bpp" +SSAnneSmokePuffTileEnd: diff --git a/engine/overworld/hidden_items.asm b/engine/overworld/hidden_items.asm deleted file mode 100755 index e40b0ac7..00000000 --- a/engine/overworld/hidden_items.asm +++ /dev/null @@ -1,161 +0,0 @@ -HiddenItems: - ld hl, HiddenItemCoords - call FindHiddenItemOrCoinsIndex - ld [wHiddenItemOrCoinsIndex], a - ld hl, wObtainedHiddenItemsFlags - ld a, [wHiddenItemOrCoinsIndex] - ld c, a - ld b, FLAG_TEST - predef FlagActionPredef - ld a, c - and a - ret nz - call EnableAutoTextBoxDrawing - ld a, 1 - ld [wDoNotWaitForButtonPressAfterDisplayingText], a - ld a, [wHiddenObjectFunctionArgument] ; item ID - ld [wd11e], a - call GetItemName - tx_pre_jump FoundHiddenItemText - -INCLUDE "data/hidden_item_coords.asm" - -FoundHiddenItemText:: - TX_FAR _FoundHiddenItemText - TX_ASM - ld a, [wHiddenObjectFunctionArgument] ; item ID - ld b, a - ld c, 1 - call GiveItem - jr nc, .bagFull - ld hl, wObtainedHiddenItemsFlags - ld a, [wHiddenItemOrCoinsIndex] - ld c, a - ld b, FLAG_SET - predef FlagActionPredef - ld a, SFX_GET_ITEM_2 - call PlaySoundWaitForCurrent - call WaitForSoundToFinish - jp TextScriptEnd -.bagFull - call WaitForTextScrollButtonPress ; wait for button press - xor a - ld [wDoNotWaitForButtonPressAfterDisplayingText], a - ld hl, HiddenItemBagFullText - call PrintText - jp TextScriptEnd - -HiddenItemBagFullText:: - TX_FAR _HiddenItemBagFullText - db "@" - -HiddenCoins: - ld b, COIN_CASE - predef GetQuantityOfItemInBag - ld a, b - and a - ret z - ld hl, HiddenCoinCoords - call FindHiddenItemOrCoinsIndex - ld [wHiddenItemOrCoinsIndex], a - ld hl, wObtainedHiddenCoinsFlags - ld a, [wHiddenItemOrCoinsIndex] - ld c, a - ld b, FLAG_TEST - predef FlagActionPredef - ld a, c - and a - ret nz - xor a - ld [hUnusedCoinsByte], a - ld [hCoins], a - ld [hCoins + 1], a - ld a, [wHiddenObjectFunctionArgument] - sub COIN - cp 10 - jr z, .bcd10 - cp 20 - jr z, .bcd20 - cp 40 - jr z, .bcd20 ; should be bcd40 - jr .bcd100 -.bcd10 - ld a, $10 - ld [hCoins + 1], a - jr .bcdDone -.bcd20 - ld a, $20 - ld [hCoins + 1], a - jr .bcdDone -.bcd40 ; due to a typo, this is never used - ld a, $40 - ld [hCoins + 1], a - jr .bcdDone -.bcd100 - ld a, $1 - ld [hCoins], a -.bcdDone - ld de, wPlayerCoins + 1 - ld hl, hCoins + 1 - ld c, $2 - predef AddBCDPredef - ld hl, wObtainedHiddenCoinsFlags - ld a, [wHiddenItemOrCoinsIndex] - ld c, a - ld b, FLAG_SET - predef FlagActionPredef - call EnableAutoTextBoxDrawing - ld a, [wPlayerCoins] - cp $99 - jr nz, .roomInCoinCase - ld a, [wPlayerCoins + 1] - cp $99 - jr nz, .roomInCoinCase - tx_pre_id DroppedHiddenCoinsText - jr .done -.roomInCoinCase - tx_pre_id FoundHiddenCoinsText -.done - jp PrintPredefTextID - -INCLUDE "data/hidden_coins.asm" - -FoundHiddenCoinsText:: - TX_FAR _FoundHiddenCoinsText - TX_SFX_ITEM_2 - db "@" - -DroppedHiddenCoinsText:: - TX_FAR _FoundHiddenCoins2Text - TX_SFX_ITEM_2 - TX_FAR _DroppedHiddenCoinsText - db "@" - -FindHiddenItemOrCoinsIndex: - ld a, [wHiddenObjectY] - ld d, a - ld a, [wHiddenObjectX] - ld e, a - ld a, [wCurMap] - ld b, a - ld c, -1 -.loop - inc c - ld a, [hli] - cp $ff ; end of the list? - ret z ; if so, we're done here - cp b - jr nz, .next1 - ld a, [hli] - cp d - jr nz, .next2 - ld a, [hli] - cp e - jr nz, .loop - ld a, c - ret -.next1 - inc hl -.next2 - inc hl - jr .loop diff --git a/engine/overworld/item.asm b/engine/overworld/item.asm deleted file mode 100644 index 9f19100a..00000000 --- a/engine/overworld/item.asm +++ /dev/null @@ -1,54 +0,0 @@ -PickUpItem: - call EnableAutoTextBoxDrawing - - ld a, [hSpriteIndexOrTextID] - ld b, a - ld hl, wMissableObjectList -.missableObjectsListLoop - ld a, [hli] - cp $ff - ret z - cp b - jr z, .isMissable - inc hl - jr .missableObjectsListLoop - -.isMissable - ld a, [hl] - ld [$ffdb], a - - ld hl, wMapSpriteExtraData - ld a, [hSpriteIndexOrTextID] - dec a - add a - ld d, 0 - ld e, a - add hl, de - ld a, [hl] - ld b, a ; item - ld c, 1 ; quantity - call GiveItem - jr nc, .BagFull - - ld a, [$ffdb] - ld [wMissableObjectIndex], a - predef HideObject - ld a, 1 - ld [wDoNotWaitForButtonPressAfterDisplayingText], a - ld hl, FoundItemText - jr .print - -.BagFull - ld hl, NoMoreRoomForItemText -.print - call PrintText - ret - -FoundItemText: - TX_FAR _FoundItemText - TX_SFX_ITEM_1 - db "@" - -NoMoreRoomForItemText: - TX_FAR _NoMoreRoomForItemText - db "@" diff --git a/engine/overworld/map_sprite_functions1.asm b/engine/overworld/map_sprite_functions1.asm deleted file mode 100644 index 0e6b2d06..00000000 --- a/engine/overworld/map_sprite_functions1.asm +++ /dev/null @@ -1,356 +0,0 @@ -_UpdateSprites:: - ld h, $c1 - inc h - ld a, $e ; wSpriteStateData2 + $0e -.spriteLoop - ld l, a - sub $e - ld c, a - ld [H_CURRENTSPRITEOFFSET], a - ld a, [hl] - and a - jr z, .skipSprite ; tests $c2Xe - push hl - push de - push bc - call .updateCurrentSprite - pop bc - pop de - pop hl -.skipSprite - ld a, l - add $10 ; move to next sprite - cp $e ; test for overflow (back at $0e) - jr nz, .spriteLoop - ret -.updateCurrentSprite - cp $1 - jp nz, UpdateNonPlayerSprite - jp UpdatePlayerSprite - -UpdateNonPlayerSprite: - dec a - swap a - ld [$ff93], a ; $10 * sprite# - ld a, [wNPCMovementScriptSpriteOffset] ; some sprite offset? - ld b, a - ld a, [H_CURRENTSPRITEOFFSET] - cp b - jr nz, .unequal - jp DoScriptedNPCMovement -.unequal - jp UpdateNPCSprite - -; This detects if the current sprite (whose offset is at H_CURRENTSPRITEOFFSET) -; is going to collide with another sprite by looping over the other sprites. -; The current sprite's offset will be labelled with i (e.g. $c1i0). -; The loop sprite's offset will labelled with j (e.g. $c1j0). -; -; Note that the Y coordinate of the sprite (in [$c1k4]) is one of the following -; 9 values when the sprite is aligned with the grid: $fc, $0c, $1c, $2c, ..., $7c. -; 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 - - ld h, wSpriteStateData1 / $100 - ld a, [H_CURRENTSPRITEOFFSET] - add wSpriteStateData1 % $100 - ld l, a - - ld a, [hl] ; a = [$c1i0] (picture) (0 if slot is unused) - and a ; is this sprite slot slot used? - ret z ; return if not used - - ld a, l - add 3 - ld l, a - - ld a, [hli] ; a = [$c1i3] (delta Y) (-1, 0, or 1) - call SetSpriteCollisionValues - - ld a, [hli] ; a = [$C1i4] (Y screen coordinate) - add 4 ; align with multiple of $10 - -; The effect of the following 3 lines is to -; add 7 to a if moving south or -; subtract 7 from a if moving north. - add b - and $f0 - or c - - ld [$ff90], a ; store Y coordinate adjusted for direction of movement - - ld a, [hli] ; a = [$c1i5] (delta X) (-1, 0, or 1) - call SetSpriteCollisionValues - ld a, [hl] ; a = [$C1i6] (X screen coordinate) - -; The effect of the following 3 lines is to -; add 7 to a if moving east or -; subtract 7 from a if moving west. - add b - and $f0 - or c - - ld [$ff91], a ; store X coordinate adjusted for direction of movement - - ld a, l - add 7 - ld l, a - - xor a - ld [hld], a ; zero [$c1id] XXX what's [$c1id] for? - ld [hld], a ; zero [$c1ic] (directions in which collisions occurred) - - ld a, [$ff91] - ld [hld], a ; [$c1ib] = adjusted X coordinate - ld a, [$ff90] - ld [hl], a ; [$c1ia] = adjusted Y coordinate - - xor a ; zero the loop counter - -.loop - ld [$ff8f], a ; store loop counter - swap a - ld e, a - ld a, [H_CURRENTSPRITEOFFSET] - cp e ; does the loop sprite match the current sprite? - jp z, .next ; go to the next sprite if they match - - ld d, h - ld a, [de] ; a = [$c1j0] (picture) (0 if slot is unused) - and a ; is this sprite slot slot used? - jp z, .next ; go the next sprite if not used - - inc e - inc e - ld a, [de] ; a = [$c1j2] ($ff means the sprite is offscreen) - inc a - jp z, .next ; go the next sprite if offscreen - - ld a, [H_CURRENTSPRITEOFFSET] - add 10 - ld l, a - - inc e - ld a, [de] ; a = [$c1j3] (delta Y) - call SetSpriteCollisionValues - - inc e - ld a, [de] ; a = [$C1j4] (Y screen coordinate) - add 4 ; align with multiple of $10 - -; The effect of the following 3 lines is to -; add 7 to a if moving south or -; subtract 7 from a if moving north. - add b - and $f0 - or c - - sub [hl] ; subtract the adjusted Y coordinate of sprite i ([$c1ia]) from that of sprite j - -; calculate the absolute value of the difference to get the distance - jr nc, .noCarry1 - cpl - inc a -.noCarry1 - ld [$ff90], a ; store the distance between the two sprites' adjusted Y values - -; Use the carry flag set by the above subtraction to determine which sprite's -; Y coordinate is larger. This information is used later to set [$c1ic], -; which stores which direction the collision occurred in. -; The following 5 lines set the lowest 2 bits of c, which are later shifted left by 2. -; If sprite i's Y is larger, set lowest 2 bits of c to 10. -; If sprite j's Y is larger or both are equal, set lowest 2 bits of c to 01. - push af - rl c - pop af - ccf - rl c - -; If sprite i's delta Y is 0, then b = 7, else b = 9. - ld b, 7 - ld a, [hl] ; a = [$c1ia] (adjusted Y coordinate) - and $f - jr z, .next1 - ld b, 9 - -.next1 - ld a, [$ff90] ; a = distance between adjusted Y coordinates - sub b - ld [$ff92], a ; store distance adjusted using sprite i's direction - ld a, b - ld [$ff90], a ; store 7 or 9 depending on sprite i's delta Y - jr c, .checkXDistance - -; If sprite j's delta Y is 0, then b = 7, else b = 9. - ld b, 7 - dec e - ld a, [de] ; a = [$c1j3] (delta Y) - inc e - and a - jr z, .next2 - ld b, 9 - -.next2 - ld a, [$ff92] ; a = distance adjusted using sprite i's direction - sub b ; adjust distance using sprite j's direction - jr z, .checkXDistance - jr nc, .next ; go to next sprite if distance is still positive after both adjustments - -.checkXDistance - inc e - inc l - ld a, [de] ; a = [$c1j5] (delta X) - - push bc - - call SetSpriteCollisionValues - inc e - ld a, [de] ; a = [$c1j6] (X screen coordinate) - -; The effect of the following 3 lines is to -; add 7 to a if moving east or -; subtract 7 from a if moving west. - add b - and $f0 - or c - - pop bc - - sub [hl] ; subtract the adjusted X coordinate of sprite i ([$c1ib]) from that of sprite j - -; calculate the absolute value of the difference to get the distance - jr nc, .noCarry2 - cpl - inc a -.noCarry2 - ld [$ff91], a ; store the distance between the two sprites' adjusted X values - -; Use the carry flag set by the above subtraction to determine which sprite's -; X coordinate is larger. This information is used later to set [$c1ic], -; which stores which direction the collision occurred in. -; The following 5 lines set the lowest 2 bits of c. -; If sprite i's X is larger, set lowest 2 bits of c to 10. -; If sprite j's X is larger or both are equal, set lowest 2 bits of c to 01. - push af - rl c - pop af - ccf - rl c - -; If sprite i's delta X is 0, then b = 7, else b = 9. - ld b, 7 - ld a, [hl] ; a = [$c1ib] (adjusted X coordinate) - and $f - jr z, .next3 - ld b, 9 - -.next3 - ld a, [$ff91] ; a = distance between adjusted X coordinates - sub b - ld [$ff92], a ; store distance adjusted using sprite i's direction - ld a, b - ld [$ff91], a ; store 7 or 9 depending on sprite i's delta X - jr c, .collision - -; If sprite j's delta X is 0, then b = 7, else b = 9. - ld b, 7 - dec e - ld a, [de] ; a = [$c1j5] (delta X) - inc e - and a - jr z, .next4 - ld b, 9 - -.next4 - ld a, [$ff92] ; a = distance adjusted using sprite i's direction - sub b ; adjust distance using sprite j's direction - jr z, .collision - jr nc, .next ; go to next sprite if distance is still positive after both adjustments - -.collision - ld a, [$ff91] ; a = 7 or 9 depending on sprite i's delta X - ld b, a - ld a, [$ff90] ; a = 7 or 9 depending on sprite i's delta Y - inc l - -; If delta X isn't 0 and delta Y is 0, then b = %0011, else b = %1100. -; (note that normally if delta X isn't 0, then delta Y must be 0 and vice versa) - cp b - jr c, .next5 - ld b, %1100 - jr .next6 -.next5 - ld b, %0011 - -.next6 - ld a, c ; c has 2 bits set (one of bits 0-1 is set for the X axis and one of bits 2-3 for the Y axis) - and b ; we select either the bit in bits 0-1 or bits 2-3 based on the calculation immediately above - or [hl] ; or with existing collision direction bits in [$c1ic] - ld [hl], a ; store new value - ld a, c ; useless code because a is overwritten before being used again - -; set bit in [$c1ie] or [$c1if] to indicate which sprite the collision occurred with - inc l - inc l - ld a, [$ff8f] ; a = loop counter - ld de, SpriteCollisionBitTable - add a - add e - ld e, a - jr nc, .noCarry3 - inc d -.noCarry3 - ld a, [de] - or [hl] - ld [hli], a - inc de - ld a, [de] - or [hl] - ld [hl], a - -.next - ld a, [$ff8f] ; a = loop counter - inc a - cp $10 - jp nz, .loop - ret - -; takes delta X or delta Y in a -; b = delta X/Y -; c = 0 if delta X/Y is 0 -; c = 7 if delta X/Y is 1 -; c = 9 if delta X/Y is -1 -SetSpriteCollisionValues: - and a - ld b, 0 - ld c, 0 - jr z, .done - ld c, 9 - cp -1 - jr z, .ok - ld c, 7 - ld a, 0 -.ok - ld b, a -.done - ret - -SpriteCollisionBitTable: - db %00000000,%00000001 - db %00000000,%00000010 - db %00000000,%00000100 - db %00000000,%00001000 - db %00000000,%00010000 - db %00000000,%00100000 - db %00000000,%01000000 - db %00000000,%10000000 - db %00000001,%00000000 - db %00000010,%00000000 - db %00000100,%00000000 - db %00001000,%00000000 - db %00010000,%00000000 - db %00100000,%00000000 - db %01000000,%00000000 - db %10000000,%00000000 diff --git a/engine/overworld/npc_movement.asm b/engine/overworld/npc_movement.asm deleted file mode 100755 index e478c9ad..00000000 --- a/engine/overworld/npc_movement.asm +++ /dev/null @@ -1,292 +0,0 @@ -PlayerStepOutFromDoor:: - ld hl, wd730 - res 1, [hl] - call IsPlayerStandingOnDoorTile - jr nc, .notStandingOnDoor - ld a, $fc - ld [wJoyIgnore], a - ld hl, wd736 - set 1, [hl] - ld a, $1 - ld [wSimulatedJoypadStatesIndex], a - ld a, D_DOWN - ld [wSimulatedJoypadStatesEnd], a - xor a - ld [wSpriteStateData1 + 2], a - call StartSimulatingJoypadStates - ret -.notStandingOnDoor - xor a - ld [wWastedByteCD3A], a - ld [wSimulatedJoypadStatesIndex], a - ld [wSimulatedJoypadStatesEnd], a - ld hl, wd736 - res 0, [hl] - res 1, [hl] - ld hl, wd730 - res 7, [hl] - ret - -_EndNPCMovementScript:: - ld hl, wd730 - res 7, [hl] - ld hl, wd72e - res 7, [hl] - ld hl, wd736 - res 0, [hl] - res 1, [hl] - xor a - ld [wNPCMovementScriptSpriteOffset], a - ld [wNPCMovementScriptPointerTableNum], a - ld [wNPCMovementScriptFunctionNum], a - ld [wWastedByteCD3A], a - ld [wSimulatedJoypadStatesIndex], a - ld [wSimulatedJoypadStatesEnd], a - ret - -PalletMovementScriptPointerTable:: - dw PalletMovementScript_OakMoveLeft - dw PalletMovementScript_PlayerMoveLeft - dw PalletMovementScript_WaitAndWalkToLab - dw PalletMovementScript_WalkToLab - dw PalletMovementScript_Done - -PalletMovementScript_OakMoveLeft: - ld a, [wXCoord] - sub $a - ld [wNumStepsToTake], a - jr z, .playerOnLeftTile -; The player is on the right tile of the northern path out of Pallet Town and -; Prof. Oak is below. -; Make Prof. Oak step to the left. - ld b, 0 - ld c, a - ld hl, wNPCMovementDirections2 - ld a, NPC_MOVEMENT_LEFT - call FillMemory - ld [hl], $ff - ld a, [wSpriteIndex] - ld [H_SPRITEINDEX], a - ld de, wNPCMovementDirections2 - call MoveSprite - ld a, $1 - ld [wNPCMovementScriptFunctionNum], a - jr .done -; The player is on the left tile of the northern path out of Pallet Town and -; Prof. Oak is below. -; Prof. Oak is already where he needs to be. -.playerOnLeftTile - ld a, $3 - ld [wNPCMovementScriptFunctionNum], a -.done - ld hl, wFlags_D733 - set 1, [hl] - ld a, $fc - ld [wJoyIgnore], a - ret - -PalletMovementScript_PlayerMoveLeft: - ld a, [wd730] - bit 0, a ; is an NPC being moved by a script? - ret nz ; return if Oak is still moving - ld a, [wNumStepsToTake] - ld [wSimulatedJoypadStatesIndex], a - ld [hNPCMovementDirections2Index], a - predef ConvertNPCMovementDirectionsToJoypadMasks - call StartSimulatingJoypadStates - ld a, $2 - ld [wNPCMovementScriptFunctionNum], a - ret - -PalletMovementScript_WaitAndWalkToLab: - ld a, [wSimulatedJoypadStatesIndex] - and a ; is the player done moving left yet? - ret nz - -PalletMovementScript_WalkToLab: - xor a - ld [wOverrideSimulatedJoypadStatesMask], a - ld a, [wSpriteIndex] - swap a - ld [wNPCMovementScriptSpriteOffset], a - xor a - ld [wSpriteStateData2 + $06], a - ld hl, wSimulatedJoypadStatesEnd - ld de, RLEList_PlayerWalkToLab - call DecodeRLEList - dec a - ld [wSimulatedJoypadStatesIndex], a - ld hl, wNPCMovementDirections2 - ld de, RLEList_ProfOakWalkToLab - call DecodeRLEList - ld hl, wd72e - res 7, [hl] - ld hl, wd730 - set 7, [hl] - ld a, $4 - ld [wNPCMovementScriptFunctionNum], a - ret - -RLEList_ProfOakWalkToLab: - db NPC_MOVEMENT_DOWN, $05 - db NPC_MOVEMENT_LEFT, $01 - db NPC_MOVEMENT_DOWN, $05 - db NPC_MOVEMENT_RIGHT, $03 - db NPC_MOVEMENT_UP, $01 - db $E0, $01 ; stand still - db $FF - -RLEList_PlayerWalkToLab: - db D_UP, $02 - db D_RIGHT, $03 - db D_DOWN, $05 - db D_LEFT, $01 - db D_DOWN, $06 - db $FF - -PalletMovementScript_Done: - ld a, [wSimulatedJoypadStatesIndex] - and a - ret nz - ld a, HS_PALLET_TOWN_OAK - ld [wMissableObjectIndex], a - predef HideObject - ld hl, wd730 - res 7, [hl] - ld hl, wd72e - res 7, [hl] - jp EndNPCMovementScript - -PewterMuseumGuyMovementScriptPointerTable:: - dw PewterMovementScript_WalkToMuseum - dw PewterMovementScript_Done - -PewterMovementScript_WalkToMuseum: - ld a, BANK(Music_MuseumGuy) - ld [wAudioROMBank], a - ld [wAudioSavedROMBank], a - ld a, MUSIC_MUSEUM_GUY - ld [wNewSoundID], a - call PlaySound - ld a, [wSpriteIndex] - swap a - ld [wNPCMovementScriptSpriteOffset], a - call StartSimulatingJoypadStates - ld hl, wSimulatedJoypadStatesEnd - ld de, RLEList_PewterMuseumPlayer - call DecodeRLEList - dec a - ld [wSimulatedJoypadStatesIndex], a - xor a - ld [wWhichPewterGuy], a - predef PewterGuys - ld hl, wNPCMovementDirections2 - ld de, RLEList_PewterMuseumGuy - call DecodeRLEList - ld hl, wd72e - res 7, [hl] - ld a, $1 - ld [wNPCMovementScriptFunctionNum], a - ret - -RLEList_PewterMuseumPlayer: - db 0, $01 - db D_UP, $03 - db D_LEFT, $0D - db D_UP, $06 - db $FF - -RLEList_PewterMuseumGuy: - db NPC_MOVEMENT_UP, $06 - db NPC_MOVEMENT_LEFT, $0D - db NPC_MOVEMENT_UP, $03 - db NPC_MOVEMENT_LEFT, $01 - db $FF - -PewterMovementScript_Done: - ld a, [wSimulatedJoypadStatesIndex] - and a - ret nz - ld hl, wd730 - res 7, [hl] - ld hl, wd72e - res 7, [hl] - jp EndNPCMovementScript - -PewterGymGuyMovementScriptPointerTable:: - dw PewterMovementScript_WalkToGym - dw PewterMovementScript_Done - -PewterMovementScript_WalkToGym: - ld a, BANK(Music_MuseumGuy) - ld [wAudioROMBank], a - ld [wAudioSavedROMBank], a - ld a, MUSIC_MUSEUM_GUY - ld [wNewSoundID], a - call PlaySound - ld a, [wSpriteIndex] - swap a - ld [wNPCMovementScriptSpriteOffset], a - xor a - ld [wSpriteStateData2 + $06], a - ld hl, wSimulatedJoypadStatesEnd - ld de, RLEList_PewterGymPlayer - call DecodeRLEList - dec a - ld [wSimulatedJoypadStatesIndex], a - ld a, 1 - ld [wWhichPewterGuy], a - predef PewterGuys - ld hl, wNPCMovementDirections2 - ld de, RLEList_PewterGymGuy - call DecodeRLEList - ld hl, wd72e - res 7, [hl] - ld hl, wd730 - set 7, [hl] - ld a, $1 - ld [wNPCMovementScriptFunctionNum], a - ret - -RLEList_PewterGymPlayer: - db 0, $01 - db D_RIGHT, $02 - db D_DOWN, $05 - db D_LEFT, $0B - db D_UP, $05 - db D_LEFT, $0F - db $FF - -RLEList_PewterGymGuy: - db NPC_MOVEMENT_DOWN, $02 - db NPC_MOVEMENT_LEFT, $0F - db NPC_MOVEMENT_UP, $05 - db NPC_MOVEMENT_LEFT, $0B - db NPC_MOVEMENT_DOWN, $05 - db NPC_MOVEMENT_RIGHT, $03 - db $FF - -FreezeEnemyTrainerSprite:: - ld a, [wCurMap] - cp POKEMON_TOWER_7F - ret z ; the Rockets on Pokemon Tower 7F leave after battling, so don't freeze them - ld hl, RivalIDs - ld a, [wEngagedTrainerClass] - ld b, a -.loop - ld a, [hli] - cp $ff - jr z, .notRival - cp b - ret z ; the rival leaves after battling, so don't freeze him - jr .loop -.notRival - ld a, [wSpriteIndex] - ld [H_SPRITEINDEX], a - jp SetSpriteMovementBytesToFF - -RivalIDs: - db OPP_SONY1 - db OPP_SONY2 - db OPP_SONY3 - db $ff diff --git a/engine/overworld/oaks_aide.asm b/engine/overworld/oaks_aide.asm deleted file mode 100755 index f5068fda..00000000 --- a/engine/overworld/oaks_aide.asm +++ /dev/null @@ -1,71 +0,0 @@ -OaksAideScript: - ld hl, OaksAideHiText - call PrintText - call YesNoChoice - ld a, [wCurrentMenuItem] - and a - jr nz, .choseNo - ld hl, wPokedexOwned - ld b, wPokedexOwnedEnd - wPokedexOwned - call CountSetBits - ld a, [wNumSetBits] - ld [hOaksAideNumMonsOwned], a - ld b, a - ld a, [hOaksAideRequirement] - cp b - jr z, .giveItem - jr nc, .notEnoughOwnedMons -.giveItem - ld hl, OaksAideHereYouGoText - call PrintText - ld a, [hOaksAideRewardItem] - ld b, a - ld c, 1 - call GiveItem - jr nc, .bagFull - ld hl, OaksAideGotItemText - call PrintText - ld a, $1 - jr .done -.bagFull - ld hl, OaksAideNoRoomText - call PrintText - xor a - jr .done -.notEnoughOwnedMons - ld hl, OaksAideUhOhText - call PrintText - ld a, $80 - jr .done -.choseNo - ld hl, OaksAideComeBackText - call PrintText - ld a, $ff -.done - ld [hOaksAideResult], a - ret - -OaksAideHiText: - TX_FAR _OaksAideHiText - db "@" - -OaksAideUhOhText: - TX_FAR _OaksAideUhOhText - db "@" - -OaksAideComeBackText: - TX_FAR _OaksAideComeBackText - db "@" - -OaksAideHereYouGoText: - TX_FAR _OaksAideHereYouGoText - db "@" - -OaksAideGotItemText: - TX_FAR _OaksAideGotItemText - TX_SFX_ITEM_1 - db "@" - -OaksAideNoRoomText: - TX_FAR _OaksAideNoRoomText - db "@" diff --git a/engine/overworld/oam.asm b/engine/overworld/oam.asm deleted file mode 100644 index 68128413..00000000 --- a/engine/overworld/oam.asm +++ /dev/null @@ -1,189 +0,0 @@ -PrepareOAMData:: -; Determine OAM data for currently visible -; sprites and write it to wOAMBuffer. - - ld a, [wUpdateSpritesEnabled] - dec a - jr z, .updateEnabled - - cp -1 - ret nz - ld [wUpdateSpritesEnabled], a - jp HideSprites - -.updateEnabled - xor a - ld [hOAMBufferOffset], a - -.spriteLoop - ld [hSpriteOffset2], a - - ld d, wSpriteStateData1 / $100 - ld a, [hSpriteOffset2] - ld e, a - ld a, [de] ; c1x0 - and a - jp z, .nextSprite - - inc e - inc e - ld a, [de] ; c1x2 (facing/anim) - ld [wd5cd], a - cp $ff ; off-screen (don't draw) - jr nz, .visible - - call GetSpriteScreenXY - jr .nextSprite - -.visible - cp $a0 ; is the sprite unchanging like an item ball or boulder? - jr c, .usefacing - -; unchanging - and $f - add $10 ; skip to the second half of the table which doesn't account for facing direction - jr .next - -.usefacing - and $f - -.next - ld l, a - -; get sprite priority - push de - inc d - ld a, e - add $5 - ld e, a - ld a, [de] ; c2x7 - and $80 - ld [hSpritePriority], a ; temp store sprite priority - pop de - -; read the entry from the table - ld h, 0 - ld bc, SpriteFacingAndAnimationTable - add hl, hl - add hl, hl - add hl, bc - ld a, [hli] - ld c, a - ld a, [hli] - ld b, a - ld a, [hli] - ld h, [hl] - ld l, a - - call GetSpriteScreenXY - - ld a, [hOAMBufferOffset] - ld e, a - ld d, wOAMBuffer / $100 - -.tileLoop - ld a, [hSpriteScreenY] ; temp for sprite Y position - add $10 ; Y=16 is top of screen (Y=0 is invisible) - add [hl] ; add Y offset from table - ld [de], a ; write new sprite OAM Y position - inc hl - ld a, [hSpriteScreenX] ; temp for sprite X position - add $8 ; X=8 is left of screen (X=0 is invisible) - add [hl] ; add X offset from table - inc e - ld [de], a ; write new sprite OAM X position - inc e - ld a, [bc] ; read pattern number offset (accommodates orientation (offset 0,4 or 8) and animation (offset 0 or $80)) - inc bc - push bc - ld b, a - - ld a, [wd5cd] ; temp copy of c1x2 - swap a ; high nybble determines sprite used (0 is always player sprite, next are some npcs) - and $f - - ; Sprites $a and $b have one face (and therefore 4 tiles instead of 12). - ; As a result, sprite $b's tile offset is less than normal. - cp $b - jr nz, .notFourTileSprite - ld a, $a * 12 + 4 - jr .next2 - -.notFourTileSprite - ; a *= 12 - sla a - sla a - ld c, a - sla a - add c - -.next2 - add b ; add the tile offset from the table (based on frame and facing direction) - pop bc - ld [de], a ; tile id - inc hl - inc e - ld a, [hl] - bit 1, a ; is the tile allowed to set the sprite priority bit? - jr z, .skipPriority - ld a, [hSpritePriority] - or [hl] -.skipPriority - inc hl - ld [de], a - inc e - bit 0, a ; OAMFLAG_ENDOFDATA - jr z, .tileLoop - - ld a, e - ld [hOAMBufferOffset], a - -.nextSprite - ld a, [hSpriteOffset2] - add $10 - cp $100 % $100 - jp nz, .spriteLoop - - ; Clear unused OAM. - ld a, [hOAMBufferOffset] - ld l, a - ld h, wOAMBuffer / $100 - ld de, $4 - ld b, $a0 - ld a, [wd736] - bit 6, a ; jumping down ledge or fishing animation? - ld a, $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 - -.clear - cp l - ret z - ld [hl], b - add hl, de - jr .clear - -GetSpriteScreenXY: - inc e - inc e - ld a, [de] ; c1x4 - ld [hSpriteScreenY], a - inc e - inc e - ld a, [de] ; c1x6 - ld [hSpriteScreenX], a - ld a, 4 - add e - ld e, a - ld a, [hSpriteScreenY] - add 4 - and $f0 - ld [de], a ; c1xa (y) - inc e - ld a, [hSpriteScreenX] - and $f0 - ld [de], a ; c1xb (x) - ret diff --git a/engine/overworld/pathfinding.asm b/engine/overworld/pathfinding.asm new file mode 100644 index 00000000..ba052d38 --- /dev/null +++ b/engine/overworld/pathfinding.asm @@ -0,0 +1,201 @@ +FindPathToPlayer: + xor a + ld hl, hFindPathNumSteps + ld [hli], a ; hFindPathNumSteps + ld [hli], a ; hFindPathFlags + ld [hli], a ; hFindPathYProgress + ld [hl], a ; hFindPathXProgress + ld hl, wNPCMovementDirections2 + ld de, $0 +.loop + ld a, [hFindPathYProgress] + ld b, a + ld a, [hNPCPlayerYDistance] ; Y distance in steps + call CalcDifference + ld d, a + and a + jr nz, .asm_f8da + ld a, [hFindPathFlags] + set 0, a ; current end of path matches the player's Y coordinate + ld [hFindPathFlags], a +.asm_f8da + ld a, [hFindPathXProgress] + ld b, a + ld a, [hNPCPlayerXDistance] ; X distance in steps + call CalcDifference + ld e, a + and a + jr nz, .asm_f8ec + ld a, [hFindPathFlags] + set 1, a ; current end of path matches the player's X coordinate + ld [hFindPathFlags], a +.asm_f8ec + ld a, [hFindPathFlags] + cp $3 ; has the end of the path reached the player's position? + jr z, .done +; Compare whether the X distance between the player and the current of the path +; is greater or if the Y distance is. Then, try to reduce whichever is greater. + ld a, e + cp d + jr c, .yDistanceGreater +; x distance is greater + ld a, [hNPCPlayerRelativePosFlags] + bit 1, a + jr nz, .playerIsLeftOfNPC + ld d, NPC_MOVEMENT_RIGHT + jr .next1 +.playerIsLeftOfNPC + ld d, NPC_MOVEMENT_LEFT +.next1 + ld a, [hFindPathXProgress] + add 1 + ld [hFindPathXProgress], a + jr .storeDirection +.yDistanceGreater + ld a, [hNPCPlayerRelativePosFlags] + bit 0, a + jr nz, .playerIsAboveNPC + ld d, NPC_MOVEMENT_DOWN + jr .next2 +.playerIsAboveNPC + ld d, NPC_MOVEMENT_UP +.next2 + ld a, [hFindPathYProgress] + add 1 + ld [hFindPathYProgress], a +.storeDirection + ld a, d + ld [hli], a + ld a, [hFindPathNumSteps] + inc a + ld [hFindPathNumSteps], a + jp .loop +.done + ld [hl], $ff + ret + +CalcPositionOfPlayerRelativeToNPC: + xor a + ld [hNPCPlayerRelativePosFlags], a + ld a, [wSpriteStateData1 + 4] ; player's sprite screen Y position in pixels + ld d, a + ld a, [wSpriteStateData1 + 6] ; player's sprite screen X position in pixels + ld e, a + ld hl, wSpriteStateData1 + ld a, [hNPCSpriteOffset] + add l + add $4 + ld l, a + jr nc, .noCarry + inc h +.noCarry + ld a, d + ld b, a + ld a, [hli] ; NPC sprite screen Y position in pixels + call CalcDifference + jr nc, .NPCSouthOfOrAlignedWithPlayer +.NPCNorthOfPlayer + push hl + ld hl, hNPCPlayerRelativePosFlags + bit 0, [hl] + set 0, [hl] + pop hl + jr .divideYDistance +.NPCSouthOfOrAlignedWithPlayer + push hl + ld hl, hNPCPlayerRelativePosFlags + bit 0, [hl] + res 0, [hl] + pop hl +.divideYDistance + push hl + ld hl, hDividend2 + ld [hli], a + ld a, 16 + ld [hli], a + call DivideBytes ; divide Y absolute distance by 16 + ld a, [hl] ; quotient + ld [hNPCPlayerYDistance], a + pop hl + inc hl + ld b, e + ld a, [hl] ; NPC sprite screen X position in pixels + call CalcDifference + jr nc, .NPCEastOfOrAlignedWithPlayer +.NPCWestOfPlayer + push hl + ld hl, hNPCPlayerRelativePosFlags + bit 1, [hl] + set 1, [hl] + pop hl + jr .divideXDistance +.NPCEastOfOrAlignedWithPlayer + push hl + ld hl, hNPCPlayerRelativePosFlags + bit 1, [hl] + res 1, [hl] + pop hl +.divideXDistance + ld [hDividend2], a + ld a, 16 + ld [hDivisor2], a + call DivideBytes ; divide X absolute distance by 16 + ld a, [hQuotient2] + ld [hNPCPlayerXDistance], a + ld a, [hNPCPlayerRelativePosPerspective] + and a + ret z + ld a, [hNPCPlayerRelativePosFlags] + cpl + and $3 + ld [hNPCPlayerRelativePosFlags], a + ret + +ConvertNPCMovementDirectionsToJoypadMasks: + ld a, [hNPCMovementDirections2Index] + ld [wNPCMovementDirections2Index], a + dec a + ld de, wSimulatedJoypadStatesEnd + ld hl, wNPCMovementDirections2 + add l + ld l, a + jr nc, .loop + inc h +.loop + ld a, [hld] + call ConvertNPCMovementDirectionToJoypadMask + ld [de], a + inc de + ld a, [hNPCMovementDirections2Index] + dec a + ld [hNPCMovementDirections2Index], a + jr nz, .loop + ret + +ConvertNPCMovementDirectionToJoypadMask: + push hl + ld b, a + ld hl, NPCMovementDirectionsToJoypadMasksTable +.loop + ld a, [hli] + cp $ff + jr z, .done + cp b + jr z, .loadJoypadMask + inc hl + jr .loop +.loadJoypadMask + ld a, [hl] +.done + pop hl + ret + +NPCMovementDirectionsToJoypadMasksTable: + db NPC_MOVEMENT_UP, D_UP + db NPC_MOVEMENT_DOWN, D_DOWN + db NPC_MOVEMENT_LEFT, D_LEFT + db NPC_MOVEMENT_RIGHT, D_RIGHT + db $ff + +; unreferenced + ret diff --git a/engine/overworld/pewter_guys.asm b/engine/overworld/pewter_guys.asm deleted file mode 100755 index 532fa4bf..00000000 --- a/engine/overworld/pewter_guys.asm +++ /dev/null @@ -1,102 +0,0 @@ -PewterGuys: - ld hl, wSimulatedJoypadStatesEnd - ld a, [wSimulatedJoypadStatesIndex] - dec a ; this decrement causes it to overwrite the last byte before $FF in the list - ld [wSimulatedJoypadStatesIndex], a - ld d, 0 - ld e, a - add hl, de - ld d, h - ld e, l - ld hl, PointerTable_37ce6 - ld a, [wWhichPewterGuy] - add a - ld b, 0 - ld c, a - add hl, bc - ld a, [hli] - ld h, [hl] - ld l, a - ld a, [wYCoord] - ld b, a - ld a, [wXCoord] - ld c, a -.findMatchingCoordsLoop - ld a, [hli] - cp b - jr nz, .nextEntry1 - ld a, [hli] - cp c - jr nz, .nextEntry2 - ld a, [hli] - ld h, [hl] - ld l, a -.copyMovementDataLoop - ld a, [hli] - cp $ff - ret z - ld [de], a - inc de - ld a, [wSimulatedJoypadStatesIndex] - inc a - ld [wSimulatedJoypadStatesIndex], a - jr .copyMovementDataLoop -.nextEntry1 - inc hl -.nextEntry2 - inc hl - inc hl - jr .findMatchingCoordsLoop - -PointerTable_37ce6: - dw PewterMuseumGuyCoords - dw PewterGymGuyCoords - -; these are the four coordinates of the spaces below, above, to the left and -; to the right of the museum guy, and pointers to different movements for -; the player to make to get positioned before the main movement. -PewterMuseumGuyCoords: - db 18, 27 - dw .down - db 16, 27 - dw .up - db 17, 26 - dw .left - db 17, 28 - dw .right - -.down - db D_UP, D_UP, $ff -.up - db D_RIGHT, D_LEFT, $ff -.left - db D_UP, D_RIGHT, $ff -.right - db D_UP, D_LEFT, $ff - -; these are the five coordinates which trigger the gym guy and pointers to -; different movements for the player to make to get positioned before the -; main movement -; $00 is a pause -PewterGymGuyCoords: - db 16, 34 - dw .one - db 17, 35 - dw .two - db 18, 37 - dw .three - db 19, 37 - dw .four - db 17, 36 - dw .five - -.one - db D_LEFT, D_DOWN, D_DOWN, D_RIGHT, $ff -.two - db D_LEFT, D_DOWN, D_RIGHT, D_LEFT, $ff -.three - db D_LEFT, D_LEFT, D_LEFT, $00, $00, $00, $00, $00, $00, $00, $00, $ff -.four - db D_LEFT, D_LEFT, D_UP, D_LEFT, $ff -.five - db D_LEFT, D_DOWN, D_LEFT, $00, $00, $00, $00, $00, $00, $00, $00, $ff diff --git a/engine/overworld/poison.asm b/engine/overworld/poison.asm deleted file mode 100644 index 5d8eb9fd..00000000 --- a/engine/overworld/poison.asm +++ /dev/null @@ -1,112 +0,0 @@ -ApplyOutOfBattlePoisonDamage: - ld a, [wd730] - add a - jp c, .noBlackOut ; no black out if joypad states are being simulated - ld a, [wPartyCount] - and a - jp z, .noBlackOut - call IncrementDayCareMonExp - ld a, [wStepCounter] - and $3 ; is the counter a multiple of 4? - jp nz, .noBlackOut ; only apply poison damage every fourth step - ld [wWhichPokemon], a - ld hl, wPartyMon1Status - ld de, wPartySpecies -.applyDamageLoop - ld a, [hl] - and (1 << PSN) - jr z, .nextMon2 ; not poisoned - dec hl - dec hl - ld a, [hld] - ld b, a - ld a, [hli] - or b - jr z, .nextMon ; already fainted -; subtract 1 from HP - ld a, [hl] - dec a - ld [hld], a - inc a - jr nz, .noBorrow -; borrow 1 from upper byte of HP - dec [hl] - inc hl - jr .nextMon -.noBorrow - ld a, [hli] - or [hl] - jr nz, .nextMon ; didn't faint from damage -; the mon fainted from the damage - push hl - inc hl - inc hl - ld [hl], a - ld a, [de] - ld [wd11e], a - push de - ld a, [wWhichPokemon] - ld hl, wPartyMonNicks - call GetPartyMonName - xor a - ld [wJoyIgnore], a - call EnableAutoTextBoxDrawing - ld a, TEXT_MON_FAINTED - ld [hSpriteIndexOrTextID], a - call DisplayTextID - pop de - pop hl -.nextMon - inc hl - inc hl -.nextMon2 - inc de - ld a, [de] - inc a - jr z, .applyDamageLoopDone - ld bc, wPartyMon2 - wPartyMon1 - add hl, bc - push hl - ld hl, wWhichPokemon - inc [hl] - pop hl - jr .applyDamageLoop -.applyDamageLoopDone - ld hl, wPartyMon1Status - ld a, [wPartyCount] - ld d, a - ld e, 0 -.countPoisonedLoop - ld a, [hl] - and (1 << PSN) - or e - ld e, a - ld bc, wPartyMon2 - wPartyMon1 - add hl, bc - dec d - jr nz, .countPoisonedLoop - ld a, e - and a ; are any party members poisoned? - jr z, .skipPoisonEffectAndSound - ld b, $2 - predef ChangeBGPalColor0_4Frames ; change BG white to dark grey for 4 frames - ld a, SFX_POISONED - call PlaySound -.skipPoisonEffectAndSound - predef AnyPartyAlive - ld a, d - and a - jr nz, .noBlackOut - call EnableAutoTextBoxDrawing - ld a, TEXT_BLACKED_OUT - ld [hSpriteIndexOrTextID], a - call DisplayTextID - ld hl, wd72e - set 5, [hl] - ld a, $ff - jr .done -.noBlackOut - xor a -.done - ld [wOutOfBattleBlackout], a - ret diff --git a/engine/overworld/pokecenter.asm b/engine/overworld/pokecenter.asm deleted file mode 100755 index f340e06d..00000000 --- a/engine/overworld/pokecenter.asm +++ /dev/null @@ -1,68 +0,0 @@ -DisplayPokemonCenterDialogue_:: - call SaveScreenTilesToBuffer1 ; save screen - ld hl, PokemonCenterWelcomeText - call PrintText - ld hl, wd72e - bit 2, [hl] - set 1, [hl] - set 2, [hl] - jr nz, .skipShallWeHealYourPokemon - ld hl, ShallWeHealYourPokemonText - call PrintText -.skipShallWeHealYourPokemon - call YesNoChoicePokeCenter ; yes/no menu - ld a, [wCurrentMenuItem] - and a - jr nz, .declinedHealing ; if the player chose No - call SetLastBlackoutMap - call LoadScreenTilesFromBuffer1 ; restore screen - ld hl, NeedYourPokemonText - call PrintText - ld a, $18 - ld [wSpriteStateData1 + $12], a ; make the nurse turn to face the machine - call Delay3 - predef HealParty - callba AnimateHealingMachine ; do the healing machine animation - xor a - ld [wAudioFadeOutControl], a - ld a, [wAudioSavedROMBank] - ld [wAudioROMBank], a - ld a, [wMapMusicSoundID] - ld [wLastMusicSoundID], a - ld [wNewSoundID], a - call PlaySound - ld hl, PokemonFightingFitText - call PrintText - ld a, $14 - ld [wSpriteStateData1 + $12], a ; make the nurse bow - ld c, a - call DelayFrames - jr .done -.declinedHealing - call LoadScreenTilesFromBuffer1 ; restore screen -.done - ld hl, PokemonCenterFarewellText - call PrintText - jp UpdateSprites - -PokemonCenterWelcomeText: - TX_FAR _PokemonCenterWelcomeText - db "@" - -ShallWeHealYourPokemonText: - TX_DELAY - TX_FAR _ShallWeHealYourPokemonText - db "@" - -NeedYourPokemonText: - TX_FAR _NeedYourPokemonText - db "@" - -PokemonFightingFitText: - TX_FAR _PokemonFightingFitText - db "@" - -PokemonCenterFarewellText: - TX_DELAY - TX_FAR _PokemonCenterFarewellText - db "@" diff --git a/engine/overworld/pokemart.asm b/engine/overworld/pokemart.asm deleted file mode 100755 index 177e8a09..00000000 --- a/engine/overworld/pokemart.asm +++ /dev/null @@ -1,272 +0,0 @@ -DisplayPokemartDialogue_:: - ld a, [wListScrollOffset] - ld [wSavedListScrollOffset], a - call UpdateSprites - xor a - ld [wBoughtOrSoldItemInMart], a -.loop - xor a - ld [wListScrollOffset], a - ld [wCurrentMenuItem], a - ld [wPlayerMonNumber], a - inc a - ld [wPrintItemPrices], a - ld a, MONEY_BOX - ld [wTextBoxID], a - call DisplayTextBoxID - ld a, BUY_SELL_QUIT_MENU - ld [wTextBoxID], a - call DisplayTextBoxID - -; This code is useless. It copies the address of the pokemart's inventory to hl, -; but the address is never used. - ld hl, wItemListPointer - ld a, [hli] - ld l, [hl] - ld h, a - - ld a, [wMenuExitMethod] - cp CANCELLED_MENU - jp z, .done - ld a, [wChosenMenuItem] - and a ; buying? - jp z, .buyMenu - dec a ; selling? - jp z, .sellMenu - dec a ; quitting? - jp z, .done -.sellMenu - -; the same variables are set again below, so this code has no effect - xor a - ld [wPrintItemPrices], a - ld a, INIT_BAG_ITEM_LIST - ld [wInitListType], a - callab InitList - - ld a, [wNumBagItems] - and a - jp z, .bagEmpty - ld hl, PokemonSellingGreetingText - call PrintText - call SaveScreenTilesToBuffer1 ; save screen -.sellMenuLoop - call LoadScreenTilesFromBuffer1 ; restore saved screen - ld a, MONEY_BOX - ld [wTextBoxID], a - call DisplayTextBoxID ; draw money text box - ld hl, wNumBagItems - ld a, l - ld [wListPointer], a - ld a, h - ld [wListPointer + 1], a - xor a - ld [wPrintItemPrices], a - ld [wCurrentMenuItem], a - ld a, ITEMLISTMENU - ld [wListMenuID], a - call DisplayListMenuID - jp c, .returnToMainPokemartMenu ; if the player closed the menu -.confirmItemSale ; if the player is trying to sell a specific item - call IsKeyItem - ld a, [wIsKeyItem] - and a - jr nz, .unsellableItem - ld a, [wcf91] - call IsItemHM - jr c, .unsellableItem - ld a, PRICEDITEMLISTMENU - ld [wListMenuID], a - ld [hHalveItemPrices], a ; halve prices when selling - call DisplayChooseQuantityMenu - inc a - jr z, .sellMenuLoop ; if the player closed the choose quantity menu with the B button - ld hl, PokemartTellSellPriceText - lb bc, 14, 1 ; location that PrintText always prints to, this is useless - call PrintText - coord hl, 14, 7 - lb bc, 8, 15 - ld a, TWO_OPTION_MENU - ld [wTextBoxID], a - call DisplayTextBoxID ; yes/no menu - ld a, [wMenuExitMethod] - cp CHOSE_SECOND_ITEM - jr z, .sellMenuLoop ; if the player chose No or pressed the B button - -; The following code is supposed to check if the player chose No, but the above -; check already catches it. - ld a, [wChosenMenuItem] - dec a - jr z, .sellMenuLoop - -.sellItem - ld a, [wBoughtOrSoldItemInMart] - and a - jr nz, .skipSettingFlag1 - inc a - ld [wBoughtOrSoldItemInMart], a -.skipSettingFlag1 - call AddAmountSoldToMoney - ld hl, wNumBagItems - call RemoveItemFromInventory - jp .sellMenuLoop -.unsellableItem - ld hl, PokemartUnsellableItemText - call PrintText - jp .returnToMainPokemartMenu -.bagEmpty - ld hl, PokemartItemBagEmptyText - call PrintText - call SaveScreenTilesToBuffer1 - jp .returnToMainPokemartMenu -.buyMenu - -; the same variables are set again below, so this code has no effect - ld a, 1 - ld [wPrintItemPrices], a - ld a, INIT_OTHER_ITEM_LIST - ld [wInitListType], a - callab InitList - - ld hl, PokemartBuyingGreetingText - call PrintText - call SaveScreenTilesToBuffer1 -.buyMenuLoop - call LoadScreenTilesFromBuffer1 - ld a, MONEY_BOX - ld [wTextBoxID], a - call DisplayTextBoxID - ld hl, wItemList - ld a, l - ld [wListPointer], a - ld a, h - ld [wListPointer + 1], a - xor a - ld [wCurrentMenuItem], a - inc a - ld [wPrintItemPrices], a - inc a ; a = 2 (PRICEDITEMLISTMENU) - ld [wListMenuID], a - call DisplayListMenuID - jr c, .returnToMainPokemartMenu ; if the player closed the menu - ld a, 99 - ld [wMaxItemQuantity], a - xor a - ld [hHalveItemPrices], a ; don't halve item prices when buying - call DisplayChooseQuantityMenu - inc a - jr z, .buyMenuLoop ; if the player closed the choose quantity menu with the B button - ld a, [wcf91] ; item ID - ld [wd11e], a ; store item ID for GetItemName - call GetItemName - call CopyStringToCF4B ; copy name to wcf4b - ld hl, PokemartTellBuyPriceText - call PrintText - coord hl, 14, 7 - lb bc, 8, 15 - ld a, TWO_OPTION_MENU - ld [wTextBoxID], a - call DisplayTextBoxID ; yes/no menu - ld a, [wMenuExitMethod] - cp CHOSE_SECOND_ITEM - jp z, .buyMenuLoop ; if the player chose No or pressed the B button - -; The following code is supposed to check if the player chose No, but the above -; check already catches it. - ld a, [wChosenMenuItem] - dec a - jr z, .buyMenuLoop - -.buyItem - call .isThereEnoughMoney - jr c, .notEnoughMoney - ld hl, wNumBagItems - call AddItemToInventory - jr nc, .bagFull - call SubtractAmountPaidFromMoney - ld a, [wBoughtOrSoldItemInMart] - and a - jr nz, .skipSettingFlag2 - ld a, 1 - ld [wBoughtOrSoldItemInMart], a -.skipSettingFlag2 - ld a, SFX_PURCHASE - call PlaySoundWaitForCurrent - call WaitForSoundToFinish - ld hl, PokemartBoughtItemText - call PrintText - jp .buyMenuLoop -.returnToMainPokemartMenu - call LoadScreenTilesFromBuffer1 - ld a, MONEY_BOX - ld [wTextBoxID], a - call DisplayTextBoxID - ld hl, PokemartAnythingElseText - call PrintText - jp .loop -.isThereEnoughMoney - ld de, wPlayerMoney - ld hl, hMoney - ld c, 3 ; length of money in bytes - jp StringCmp -.notEnoughMoney - ld hl, PokemartNotEnoughMoneyText - call PrintText - jr .returnToMainPokemartMenu -.bagFull - ld hl, PokemartItemBagFullText - call PrintText - jr .returnToMainPokemartMenu -.done - ld hl, PokemartThankYouText - call PrintText - ld a, 1 - ld [wUpdateSpritesEnabled], a - call UpdateSprites - ld a, [wSavedListScrollOffset] - ld [wListScrollOffset], a - ret - -PokemartBuyingGreetingText: - TX_FAR _PokemartBuyingGreetingText - db "@" - -PokemartTellBuyPriceText: - TX_FAR _PokemartTellBuyPriceText - db "@" - -PokemartBoughtItemText: - TX_FAR _PokemartBoughtItemText - db "@" - -PokemartNotEnoughMoneyText: - TX_FAR _PokemartNotEnoughMoneyText - db "@" - -PokemartItemBagFullText: - TX_FAR _PokemartItemBagFullText - db "@" - -PokemonSellingGreetingText: - TX_FAR _PokemonSellingGreetingText - db "@" - -PokemartTellSellPriceText: - TX_FAR _PokemartTellSellPriceText - db "@" - -PokemartItemBagEmptyText: - TX_FAR _PokemartItemBagEmptyText - db "@" - -PokemartUnsellableItemText: - TX_FAR _PokemartUnsellableItemText - db "@" - -PokemartThankYouText: - TX_FAR _PokemartThankYouText - db "@" - -PokemartAnythingElseText: - TX_FAR _PokemartAnythingElseText - db "@" diff --git a/engine/overworld/saffron_guards.asm b/engine/overworld/saffron_guards.asm deleted file mode 100755 index 091cfa1a..00000000 --- a/engine/overworld/saffron_guards.asm +++ /dev/null @@ -1,15 +0,0 @@ -RemoveGuardDrink:: - ld hl, GuardDrinksList -.drinkLoop - ld a, [hli] - ld [$ffdb], a - and a - ret z - push hl - ld b, a - call IsItemInBag - pop hl - jr z, .drinkLoop - jpba RemoveItemByID - -INCLUDE "data/guard_drink_items.asm" diff --git a/engine/overworld/set_blackout_map.asm b/engine/overworld/set_blackout_map.asm deleted file mode 100644 index 14f0ba28..00000000 --- a/engine/overworld/set_blackout_map.asm +++ /dev/null @@ -1,25 +0,0 @@ -SetLastBlackoutMap: -; Set the map to return to when -; blacking out or using Teleport or Dig. -; Safari rest houses don't count. - - push hl - ld hl, SafariZoneRestHouses - ld a, [wCurMap] - ld b, a -.loop - ld a, [hli] - cp -1 - jr z, .notresthouse - cp b - jr nz, .loop - jr .done - -.notresthouse - ld a, [wLastMap] - ld [wLastBlackoutMap], a -.done - pop hl - ret - -INCLUDE "data/rest_house_maps.asm" diff --git a/engine/overworld/special_warps.asm b/engine/overworld/special_warps.asm new file mode 100644 index 00000000..eee85402 --- /dev/null +++ b/engine/overworld/special_warps.asm @@ -0,0 +1,149 @@ +SpecialWarpIn:: + call LoadSpecialWarpData + predef LoadTilesetHeader + ld hl, wd732 + bit 2, [hl] ; dungeon warp or fly warp? + res 2, [hl] + jr z, .next +; if dungeon warp or fly warp + ld a, [wDestinationMap] + jr .next2 +.next + bit 1, [hl] + jr z, .next3 + call EmptyFunc +.next3 + ld a, 0 +.next2 + ld b, a + ld a, [wd72d] + and a + jr nz, .next4 + ld a, b +.next4 + ld hl, wd732 + bit 4, [hl] ; dungeon warp? + ret nz +; if not dungeon warp + ld [wLastMap], a + ret + +; gets the map ID, tile block map view pointer, tileset, and coordinates +LoadSpecialWarpData: + ld a, [wd72d] + cp TRADE_CENTER + jr nz, .notTradeCenter + ld hl, TradeCenterSpec1 + ld a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK ; which gameboy is clocking determines who is on the left and who is on the right + jr z, .copyWarpData + ld hl, TradeCenterSpec2 + jr .copyWarpData +.notTradeCenter + cp COLOSSEUM + jr nz, .notColosseum + ld hl, ColosseumSpec1 + ld a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + jr z, .copyWarpData + ld hl, ColosseumSpec2 + jr .copyWarpData +.notColosseum + ld a, [wd732] + bit 1, a + jr nz, .notFirstMap + bit 2, a + jr nz, .notFirstMap + ld hl, FirstMapSpec +.copyWarpData + ld de, wCurMap + ld c, $7 +.copyWarpDataLoop + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .copyWarpDataLoop + ld a, [hli] + ld [wCurMapTileset], a + xor a + jr .done +.notFirstMap + ld a, [wLastMap] ; this value is overwritten before it's ever read + ld hl, wd732 + bit 4, [hl] ; used dungeon warp (jumped down hole/waterfall)? + jr nz, .usedDunegonWarp + bit 6, [hl] ; return to last pokemon center (or player's house)? + res 6, [hl] + jr z, .otherDestination +; return to last pokemon center or player's house + ld a, [wLastBlackoutMap] + jr .usedFlyWarp +.usedDunegonWarp + ld hl, wd72d + res 4, [hl] + ld a, [wDungeonWarpDestinationMap] + ld b, a + ld [wCurMap], a + ld a, [wWhichDungeonWarp] + ld c, a + ld hl, DungeonWarpList + ld de, 0 + ld a, 6 + ld [wDungeonWarpDataEntrySize], a +.dungeonWarpListLoop + ld a, [hli] + cp b + jr z, .matchedDungeonWarpDestinationMap + inc hl + jr .nextDungeonWarp +.matchedDungeonWarpDestinationMap + ld a, [hli] + cp c + jr z, .matchedDungeonWarpID +.nextDungeonWarp + ld a, [wDungeonWarpDataEntrySize] + add e + ld e, a + jr .dungeonWarpListLoop +.matchedDungeonWarpID + ld hl, DungeonWarpData + add hl, de + jr .copyWarpData2 +.otherDestination + ld a, [wDestinationMap] +.usedFlyWarp + ld b, a + ld [wCurMap], a + ld hl, FlyWarpDataPtr +.flyWarpDataPtrLoop + ld a, [hli] + inc hl + cp b + jr z, .foundFlyWarpMatch + inc hl + inc hl + jr .flyWarpDataPtrLoop +.foundFlyWarpMatch + ld a, [hli] + ld h, [hl] + ld l, a +.copyWarpData2 + ld de, wCurrentTileBlockMapViewPointer + ld c, $6 +.copyWarpDataLoop2 + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .copyWarpDataLoop2 + xor a ; OVERWORLD + ld [wCurMapTileset], a +.done + ld [wYOffsetSinceLastSpecialWarp], a + ld [wXOffsetSinceLastSpecialWarp], a + ld a, $ff ; the player's coordinates have already been updated using a special warp, so don't use any of the normal warps + ld [wDestinationWarpID], a + ret + +INCLUDE "data/special_warps.asm" diff --git a/engine/overworld/sprite_collisions.asm b/engine/overworld/sprite_collisions.asm new file mode 100644 index 00000000..0e6b2d06 --- /dev/null +++ b/engine/overworld/sprite_collisions.asm @@ -0,0 +1,356 @@ +_UpdateSprites:: + ld h, $c1 + inc h + ld a, $e ; wSpriteStateData2 + $0e +.spriteLoop + ld l, a + sub $e + ld c, a + ld [H_CURRENTSPRITEOFFSET], a + ld a, [hl] + and a + jr z, .skipSprite ; tests $c2Xe + push hl + push de + push bc + call .updateCurrentSprite + pop bc + pop de + pop hl +.skipSprite + ld a, l + add $10 ; move to next sprite + cp $e ; test for overflow (back at $0e) + jr nz, .spriteLoop + ret +.updateCurrentSprite + cp $1 + jp nz, UpdateNonPlayerSprite + jp UpdatePlayerSprite + +UpdateNonPlayerSprite: + dec a + swap a + ld [$ff93], a ; $10 * sprite# + ld a, [wNPCMovementScriptSpriteOffset] ; some sprite offset? + ld b, a + ld a, [H_CURRENTSPRITEOFFSET] + cp b + jr nz, .unequal + jp DoScriptedNPCMovement +.unequal + jp UpdateNPCSprite + +; This detects if the current sprite (whose offset is at H_CURRENTSPRITEOFFSET) +; is going to collide with another sprite by looping over the other sprites. +; The current sprite's offset will be labelled with i (e.g. $c1i0). +; The loop sprite's offset will labelled with j (e.g. $c1j0). +; +; Note that the Y coordinate of the sprite (in [$c1k4]) is one of the following +; 9 values when the sprite is aligned with the grid: $fc, $0c, $1c, $2c, ..., $7c. +; 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 + + ld h, wSpriteStateData1 / $100 + ld a, [H_CURRENTSPRITEOFFSET] + add wSpriteStateData1 % $100 + ld l, a + + ld a, [hl] ; a = [$c1i0] (picture) (0 if slot is unused) + and a ; is this sprite slot slot used? + ret z ; return if not used + + ld a, l + add 3 + ld l, a + + ld a, [hli] ; a = [$c1i3] (delta Y) (-1, 0, or 1) + call SetSpriteCollisionValues + + ld a, [hli] ; a = [$C1i4] (Y screen coordinate) + add 4 ; align with multiple of $10 + +; The effect of the following 3 lines is to +; add 7 to a if moving south or +; subtract 7 from a if moving north. + add b + and $f0 + or c + + ld [$ff90], a ; store Y coordinate adjusted for direction of movement + + ld a, [hli] ; a = [$c1i5] (delta X) (-1, 0, or 1) + call SetSpriteCollisionValues + ld a, [hl] ; a = [$C1i6] (X screen coordinate) + +; The effect of the following 3 lines is to +; add 7 to a if moving east or +; subtract 7 from a if moving west. + add b + and $f0 + or c + + ld [$ff91], a ; store X coordinate adjusted for direction of movement + + ld a, l + add 7 + ld l, a + + xor a + ld [hld], a ; zero [$c1id] XXX what's [$c1id] for? + ld [hld], a ; zero [$c1ic] (directions in which collisions occurred) + + ld a, [$ff91] + ld [hld], a ; [$c1ib] = adjusted X coordinate + ld a, [$ff90] + ld [hl], a ; [$c1ia] = adjusted Y coordinate + + xor a ; zero the loop counter + +.loop + ld [$ff8f], a ; store loop counter + swap a + ld e, a + ld a, [H_CURRENTSPRITEOFFSET] + cp e ; does the loop sprite match the current sprite? + jp z, .next ; go to the next sprite if they match + + ld d, h + ld a, [de] ; a = [$c1j0] (picture) (0 if slot is unused) + and a ; is this sprite slot slot used? + jp z, .next ; go the next sprite if not used + + inc e + inc e + ld a, [de] ; a = [$c1j2] ($ff means the sprite is offscreen) + inc a + jp z, .next ; go the next sprite if offscreen + + ld a, [H_CURRENTSPRITEOFFSET] + add 10 + ld l, a + + inc e + ld a, [de] ; a = [$c1j3] (delta Y) + call SetSpriteCollisionValues + + inc e + ld a, [de] ; a = [$C1j4] (Y screen coordinate) + add 4 ; align with multiple of $10 + +; The effect of the following 3 lines is to +; add 7 to a if moving south or +; subtract 7 from a if moving north. + add b + and $f0 + or c + + sub [hl] ; subtract the adjusted Y coordinate of sprite i ([$c1ia]) from that of sprite j + +; calculate the absolute value of the difference to get the distance + jr nc, .noCarry1 + cpl + inc a +.noCarry1 + ld [$ff90], a ; store the distance between the two sprites' adjusted Y values + +; Use the carry flag set by the above subtraction to determine which sprite's +; Y coordinate is larger. This information is used later to set [$c1ic], +; which stores which direction the collision occurred in. +; The following 5 lines set the lowest 2 bits of c, which are later shifted left by 2. +; If sprite i's Y is larger, set lowest 2 bits of c to 10. +; If sprite j's Y is larger or both are equal, set lowest 2 bits of c to 01. + push af + rl c + pop af + ccf + rl c + +; If sprite i's delta Y is 0, then b = 7, else b = 9. + ld b, 7 + ld a, [hl] ; a = [$c1ia] (adjusted Y coordinate) + and $f + jr z, .next1 + ld b, 9 + +.next1 + ld a, [$ff90] ; a = distance between adjusted Y coordinates + sub b + ld [$ff92], a ; store distance adjusted using sprite i's direction + ld a, b + ld [$ff90], a ; store 7 or 9 depending on sprite i's delta Y + jr c, .checkXDistance + +; If sprite j's delta Y is 0, then b = 7, else b = 9. + ld b, 7 + dec e + ld a, [de] ; a = [$c1j3] (delta Y) + inc e + and a + jr z, .next2 + ld b, 9 + +.next2 + ld a, [$ff92] ; a = distance adjusted using sprite i's direction + sub b ; adjust distance using sprite j's direction + jr z, .checkXDistance + jr nc, .next ; go to next sprite if distance is still positive after both adjustments + +.checkXDistance + inc e + inc l + ld a, [de] ; a = [$c1j5] (delta X) + + push bc + + call SetSpriteCollisionValues + inc e + ld a, [de] ; a = [$c1j6] (X screen coordinate) + +; The effect of the following 3 lines is to +; add 7 to a if moving east or +; subtract 7 from a if moving west. + add b + and $f0 + or c + + pop bc + + sub [hl] ; subtract the adjusted X coordinate of sprite i ([$c1ib]) from that of sprite j + +; calculate the absolute value of the difference to get the distance + jr nc, .noCarry2 + cpl + inc a +.noCarry2 + ld [$ff91], a ; store the distance between the two sprites' adjusted X values + +; Use the carry flag set by the above subtraction to determine which sprite's +; X coordinate is larger. This information is used later to set [$c1ic], +; which stores which direction the collision occurred in. +; The following 5 lines set the lowest 2 bits of c. +; If sprite i's X is larger, set lowest 2 bits of c to 10. +; If sprite j's X is larger or both are equal, set lowest 2 bits of c to 01. + push af + rl c + pop af + ccf + rl c + +; If sprite i's delta X is 0, then b = 7, else b = 9. + ld b, 7 + ld a, [hl] ; a = [$c1ib] (adjusted X coordinate) + and $f + jr z, .next3 + ld b, 9 + +.next3 + ld a, [$ff91] ; a = distance between adjusted X coordinates + sub b + ld [$ff92], a ; store distance adjusted using sprite i's direction + ld a, b + ld [$ff91], a ; store 7 or 9 depending on sprite i's delta X + jr c, .collision + +; If sprite j's delta X is 0, then b = 7, else b = 9. + ld b, 7 + dec e + ld a, [de] ; a = [$c1j5] (delta X) + inc e + and a + jr z, .next4 + ld b, 9 + +.next4 + ld a, [$ff92] ; a = distance adjusted using sprite i's direction + sub b ; adjust distance using sprite j's direction + jr z, .collision + jr nc, .next ; go to next sprite if distance is still positive after both adjustments + +.collision + ld a, [$ff91] ; a = 7 or 9 depending on sprite i's delta X + ld b, a + ld a, [$ff90] ; a = 7 or 9 depending on sprite i's delta Y + inc l + +; If delta X isn't 0 and delta Y is 0, then b = %0011, else b = %1100. +; (note that normally if delta X isn't 0, then delta Y must be 0 and vice versa) + cp b + jr c, .next5 + ld b, %1100 + jr .next6 +.next5 + ld b, %0011 + +.next6 + ld a, c ; c has 2 bits set (one of bits 0-1 is set for the X axis and one of bits 2-3 for the Y axis) + and b ; we select either the bit in bits 0-1 or bits 2-3 based on the calculation immediately above + or [hl] ; or with existing collision direction bits in [$c1ic] + ld [hl], a ; store new value + ld a, c ; useless code because a is overwritten before being used again + +; set bit in [$c1ie] or [$c1if] to indicate which sprite the collision occurred with + inc l + inc l + ld a, [$ff8f] ; a = loop counter + ld de, SpriteCollisionBitTable + add a + add e + ld e, a + jr nc, .noCarry3 + inc d +.noCarry3 + ld a, [de] + or [hl] + ld [hli], a + inc de + ld a, [de] + or [hl] + ld [hl], a + +.next + ld a, [$ff8f] ; a = loop counter + inc a + cp $10 + jp nz, .loop + ret + +; takes delta X or delta Y in a +; b = delta X/Y +; c = 0 if delta X/Y is 0 +; c = 7 if delta X/Y is 1 +; c = 9 if delta X/Y is -1 +SetSpriteCollisionValues: + and a + ld b, 0 + ld c, 0 + jr z, .done + ld c, 9 + cp -1 + jr z, .ok + ld c, 7 + ld a, 0 +.ok + ld b, a +.done + ret + +SpriteCollisionBitTable: + db %00000000,%00000001 + db %00000000,%00000010 + db %00000000,%00000100 + db %00000000,%00001000 + db %00000000,%00010000 + db %00000000,%00100000 + db %00000000,%01000000 + db %00000000,%10000000 + db %00000001,%00000000 + db %00000010,%00000000 + db %00000100,%00000000 + db %00001000,%00000000 + db %00010000,%00000000 + db %00100000,%00000000 + db %01000000,%00000000 + db %10000000,%00000000 diff --git a/engine/overworld/ssanne.asm b/engine/overworld/ssanne.asm deleted file mode 100755 index 6c26b712..00000000 --- a/engine/overworld/ssanne.asm +++ /dev/null @@ -1,93 +0,0 @@ -AnimateBoulderDust: - ld a, $1 - ld [wWhichAnimationOffsets], a ; select the boulder dust offsets - ld a, [wUpdateSpritesEnabled] - push af - ld a, $ff - ld [wUpdateSpritesEnabled], a - ld a, %11100100 - ld [rOBP1], a - call LoadSmokeTileFourTimes - callba WriteCutOrBoulderDustAnimationOAMBlock - ld c, 8 ; number of steps in animation -.loop - push bc - call GetMoveBoulderDustFunctionPointer - ld bc, .returnAddress - push bc - ld c, 4 - jp hl -.returnAddress - ld a, [rOBP1] - xor %01100100 - ld [rOBP1], a - call Delay3 - pop bc - dec c - jr nz, .loop - pop af - ld [wUpdateSpritesEnabled], a - jp LoadPlayerSpriteGraphics - -GetMoveBoulderDustFunctionPointer: - ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction - ld hl, MoveBoulderDustFunctionPointerTable - ld c, a - ld b, $0 - add hl, bc - ld a, [hli] - ld [wCoordAdjustmentAmount], a - ld a, [hli] - ld e, a - ld a, [hli] - ld h, [hl] - ld l, a - push hl - ld hl, wOAMBuffer + $90 - ld d, $0 - add hl, de - ld e, l - ld d, h - pop hl - ret - -MoveBoulderDustFunctionPointerTable: -; facing down - db $FF,$00 - dw AdjustOAMBlockYPos - -; facing up - db $01,$00 - dw AdjustOAMBlockYPos - -; facing left - db $01,$01 - dw AdjustOAMBlockXPos - -; facing right - db $FF,$01 - dw AdjustOAMBlockXPos - -LoadSmokeTileFourTimes:: - ld hl, vChars1 + $7c0 - ld c, $4 -.loop - push bc - push hl - call LoadSmokeTile - pop hl - ld bc, $10 - add hl, bc - pop bc - dec c - jr nz, .loop - ret - -LoadSmokeTile: - ld de, SSAnneSmokePuffTile - lb bc, BANK(SSAnneSmokePuffTile), (SSAnneSmokePuffTileEnd - SSAnneSmokePuffTile) / $10 - jp CopyVideoData - -SSAnneSmokePuffTile: - INCBIN "gfx/overworld/smoke.2bpp" -SSAnneSmokePuffTileEnd: diff --git a/engine/overworld/tileset_header.asm b/engine/overworld/tileset_header.asm deleted file mode 100644 index 6e33974f..00000000 --- a/engine/overworld/tileset_header.asm +++ /dev/null @@ -1,60 +0,0 @@ -LoadTilesetHeader: - call GetPredefRegisters - push hl - ld d, 0 - 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 - ld de, wTilesetBank - ld c, $b -.copyTilesetHeaderLoop - ld a, [hli] - ld [de], a - inc de - dec c - jr nz, .copyTilesetHeaderLoop - ld a, [hl] - ld [hTilesetType], a - xor a - ld [$ffd8], a - pop hl - ld a, [wCurMapTileset] - push hl - push de - ld hl, DungeonTilesets - ld de, $1 - call IsInArray - pop de - pop hl - jr c, .asm_c797 - ld a, [wCurMapTileset] - ld b, a - ld a, [hPreviousTileset] - cp b - jr z, .done -.asm_c797 - ld a, [wDestinationWarpID] - cp $ff - jr z, .done - call LoadDestinationWarpPosition - ld a, [wYCoord] - and $1 - ld [wYBlockCoord], a - ld a, [wXCoord] - and $1 - ld [wXBlockCoord], a -.done - ret - -INCLUDE "data/dungeon_tilesets.asm" - -INCLUDE "data/tileset_headers.asm" diff --git a/engine/overworld/tilesets.asm b/engine/overworld/tilesets.asm new file mode 100644 index 00000000..6e33974f --- /dev/null +++ b/engine/overworld/tilesets.asm @@ -0,0 +1,60 @@ +LoadTilesetHeader: + call GetPredefRegisters + push hl + ld d, 0 + 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 + ld de, wTilesetBank + ld c, $b +.copyTilesetHeaderLoop + ld a, [hli] + ld [de], a + inc de + dec c + jr nz, .copyTilesetHeaderLoop + ld a, [hl] + ld [hTilesetType], a + xor a + ld [$ffd8], a + pop hl + ld a, [wCurMapTileset] + push hl + push de + ld hl, DungeonTilesets + ld de, $1 + call IsInArray + pop de + pop hl + jr c, .asm_c797 + ld a, [wCurMapTileset] + ld b, a + ld a, [hPreviousTileset] + cp b + jr z, .done +.asm_c797 + ld a, [wDestinationWarpID] + cp $ff + jr z, .done + call LoadDestinationWarpPosition + ld a, [wYCoord] + and $1 + ld [wYBlockCoord], a + ld a, [wXCoord] + and $1 + ld [wXBlockCoord], a +.done + ret + +INCLUDE "data/dungeon_tilesets.asm" + +INCLUDE "data/tileset_headers.asm" diff --git a/engine/overworld/trainer_sight.asm b/engine/overworld/trainer_sight.asm new file mode 100755 index 00000000..5a68b627 --- /dev/null +++ b/engine/overworld/trainer_sight.asm @@ -0,0 +1,349 @@ +_GetSpritePosition1:: + ld hl, wSpriteStateData1 + ld de, $4 + ld a, [wSpriteIndex] + ld [H_SPRITEINDEX], a + call GetSpriteDataPointer + ld a, [hli] ; c1x4 (screen Y pos) + ld [$ffeb], a + inc hl + ld a, [hl] ; c1x6 (screen X pos) + ld [$ffec], a + ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6) + add hl, de + ld a, [hli] ; c2x4 (map Y pos) + ld [$ffed], a + ld a, [hl] ; c2x5 (map X pos) + ld [$ffee], a + ret + +_GetSpritePosition2:: + ld hl, wSpriteStateData1 + ld de, $4 + ld a, [wSpriteIndex] + ld [H_SPRITEINDEX], a + call GetSpriteDataPointer + ld a, [hli] ; c1x4 (screen Y pos) + ld [wSavedSpriteScreenY], a + inc hl + ld a, [hl] ; c1x6 (screen X pos) + ld [wSavedSpriteScreenX], a + ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6) + add hl, de + ld a, [hli] ; c2x4 (map Y pos) + ld [wSavedSpriteMapY], a + ld a, [hl] ; c2x5 (map X pos) + ld [wSavedSpriteMapX], a + ret + +_SetSpritePosition1:: + ld hl, wSpriteStateData1 + ld de, $4 + ld a, [wSpriteIndex] + ld [H_SPRITEINDEX], a + call GetSpriteDataPointer + ld a, [$ffeb] ; c1x4 (screen Y pos) + ld [hli], a + inc hl + ld a, [$ffec] ; c1x6 (screen X pos) + ld [hl], a + ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6) + add hl, de + ld a, [$ffed] ; c2x4 (map Y pos) + ld [hli], a + ld a, [$ffee] ; c2x5 (map X pos) + ld [hl], a + ret + +_SetSpritePosition2:: + ld hl, wSpriteStateData1 + ld de, 4 + ld a, [wSpriteIndex] + ld [H_SPRITEINDEX], a + call GetSpriteDataPointer + ld a, [wSavedSpriteScreenY] + ld [hli], a ; c1x4 (screen Y pos) + inc hl + ld a, [wSavedSpriteScreenX] + ld [hl], a ; c1x6 (screen X pos) + ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6) + add hl, de + ld a, [wSavedSpriteMapY] + ld [hli], a ; c2x4 (map Y pos) + ld a, [wSavedSpriteMapX] + ld [hl], a ; c2x5 (map X pos) + ret + +TrainerWalkUpToPlayer:: + ld a, [wSpriteIndex] + swap a + ld [wTrainerSpriteOffset], a + call ReadTrainerScreenPosition + ld a, [wTrainerFacingDirection] + and a ; SPRITE_FACING_DOWN + jr z, .facingDown + cp SPRITE_FACING_UP + jr z, .facingUp + cp SPRITE_FACING_LEFT + jr z, .facingLeft + jr .facingRight +.facingDown + ld a, [wTrainerScreenY] + ld b, a + ld a, $3c ; (fixed) player screen Y pos + call CalcDifference + cp $10 ; trainer is right above player + ret z + swap a + dec a + ld c, a ; bc = steps yet to go to reach player + xor a + ld b, a ; a = direction to go to + jr .writeWalkScript +.facingUp + ld a, [wTrainerScreenY] + ld b, a + ld a, $3c ; (fixed) player screen Y pos + call CalcDifference + cp $10 ; trainer is right below player + ret z + swap a + dec a + ld c, a ; bc = steps yet to go to reach player + ld b, $0 + ld a, $40 ; a = direction to go to + jr .writeWalkScript +.facingRight + ld a, [wTrainerScreenX] + ld b, a + ld a, $40 ; (fixed) player screen X pos + call CalcDifference + cp $10 ; trainer is directly left of player + ret z + swap a + dec a + ld c, a ; bc = steps yet to go to reach player + ld b, $0 + ld a, $c0 ; a = direction to go to + jr .writeWalkScript +.facingLeft + ld a, [wTrainerScreenX] + ld b, a + ld a, $40 ; (fixed) player screen X pos + call CalcDifference + cp $10 ; trainer is directly right of player + ret z + swap a + dec a + ld c, a ; bc = steps yet to go to reach player + ld b, $0 + ld a, $80 ; a = direction to go to +.writeWalkScript + ld hl, wNPCMovementDirections2 + ld de, wNPCMovementDirections2 + call FillMemory ; write the necessary steps to reach player + ld [hl], $ff ; write end of list sentinel + ld a, [wSpriteIndex] + ld [H_SPRITEINDEX], a + jp MoveSprite_ + +; input: de = offset within sprite entry +; output: hl = pointer to sprite data +GetSpriteDataPointer: + push de + add hl, de + ld a, [H_SPRITEINDEX] + swap a + ld d, $0 + ld e, a + add hl, de + pop de + ret + +; tests if this trainer is in the right position to engage the player and do so if she is. +TrainerEngage: + push hl + push de + ld a, [wTrainerSpriteOffset] + add $2 + ld d, $0 + ld e, a + ld hl, wSpriteStateData1 + add hl, de + ld a, [hl] ; c1x2: sprite image index + sub $ff + jr nz, .spriteOnScreen ; test if sprite is on screen + jp .noEngage +.spriteOnScreen + ld a, [wTrainerSpriteOffset] + add $9 + ld d, $0 + ld e, a + ld hl, wSpriteStateData1 + add hl, de + ld a, [hl] ; c1x9: facing direction + ld [wTrainerFacingDirection], a + call ReadTrainerScreenPosition + ld a, [wTrainerScreenY] ; sprite screen Y pos + ld b, a + ld a, $3c + cp b + jr z, .linedUpY + ld a, [wTrainerScreenX] ; sprite screen X pos + ld b, a + ld a, $40 + cp b + jr z, .linedUpX + xor a + jp .noEngage +.linedUpY + ld a, [wTrainerScreenX] ; sprite screen X pos + ld b, a + ld a, $40 ; (fixed) player X position + call CalcDifference ; calc distance + jr z, .noEngage ; exact same position as player + call CheckSpriteCanSeePlayer + jr c, .engage + xor a + jr .noEngage +.linedUpX + ld a, [wTrainerScreenY] ; sprite screen Y pos + ld b, a + ld a, $3c ; (fixed) player Y position + call CalcDifference ; calc distance + jr z, .noEngage ; exact same position as player + call CheckSpriteCanSeePlayer + jr c, .engage + xor a + jp .noEngage +.engage + call CheckPlayerIsInFrontOfSprite + ld a, [wTrainerSpriteOffset] + and a + jr z, .noEngage + ld hl, wFlags_0xcd60 + set 0, [hl] + call EngageMapTrainer + ld a, $ff +.noEngage + ld [wTrainerSpriteOffset], a + pop de + pop hl + ret + +; reads trainer's Y position to wTrainerScreenY and X position to wTrainerScreenX +ReadTrainerScreenPosition: + ld a, [wTrainerSpriteOffset] + add $4 + ld d, $0 + ld e, a + ld hl, wSpriteStateData1 + add hl, de + ld a, [hl] ; c1x4 (sprite Y pos) + ld [wTrainerScreenY], a + ld a, [wTrainerSpriteOffset] + add $6 + ld d, $0 + ld e, a + ld hl, wSpriteStateData1 + add hl, de + ld a, [hl] ; c1x6 (sprite X pos) + ld [wTrainerScreenX], a + ret + +; checks if the sprite is properly lined up with the player with respect to the direction it's looking. Also checks the distance between player and sprite +; note that this does not necessarily mean the sprite is seeing the player, he could be behind it's back +; a: distance player to sprite +CheckSpriteCanSeePlayer: + ld b, a + ld a, [wTrainerEngageDistance] ; how far the trainer can see + cp b + jr nc, .checkIfLinedUp + jr .notInLine ; player too far away +.checkIfLinedUp + ld a, [wTrainerFacingDirection] ; sprite facing direction + cp SPRITE_FACING_DOWN + jr z, .checkXCoord + cp SPRITE_FACING_UP + jr z, .checkXCoord + cp SPRITE_FACING_LEFT + jr z, .checkYCoord + cp SPRITE_FACING_RIGHT + jr z, .checkYCoord + jr .notInLine +.checkXCoord + ld a, [wTrainerScreenX] ; sprite screen X position + ld b, a + cp $40 + jr z, .inLine + jr .notInLine +.checkYCoord + ld a, [wTrainerScreenY] ; sprite screen Y position + ld b, a + cp $3c + jr nz, .notInLine +.inLine + scf + ret +.notInLine + and a + ret + +; tests if the player is in front of the sprite (rather than behind it) +CheckPlayerIsInFrontOfSprite: + ld a, [wCurMap] + cp POWER_PLANT + jp z, .engage ; bypass this for power plant to get voltorb fake items to work + ld a, [wTrainerSpriteOffset] + add $4 + ld d, $0 + ld e, a + ld hl, wSpriteStateData1 + add hl, de + ld a, [hl] ; c1x4 (sprite screen Y pos) + cp $fc + jr nz, .notOnTopmostTile ; special case if sprite is on topmost tile (Y = $fc (-4)), make it come down a block + ld a, $c +.notOnTopmostTile + ld [wTrainerScreenY], a + ld a, [wTrainerSpriteOffset] + add $6 + ld d, $0 + ld e, a + ld hl, wSpriteStateData1 + add hl, de + ld a, [hl] ; c1x6 (sprite screen X pos) + ld [wTrainerScreenX], a + ld a, [wTrainerFacingDirection] ; facing direction + cp SPRITE_FACING_DOWN + jr nz, .notFacingDown + ld a, [wTrainerScreenY] ; sprite screen Y pos + cp $3c + jr c, .engage ; sprite above player + jr .noEngage ; sprite below player +.notFacingDown + cp SPRITE_FACING_UP + jr nz, .notFacingUp + ld a, [wTrainerScreenY] ; sprite screen Y pos + cp $3c + jr nc, .engage ; sprite below player + jr .noEngage ; sprite above player +.notFacingUp + cp SPRITE_FACING_LEFT + jr nz, .notFacingLeft + ld a, [wTrainerScreenX] ; sprite screen X pos + cp $40 + jr nc, .engage ; sprite right of player + jr .noEngage ; sprite left of player +.notFacingLeft + ld a, [wTrainerScreenX] ; sprite screen X pos + cp $40 + jr nc, .noEngage ; sprite right of player +.engage + ld a, $ff + jr .done +.noEngage + xor a +.done + ld [wTrainerSpriteOffset], a + ret diff --git a/engine/overworld/trainers.asm b/engine/overworld/trainers.asm deleted file mode 100755 index 5a68b627..00000000 --- a/engine/overworld/trainers.asm +++ /dev/null @@ -1,349 +0,0 @@ -_GetSpritePosition1:: - ld hl, wSpriteStateData1 - ld de, $4 - ld a, [wSpriteIndex] - ld [H_SPRITEINDEX], a - call GetSpriteDataPointer - ld a, [hli] ; c1x4 (screen Y pos) - ld [$ffeb], a - inc hl - ld a, [hl] ; c1x6 (screen X pos) - ld [$ffec], a - ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6) - add hl, de - ld a, [hli] ; c2x4 (map Y pos) - ld [$ffed], a - ld a, [hl] ; c2x5 (map X pos) - ld [$ffee], a - ret - -_GetSpritePosition2:: - ld hl, wSpriteStateData1 - ld de, $4 - ld a, [wSpriteIndex] - ld [H_SPRITEINDEX], a - call GetSpriteDataPointer - ld a, [hli] ; c1x4 (screen Y pos) - ld [wSavedSpriteScreenY], a - inc hl - ld a, [hl] ; c1x6 (screen X pos) - ld [wSavedSpriteScreenX], a - ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6) - add hl, de - ld a, [hli] ; c2x4 (map Y pos) - ld [wSavedSpriteMapY], a - ld a, [hl] ; c2x5 (map X pos) - ld [wSavedSpriteMapX], a - ret - -_SetSpritePosition1:: - ld hl, wSpriteStateData1 - ld de, $4 - ld a, [wSpriteIndex] - ld [H_SPRITEINDEX], a - call GetSpriteDataPointer - ld a, [$ffeb] ; c1x4 (screen Y pos) - ld [hli], a - inc hl - ld a, [$ffec] ; c1x6 (screen X pos) - ld [hl], a - ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6) - add hl, de - ld a, [$ffed] ; c2x4 (map Y pos) - ld [hli], a - ld a, [$ffee] ; c2x5 (map X pos) - ld [hl], a - ret - -_SetSpritePosition2:: - ld hl, wSpriteStateData1 - ld de, 4 - ld a, [wSpriteIndex] - ld [H_SPRITEINDEX], a - call GetSpriteDataPointer - ld a, [wSavedSpriteScreenY] - ld [hli], a ; c1x4 (screen Y pos) - inc hl - ld a, [wSavedSpriteScreenX] - ld [hl], a ; c1x6 (screen X pos) - ld de, (wSpriteStateData2 + $4) - (wSpriteStateData1 + $6) - add hl, de - ld a, [wSavedSpriteMapY] - ld [hli], a ; c2x4 (map Y pos) - ld a, [wSavedSpriteMapX] - ld [hl], a ; c2x5 (map X pos) - ret - -TrainerWalkUpToPlayer:: - ld a, [wSpriteIndex] - swap a - ld [wTrainerSpriteOffset], a - call ReadTrainerScreenPosition - ld a, [wTrainerFacingDirection] - and a ; SPRITE_FACING_DOWN - jr z, .facingDown - cp SPRITE_FACING_UP - jr z, .facingUp - cp SPRITE_FACING_LEFT - jr z, .facingLeft - jr .facingRight -.facingDown - ld a, [wTrainerScreenY] - ld b, a - ld a, $3c ; (fixed) player screen Y pos - call CalcDifference - cp $10 ; trainer is right above player - ret z - swap a - dec a - ld c, a ; bc = steps yet to go to reach player - xor a - ld b, a ; a = direction to go to - jr .writeWalkScript -.facingUp - ld a, [wTrainerScreenY] - ld b, a - ld a, $3c ; (fixed) player screen Y pos - call CalcDifference - cp $10 ; trainer is right below player - ret z - swap a - dec a - ld c, a ; bc = steps yet to go to reach player - ld b, $0 - ld a, $40 ; a = direction to go to - jr .writeWalkScript -.facingRight - ld a, [wTrainerScreenX] - ld b, a - ld a, $40 ; (fixed) player screen X pos - call CalcDifference - cp $10 ; trainer is directly left of player - ret z - swap a - dec a - ld c, a ; bc = steps yet to go to reach player - ld b, $0 - ld a, $c0 ; a = direction to go to - jr .writeWalkScript -.facingLeft - ld a, [wTrainerScreenX] - ld b, a - ld a, $40 ; (fixed) player screen X pos - call CalcDifference - cp $10 ; trainer is directly right of player - ret z - swap a - dec a - ld c, a ; bc = steps yet to go to reach player - ld b, $0 - ld a, $80 ; a = direction to go to -.writeWalkScript - ld hl, wNPCMovementDirections2 - ld de, wNPCMovementDirections2 - call FillMemory ; write the necessary steps to reach player - ld [hl], $ff ; write end of list sentinel - ld a, [wSpriteIndex] - ld [H_SPRITEINDEX], a - jp MoveSprite_ - -; input: de = offset within sprite entry -; output: hl = pointer to sprite data -GetSpriteDataPointer: - push de - add hl, de - ld a, [H_SPRITEINDEX] - swap a - ld d, $0 - ld e, a - add hl, de - pop de - ret - -; tests if this trainer is in the right position to engage the player and do so if she is. -TrainerEngage: - push hl - push de - ld a, [wTrainerSpriteOffset] - add $2 - ld d, $0 - ld e, a - ld hl, wSpriteStateData1 - add hl, de - ld a, [hl] ; c1x2: sprite image index - sub $ff - jr nz, .spriteOnScreen ; test if sprite is on screen - jp .noEngage -.spriteOnScreen - ld a, [wTrainerSpriteOffset] - add $9 - ld d, $0 - ld e, a - ld hl, wSpriteStateData1 - add hl, de - ld a, [hl] ; c1x9: facing direction - ld [wTrainerFacingDirection], a - call ReadTrainerScreenPosition - ld a, [wTrainerScreenY] ; sprite screen Y pos - ld b, a - ld a, $3c - cp b - jr z, .linedUpY - ld a, [wTrainerScreenX] ; sprite screen X pos - ld b, a - ld a, $40 - cp b - jr z, .linedUpX - xor a - jp .noEngage -.linedUpY - ld a, [wTrainerScreenX] ; sprite screen X pos - ld b, a - ld a, $40 ; (fixed) player X position - call CalcDifference ; calc distance - jr z, .noEngage ; exact same position as player - call CheckSpriteCanSeePlayer - jr c, .engage - xor a - jr .noEngage -.linedUpX - ld a, [wTrainerScreenY] ; sprite screen Y pos - ld b, a - ld a, $3c ; (fixed) player Y position - call CalcDifference ; calc distance - jr z, .noEngage ; exact same position as player - call CheckSpriteCanSeePlayer - jr c, .engage - xor a - jp .noEngage -.engage - call CheckPlayerIsInFrontOfSprite - ld a, [wTrainerSpriteOffset] - and a - jr z, .noEngage - ld hl, wFlags_0xcd60 - set 0, [hl] - call EngageMapTrainer - ld a, $ff -.noEngage - ld [wTrainerSpriteOffset], a - pop de - pop hl - ret - -; reads trainer's Y position to wTrainerScreenY and X position to wTrainerScreenX -ReadTrainerScreenPosition: - ld a, [wTrainerSpriteOffset] - add $4 - ld d, $0 - ld e, a - ld hl, wSpriteStateData1 - add hl, de - ld a, [hl] ; c1x4 (sprite Y pos) - ld [wTrainerScreenY], a - ld a, [wTrainerSpriteOffset] - add $6 - ld d, $0 - ld e, a - ld hl, wSpriteStateData1 - add hl, de - ld a, [hl] ; c1x6 (sprite X pos) - ld [wTrainerScreenX], a - ret - -; checks if the sprite is properly lined up with the player with respect to the direction it's looking. Also checks the distance between player and sprite -; note that this does not necessarily mean the sprite is seeing the player, he could be behind it's back -; a: distance player to sprite -CheckSpriteCanSeePlayer: - ld b, a - ld a, [wTrainerEngageDistance] ; how far the trainer can see - cp b - jr nc, .checkIfLinedUp - jr .notInLine ; player too far away -.checkIfLinedUp - ld a, [wTrainerFacingDirection] ; sprite facing direction - cp SPRITE_FACING_DOWN - jr z, .checkXCoord - cp SPRITE_FACING_UP - jr z, .checkXCoord - cp SPRITE_FACING_LEFT - jr z, .checkYCoord - cp SPRITE_FACING_RIGHT - jr z, .checkYCoord - jr .notInLine -.checkXCoord - ld a, [wTrainerScreenX] ; sprite screen X position - ld b, a - cp $40 - jr z, .inLine - jr .notInLine -.checkYCoord - ld a, [wTrainerScreenY] ; sprite screen Y position - ld b, a - cp $3c - jr nz, .notInLine -.inLine - scf - ret -.notInLine - and a - ret - -; tests if the player is in front of the sprite (rather than behind it) -CheckPlayerIsInFrontOfSprite: - ld a, [wCurMap] - cp POWER_PLANT - jp z, .engage ; bypass this for power plant to get voltorb fake items to work - ld a, [wTrainerSpriteOffset] - add $4 - ld d, $0 - ld e, a - ld hl, wSpriteStateData1 - add hl, de - ld a, [hl] ; c1x4 (sprite screen Y pos) - cp $fc - jr nz, .notOnTopmostTile ; special case if sprite is on topmost tile (Y = $fc (-4)), make it come down a block - ld a, $c -.notOnTopmostTile - ld [wTrainerScreenY], a - ld a, [wTrainerSpriteOffset] - add $6 - ld d, $0 - ld e, a - ld hl, wSpriteStateData1 - add hl, de - ld a, [hl] ; c1x6 (sprite screen X pos) - ld [wTrainerScreenX], a - ld a, [wTrainerFacingDirection] ; facing direction - cp SPRITE_FACING_DOWN - jr nz, .notFacingDown - ld a, [wTrainerScreenY] ; sprite screen Y pos - cp $3c - jr c, .engage ; sprite above player - jr .noEngage ; sprite below player -.notFacingDown - cp SPRITE_FACING_UP - jr nz, .notFacingUp - ld a, [wTrainerScreenY] ; sprite screen Y pos - cp $3c - jr nc, .engage ; sprite below player - jr .noEngage ; sprite above player -.notFacingUp - cp SPRITE_FACING_LEFT - jr nz, .notFacingLeft - ld a, [wTrainerScreenX] ; sprite screen X pos - cp $40 - jr nc, .engage ; sprite right of player - jr .noEngage ; sprite left of player -.notFacingLeft - ld a, [wTrainerScreenX] ; sprite screen X pos - cp $40 - jr nc, .noEngage ; sprite right of player -.engage - ld a, $ff - jr .done -.noEngage - xor a -.done - ld [wTrainerSpriteOffset], a - ret diff --git a/engine/overworld/turn_sprite.asm b/engine/overworld/turn_sprite.asm new file mode 100755 index 00000000..c7f7712b --- /dev/null +++ b/engine/overworld/turn_sprite.asm @@ -0,0 +1,25 @@ +UpdateSpriteFacingOffsetAndDelayMovement:: + ld h, $c2 + ld a, [H_CURRENTSPRITEOFFSET] + add $8 + ld l, a + ld a, $7f ; maximum movement delay + ld [hl], a ; c2x8 (movement delay) + dec h + ld a, [H_CURRENTSPRITEOFFSET] + add $9 + ld l, a + ld a, [hld] ; c1x9 (facing direction) + ld b, a + xor a + ld [hld], a + ld [hl], a ; c1x8 (walk animation frame) + ld a, [H_CURRENTSPRITEOFFSET] + add $2 + ld l, a + ld a, [hl] ; c1x2 (facing and animation table offset) + or b ; or in the facing direction + ld [hld], a + ld a, $2 ; delayed movement status + ld [hl], a ; c1x1 (movement status) + ret diff --git a/engine/palettes.asm b/engine/palettes.asm deleted file mode 100755 index 39991d48..00000000 --- a/engine/palettes.asm +++ /dev/null @@ -1,641 +0,0 @@ -_RunPaletteCommand: - call GetPredefRegisters - ld a, b - cp $ff - jr nz, .next - ld a, [wDefaultPaletteCommand] ; use default command if command ID is $ff -.next - cp UPDATE_PARTY_MENU_BLK_PACKET - jp z, UpdatePartyMenuBlkPacket - ld l, a - ld h, 0 - add hl, hl - ld de, SetPalFunctions - add hl, de - ld a, [hli] - ld h, [hl] - ld l, a - ld de, SendSGBPackets - push de - jp hl - -SetPal_BattleBlack: - ld hl, PalPacket_Black - ld de, BlkPacket_Battle - ret - -; uses PalPacket_Empty to build a packet based on mon IDs and health color -SetPal_Battle: - ld hl, PalPacket_Empty - ld de, wPalPacket - ld bc, $10 - call CopyData - ld a, [wPlayerBattleStatus3] - ld hl, wBattleMonSpecies - call DeterminePaletteID - ld b, a - ld a, [wEnemyBattleStatus3] - ld hl, wEnemyMonSpecies2 - call DeterminePaletteID - ld c, a - ld hl, wPalPacket + 1 - ld a, [wPlayerHPBarColor] - add PAL_GREENBAR - ld [hli], a - inc hl - ld a, [wEnemyHPBarColor] - add PAL_GREENBAR - ld [hli], a - inc hl - ld a, b - ld [hli], a - inc hl - ld a, c - ld [hl], a - ld hl, wPalPacket - ld de, BlkPacket_Battle - ld a, SET_PAL_BATTLE - ld [wDefaultPaletteCommand], a - ret - -SetPal_TownMap: - ld hl, PalPacket_TownMap - ld de, BlkPacket_WholeScreen - ret - -; uses PalPacket_Empty to build a packet based the mon ID -SetPal_StatusScreen: - ld hl, PalPacket_Empty - ld de, wPalPacket - ld bc, $10 - call CopyData - ld a, [wcf91] - cp NUM_POKEMON_INDEXES + 1 - jr c, .pokemon - ld a, $1 ; not pokemon -.pokemon - call DeterminePaletteIDOutOfBattle - push af - ld hl, wPalPacket + 1 - ld a, [wStatusScreenHPBarColor] - add PAL_GREENBAR - ld [hli], a - inc hl - pop af - ld [hl], a - ld hl, wPalPacket - ld de, BlkPacket_StatusScreen - ret - -SetPal_PartyMenu: - ld hl, PalPacket_PartyMenu - ld de, wPartyMenuBlkPacket - ret - -SetPal_Pokedex: - ld hl, PalPacket_Pokedex - ld de, wPalPacket - ld bc, $10 - call CopyData - ld a, [wcf91] - call DeterminePaletteIDOutOfBattle - ld hl, wPalPacket + 3 - ld [hl], a - ld hl, wPalPacket - ld de, BlkPacket_Pokedex - ret - -SetPal_Slots: - ld hl, PalPacket_Slots - ld de, BlkPacket_Slots - ret - -SetPal_TitleScreen: - ld hl, PalPacket_Titlescreen - ld de, BlkPacket_Titlescreen - ret - -; used mostly for menus and the Oak intro -SetPal_Generic: - ld hl, PalPacket_Generic - ld de, BlkPacket_WholeScreen - ret - -SetPal_NidorinoIntro: - ld hl, PalPacket_NidorinoIntro - ld de, BlkPacket_NidorinoIntro - ret - -SetPal_GameFreakIntro: - ld hl, PalPacket_GameFreakIntro - ld de, BlkPacket_GameFreakIntro - ld a, SET_PAL_GENERIC - ld [wDefaultPaletteCommand], a - ret - -; uses PalPacket_Empty to build a packet based on the current map -SetPal_Overworld: - ld hl, PalPacket_Empty - ld de, wPalPacket - ld bc, $10 - call CopyData - 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 -.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 palette ID is its map ID + 1 - ld hl, wPalPacket + 1 - ld [hld], a - ld de, BlkPacket_WholeScreen - ld a, SET_PAL_OVERWORLD - ld [wDefaultPaletteCommand], a - ret -.PokemonTowerOrAgatha - ld a, PAL_GREYMON - 1 - jr .town -.caveOrBruno - ld a, PAL_CAVE - 1 - jr .town -.Lorelei - xor a - jr .town - -; used when a Pokemon is the only thing on the screen -; such as evolution, trading and the Hall of Fame -SetPal_PokemonWholeScreen: - push bc - ld hl, PalPacket_Empty - ld de, wPalPacket - ld bc, $10 - call CopyData - pop bc - ld a, c - and a - ld a, PAL_BLACK - jr nz, .next - ld a, [wWholeScreenPaletteMonSpecies] - call DeterminePaletteIDOutOfBattle -.next - ld [wPalPacket + 1], a - ld hl, wPalPacket - ld de, BlkPacket_WholeScreen - ret - -SetPal_TrainerCard: - ld hl, BlkPacket_TrainerCard - ld de, wTrainerCardBlkPacket - ld bc, $40 - call CopyData - ld de, BadgeBlkDataLengths - ld hl, wTrainerCardBlkPacket + 2 - ld a, [wObtainedBadges] - ld c, 8 -.badgeLoop - srl a - push af - jr c, .haveBadge -; The player doens't have the badge, so zero the badge's blk data. - push bc - ld a, [de] - ld c, a - xor a -.zeroBadgeDataLoop - ld [hli], a - dec c - jr nz, .zeroBadgeDataLoop - pop bc - jr .nextBadge -.haveBadge -; The player does have the badge, so skip past the badge's blk data. - ld a, [de] -.skipBadgeDataLoop - inc hl - dec a - jr nz, .skipBadgeDataLoop -.nextBadge - pop af - inc de - dec c - jr nz, .badgeLoop - ld hl, PalPacket_TrainerCard - ld de, wTrainerCardBlkPacket - ret - -SetPalFunctions: - dw SetPal_BattleBlack - dw SetPal_Battle - dw SetPal_TownMap - dw SetPal_StatusScreen - dw SetPal_Pokedex - dw SetPal_Slots - dw SetPal_TitleScreen - dw SetPal_NidorinoIntro - dw SetPal_Generic - dw SetPal_Overworld - dw SetPal_PartyMenu - dw SetPal_PokemonWholeScreen - dw SetPal_GameFreakIntro - dw SetPal_TrainerCard - -; The length of the blk data of each badge on the Trainer Card. -; The Rainbow Badge has 3 entries because of its many colors. -BadgeBlkDataLengths: - db 6 ; Boulder Badge - db 6 ; Cascade Badge - db 6 ; Thunder Badge - db 6 * 3 ; Rainbow Badge - db 6 ; Soul Badge - db 6 ; Marsh Badge - db 6 ; Volcano Badge - 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 - and a ; is the mon index 0? - jr z, .skipDexNumConversion - push bc - predef IndexToPokedex - pop bc - ld a, [wd11e] -.skipDexNumConversion - ld e, a - ld d, 0 - ld hl, MonsterPalettes ; not just for Pokemon, Trainers use it too - add hl, de - ld a, [hl] - ret - -InitPartyMenuBlkPacket: - ld hl, BlkPacket_PartyMenu - ld de, wPartyMenuBlkPacket - ld bc, $30 - jp CopyData - -UpdatePartyMenuBlkPacket: -; Update the blk packet with the palette of the HP bar that is -; specified in [wWhichPartyMenuHPBar]. - ld hl, wPartyMenuHPBarColors - ld a, [wWhichPartyMenuHPBar] - ld e, a - ld d, 0 - add hl, de - ld e, l - ld d, h - ld a, [de] - and a - ld e, (1 << 2) | 1 ; green - jr z, .next - dec a - ld e, (2 << 2) | 2 ; yellow - jr z, .next - ld e, (3 << 2) | 3 ; red -.next - push de - ld hl, wPartyMenuBlkPacket + 8 + 1 - ld bc, 6 - ld a, [wWhichPartyMenuHPBar] - call AddNTimes - pop de - ld [hl], e - ret - -SendSGBPacket: -;check number of packets - ld a, [hl] - and $07 - ret z -; store number of packets in B - ld b, a -.loop2 -; save B for later use - push bc -; disable ReadJoypad to prevent it from interfering with sending the packet - ld a, 1 - ld [hDisableJoypadPolling], a -; send RESET signal (P14=LOW, P15=LOW) - xor a - ld [rJOYP], a -; set P14=HIGH, P15=HIGH - ld a, $30 - ld [rJOYP], a -;load length of packets (16 bytes) - ld b, $10 -.nextByte -;set bit counter (8 bits per byte) - ld e, $08 -; get next byte in the packet - ld a, [hli] - ld d, a -.nextBit0 - bit 0, d -; 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) - ld a, $20 -.next0 - ld [rJOYP], a -; must set P14=HIGH,P15=HIGH between each "pulse" - ld a, $30 - ld [rJOYP], a -; rotation will put next bit in 0th position (so we can always use command -; "bit 0,d" to fetch the bit that has to be sent) - rr d -; decrease bit counter so we know when we have sent all 8 bits of current byte - dec e - jr nz, .nextBit0 - dec b - jr nz, .nextByte -; send bit 1 as a "stop bit" (end of parameter data) - ld a, $20 - ld [rJOYP], a -; set P14=HIGH,P15=HIGH - ld a, $30 - ld [rJOYP], a - xor a - ld [hDisableJoypadPolling], a -; wait for about 70000 cycles - call Wait7000 -; restore (previously pushed) number of packets - pop bc - dec b -; return if there are no more packets - ret z -; else send 16 more bytes - jr .loop2 - -LoadSGB: - xor a - ld [wOnSGB], a - call CheckSGB - ret nc - ld a, 1 - ld [wOnSGB], a - ld a, [wGBC] - and a - jr z, .notGBC - ret -.notGBC - di - call PrepareSuperNintendoVRAMTransfer - ei - ld a, 1 - ld [wCopyingSGBTileData], a - ld de, ChrTrnPacket - ld hl, SGBBorderGraphics - call CopyGfxToSuperNintendoVRAM - xor a - ld [wCopyingSGBTileData], a - ld de, PctTrnPacket - ld hl, BorderPalettes - call CopyGfxToSuperNintendoVRAM - xor a - ld [wCopyingSGBTileData], a - ld de, PalTrnPacket - ld hl, SuperPalettes - call CopyGfxToSuperNintendoVRAM - call ClearVram - ld hl, MaskEnCancelPacket - jp SendSGBPacket - -PrepareSuperNintendoVRAMTransfer: - ld hl, .packetPointers - ld c, 9 -.loop - push bc - ld a, [hli] - push hl - ld h, [hl] - ld l, a - call SendSGBPacket - pop hl - inc hl - pop bc - dec c - jr nz, .loop - ret - -.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 - -CheckSGB: -; Returns whether the game is running on an SGB in carry. - ld hl, MltReq2Packet - di - call SendSGBPacket - ld a, 1 - ld [hDisableJoypadPolling], a - ei - call Wait7000 - ld a, [rJOYP] - and $3 - cp $3 - jr nz, .isSGB - ld a, $20 - ld [rJOYP], a - ld a, [rJOYP] - ld a, [rJOYP] - call Wait7000 - call Wait7000 - ld a, $30 - ld [rJOYP], a - call Wait7000 - call Wait7000 - ld a, $10 - ld [rJOYP], a - ld a, [rJOYP] - ld a, [rJOYP] - ld a, [rJOYP] - ld a, [rJOYP] - ld a, [rJOYP] - ld a, [rJOYP] - call Wait7000 - call Wait7000 - ld a, $30 - ld [rJOYP], a - ld a, [rJOYP] - ld a, [rJOYP] - ld a, [rJOYP] - call Wait7000 - call Wait7000 - ld a, [rJOYP] - and $3 - cp $3 - jr nz, .isSGB - call SendMltReq1Packet - and a - ret -.isSGB - call SendMltReq1Packet - scf - ret - -SendMltReq1Packet: - ld hl, MltReq1Packet - call SendSGBPacket - jp Wait7000 - -CopyGfxToSuperNintendoVRAM: - di - push de - call DisableLCD - ld a, $e4 - ld [rBGP], a - ld de, vChars1 - ld a, [wCopyingSGBTileData] - and a - jr z, .notCopyingTileData - call CopySGBBorderTiles - jr .next -.notCopyingTileData - ld bc, $1000 - call CopyData -.next - ld hl, vBGMap0 - ld de, $c - ld a, $80 - ld c, $d -.loop - ld b, $14 -.innerLoop - ld [hli], a - inc a - dec b - jr nz, .innerLoop - add hl, de - dec c - jr nz, .loop - ld a, $e3 - ld [rLCDC], a - pop hl - call SendSGBPacket - xor a - ld [rBGP], a - ei - ret - -Wait7000: -; Each loop takes 9 cycles so this routine actually waits 63000 cycles. - ld de, 7000 -.loop - nop - nop - nop - dec de - ld a, d - or e - jr nz, .loop - ret - -SendSGBPackets: - ld a, [wGBC] - and a - jr z, .notGBC - push de - call InitGBCPalettes - pop hl - call EmptyFunc5 - ret -.notGBC - push de - call SendSGBPacket - pop hl - jp SendSGBPacket - -InitGBCPalettes: - ld a, $80 ; index 0 with auto-increment - ld [rBGPI], a - inc hl - ld c, $20 -.loop - ld a, [hli] - inc hl - add a - add a - add a - ld de, SuperPalettes - add e - jr nc, .noCarry - inc d -.noCarry - ld a, [de] - ld [rBGPD], a - dec c - jr nz, .loop - ret - -EmptyFunc5: - ret - -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 -; the second 16 bytes contain bit planes 3 and 4. -; 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 - ld a, [hli] - ld [de], a - inc de - dec c - jr nz, .copyLoop - -; Zero bit planes 3 and 4. - ld c, 16 - xor a -.zeroLoop - ld [de], a - inc de - dec c - jr nz, .zeroLoop - - dec b - jr nz, .tileLoop - ret - -INCLUDE "data/sgb_packets.asm" - -INCLUDE "data/mon_palettes.asm" - -INCLUDE "data/super_palettes.asm" - -INCLUDE "data/sgb_border.asm" diff --git a/engine/pathfinding.asm b/engine/pathfinding.asm deleted file mode 100644 index ba052d38..00000000 --- a/engine/pathfinding.asm +++ /dev/null @@ -1,201 +0,0 @@ -FindPathToPlayer: - xor a - ld hl, hFindPathNumSteps - ld [hli], a ; hFindPathNumSteps - ld [hli], a ; hFindPathFlags - ld [hli], a ; hFindPathYProgress - ld [hl], a ; hFindPathXProgress - ld hl, wNPCMovementDirections2 - ld de, $0 -.loop - ld a, [hFindPathYProgress] - ld b, a - ld a, [hNPCPlayerYDistance] ; Y distance in steps - call CalcDifference - ld d, a - and a - jr nz, .asm_f8da - ld a, [hFindPathFlags] - set 0, a ; current end of path matches the player's Y coordinate - ld [hFindPathFlags], a -.asm_f8da - ld a, [hFindPathXProgress] - ld b, a - ld a, [hNPCPlayerXDistance] ; X distance in steps - call CalcDifference - ld e, a - and a - jr nz, .asm_f8ec - ld a, [hFindPathFlags] - set 1, a ; current end of path matches the player's X coordinate - ld [hFindPathFlags], a -.asm_f8ec - ld a, [hFindPathFlags] - cp $3 ; has the end of the path reached the player's position? - jr z, .done -; Compare whether the X distance between the player and the current of the path -; is greater or if the Y distance is. Then, try to reduce whichever is greater. - ld a, e - cp d - jr c, .yDistanceGreater -; x distance is greater - ld a, [hNPCPlayerRelativePosFlags] - bit 1, a - jr nz, .playerIsLeftOfNPC - ld d, NPC_MOVEMENT_RIGHT - jr .next1 -.playerIsLeftOfNPC - ld d, NPC_MOVEMENT_LEFT -.next1 - ld a, [hFindPathXProgress] - add 1 - ld [hFindPathXProgress], a - jr .storeDirection -.yDistanceGreater - ld a, [hNPCPlayerRelativePosFlags] - bit 0, a - jr nz, .playerIsAboveNPC - ld d, NPC_MOVEMENT_DOWN - jr .next2 -.playerIsAboveNPC - ld d, NPC_MOVEMENT_UP -.next2 - ld a, [hFindPathYProgress] - add 1 - ld [hFindPathYProgress], a -.storeDirection - ld a, d - ld [hli], a - ld a, [hFindPathNumSteps] - inc a - ld [hFindPathNumSteps], a - jp .loop -.done - ld [hl], $ff - ret - -CalcPositionOfPlayerRelativeToNPC: - xor a - ld [hNPCPlayerRelativePosFlags], a - ld a, [wSpriteStateData1 + 4] ; player's sprite screen Y position in pixels - ld d, a - ld a, [wSpriteStateData1 + 6] ; player's sprite screen X position in pixels - ld e, a - ld hl, wSpriteStateData1 - ld a, [hNPCSpriteOffset] - add l - add $4 - ld l, a - jr nc, .noCarry - inc h -.noCarry - ld a, d - ld b, a - ld a, [hli] ; NPC sprite screen Y position in pixels - call CalcDifference - jr nc, .NPCSouthOfOrAlignedWithPlayer -.NPCNorthOfPlayer - push hl - ld hl, hNPCPlayerRelativePosFlags - bit 0, [hl] - set 0, [hl] - pop hl - jr .divideYDistance -.NPCSouthOfOrAlignedWithPlayer - push hl - ld hl, hNPCPlayerRelativePosFlags - bit 0, [hl] - res 0, [hl] - pop hl -.divideYDistance - push hl - ld hl, hDividend2 - ld [hli], a - ld a, 16 - ld [hli], a - call DivideBytes ; divide Y absolute distance by 16 - ld a, [hl] ; quotient - ld [hNPCPlayerYDistance], a - pop hl - inc hl - ld b, e - ld a, [hl] ; NPC sprite screen X position in pixels - call CalcDifference - jr nc, .NPCEastOfOrAlignedWithPlayer -.NPCWestOfPlayer - push hl - ld hl, hNPCPlayerRelativePosFlags - bit 1, [hl] - set 1, [hl] - pop hl - jr .divideXDistance -.NPCEastOfOrAlignedWithPlayer - push hl - ld hl, hNPCPlayerRelativePosFlags - bit 1, [hl] - res 1, [hl] - pop hl -.divideXDistance - ld [hDividend2], a - ld a, 16 - ld [hDivisor2], a - call DivideBytes ; divide X absolute distance by 16 - ld a, [hQuotient2] - ld [hNPCPlayerXDistance], a - ld a, [hNPCPlayerRelativePosPerspective] - and a - ret z - ld a, [hNPCPlayerRelativePosFlags] - cpl - and $3 - ld [hNPCPlayerRelativePosFlags], a - ret - -ConvertNPCMovementDirectionsToJoypadMasks: - ld a, [hNPCMovementDirections2Index] - ld [wNPCMovementDirections2Index], a - dec a - ld de, wSimulatedJoypadStatesEnd - ld hl, wNPCMovementDirections2 - add l - ld l, a - jr nc, .loop - inc h -.loop - ld a, [hld] - call ConvertNPCMovementDirectionToJoypadMask - ld [de], a - inc de - ld a, [hNPCMovementDirections2Index] - dec a - ld [hNPCMovementDirections2Index], a - jr nz, .loop - ret - -ConvertNPCMovementDirectionToJoypadMask: - push hl - ld b, a - ld hl, NPCMovementDirectionsToJoypadMasksTable -.loop - ld a, [hli] - cp $ff - jr z, .done - cp b - jr z, .loadJoypadMask - inc hl - jr .loop -.loadJoypadMask - ld a, [hl] -.done - pop hl - ret - -NPCMovementDirectionsToJoypadMasksTable: - db NPC_MOVEMENT_UP, D_UP - db NPC_MOVEMENT_DOWN, D_DOWN - db NPC_MOVEMENT_LEFT, D_LEFT - db NPC_MOVEMENT_RIGHT, D_RIGHT - db $ff - -; unreferenced - ret diff --git a/engine/pokedex_rating.asm b/engine/pokedex_rating.asm deleted file mode 100755 index f1aaf618..00000000 --- a/engine/pokedex_rating.asm +++ /dev/null @@ -1,154 +0,0 @@ -DisplayDexRating: - ld hl, wPokedexSeen - ld b, wPokedexSeenEnd - wPokedexSeen - call CountSetBits - ld a, [wNumSetBits] - ld [hDexRatingNumMonsSeen], a - ld hl, wPokedexOwned - ld b, wPokedexOwnedEnd - wPokedexOwned - call CountSetBits - ld a, [wNumSetBits] - ld [hDexRatingNumMonsOwned], a - ld hl, DexRatingsTable -.findRating - ld a, [hli] - ld b, a - ld a, [hDexRatingNumMonsOwned] - cp b - jr c, .foundRating - inc hl - inc hl - jr .findRating -.foundRating - ld a, [hli] - ld h, [hl] - ld l, a ; load text pointer into hl - CheckAndResetEventA EVENT_HALL_OF_FAME_DEX_RATING - jr nz, .hallOfFame - push hl - ld hl, PokedexRatingText_441cc - call PrintText - pop hl - call PrintText - callba PlayPokedexRatingSfx - jp WaitForTextScrollButtonPress -.hallOfFame - ld de, wDexRatingNumMonsSeen - ld a, [hDexRatingNumMonsSeen] - ld [de], a - inc de - ld a, [hDexRatingNumMonsOwned] - ld [de], a - inc de -.copyRatingTextLoop - ld a, [hli] - cp "@" - jr z, .doneCopying - ld [de], a - inc de - jr .copyRatingTextLoop -.doneCopying - ld [de], a - ret - -PokedexRatingText_441cc: - TX_FAR _OaksLabText_441cc - db "@" - -DexRatingsTable: - db 10 - dw PokedexRatingText_44201 - db 20 - dw PokedexRatingText_44206 - db 30 - dw PokedexRatingText_4420b - db 40 - dw PokedexRatingText_44210 - db 50 - dw PokedexRatingText_44215 - db 60 - dw PokedexRatingText_4421a - db 70 - dw PokedexRatingText_4421f - db 80 - dw PokedexRatingText_44224 - db 90 - dw PokedexRatingText_44229 - db 100 - dw PokedexRatingText_4422e - db 110 - dw PokedexRatingText_44233 - db 120 - dw PokedexRatingText_44238 - db 130 - dw PokedexRatingText_4423d - db 140 - dw PokedexRatingText_44242 - db 150 - dw PokedexRatingText_44247 - db NUM_POKEMON + 1 - dw PokedexRatingText_4424c - -PokedexRatingText_44201: - TX_FAR _OaksLabText_44201 - db "@" - -PokedexRatingText_44206: - TX_FAR _OaksLabText_44206 - db "@" - -PokedexRatingText_4420b: - TX_FAR _OaksLabText_4420b - db "@" - -PokedexRatingText_44210: - TX_FAR _OaksLabText_44210 - db "@" - -PokedexRatingText_44215: - TX_FAR _OaksLabText_44215 - db "@" - -PokedexRatingText_4421a: - TX_FAR _OaksLabText_4421a - db "@" - -PokedexRatingText_4421f: - TX_FAR _OaksLabText_4421f - db "@" - -PokedexRatingText_44224: - TX_FAR _OaksLabText_44224 - db "@" - -PokedexRatingText_44229: - TX_FAR _OaksLabText_44229 - db "@" - -PokedexRatingText_4422e: - TX_FAR _OaksLabText_4422e - db "@" - -PokedexRatingText_44233: - TX_FAR _OaksLabText_44233 - db "@" - -PokedexRatingText_44238: - TX_FAR _OaksLabText_44238 - db "@" - -PokedexRatingText_4423d: - TX_FAR _OaksLabText_4423d - db "@" - -PokedexRatingText_44242: - TX_FAR _OaksLabText_44242 - db "@" - -PokedexRatingText_44247: - TX_FAR _OaksLabText_44247 - db "@" - -PokedexRatingText_4424c: - TX_FAR _OaksLabText_4424c - db "@" diff --git a/engine/pokemon/add_mon.asm b/engine/pokemon/add_mon.asm new file mode 100644 index 00000000..7627136b --- /dev/null +++ b/engine/pokemon/add_mon.asm @@ -0,0 +1,516 @@ +_AddPartyMon:: +; Adds a new mon to the player's or enemy's party. +; [wMonDataLocation] is used in an unusual way in this function. +; If the lower nybble is 0, the mon is added to the player's party, else the enemy's. +; If the entire value is 0, then the player is allowed to name the mon. + ld de, wPartyCount + ld a, [wMonDataLocation] + and $f + jr z, .next + ld de, wEnemyPartyCount +.next + ld a, [de] + inc a + cp PARTY_LENGTH + 1 + ret nc ; return if the party is already full + ld [de], a + ld a, [de] + ld [hNewPartyLength], a + add e + ld e, a + jr nc, .noCarry + inc d +.noCarry + ld a, [wcf91] + ld [de], a ; write species of new mon in party list + inc de + ld a, $ff ; terminator + ld [de], a + ld hl, wPartyMonOT + ld a, [wMonDataLocation] + and $f + jr z, .next2 + ld hl, wEnemyMonOT +.next2 + ld a, [hNewPartyLength] + dec a + call SkipFixedLengthTextEntries + ld d, h + ld e, l + ld hl, wPlayerName + ld bc, NAME_LENGTH + call CopyData + ld a, [wMonDataLocation] + and a + jr nz, .skipNaming + ld hl, wPartyMonNicks + ld a, [hNewPartyLength] + dec a + call SkipFixedLengthTextEntries + ld a, NAME_MON_SCREEN + ld [wNamingScreenType], a + predef AskName +.skipNaming + ld hl, wPartyMons + ld a, [wMonDataLocation] + and $f + jr z, .next3 + ld hl, wEnemyMons +.next3 + ld a, [hNewPartyLength] + dec a + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld e, l + ld d, h + push hl + ld a, [wcf91] + ld [wd0b5], a + call GetMonHeader + ld hl, wMonHeader + ld a, [hli] + ld [de], a ; species + inc de + pop hl + push hl + ld a, [wMonDataLocation] + and $f + ld a, $98 ; set enemy trainer mon IVs to fixed average values + ld b, $88 + jr nz, .next4 + +; If the mon is being added to the player's party, update the pokedex. + ld a, [wcf91] + ld [wd11e], a + push de + predef IndexToPokedex + pop de + ld a, [wd11e] + dec a + ld c, a + ld b, FLAG_TEST + ld hl, wPokedexOwned + call FlagAction + ld a, c ; whether the mon was already flagged as owned + ld [wUnusedD153], a ; not read + ld a, [wd11e] + dec a + ld c, a + ld b, FLAG_SET + push bc + call FlagAction + pop bc + ld hl, wPokedexSeen + call FlagAction + + pop hl + push hl + + ld a, [wIsInBattle] + and a ; is this a wild mon caught in battle? + jr nz, .copyEnemyMonData + +; Not wild. + call Random ; generate random IVs + ld b, a + call Random + +.next4 + push bc + ld bc, wPartyMon1DVs - wPartyMon1 + add hl, bc + pop bc + ld [hli], a + ld [hl], b ; write IVs + ld bc, (wPartyMon1HPExp - 1) - (wPartyMon1DVs + 1) + add hl, bc + ld a, 1 + ld c, a + xor a + ld b, a + call CalcStat ; calc HP stat (set cur Hp to max HP) + ld a, [H_MULTIPLICAND+1] + ld [de], a + inc de + ld a, [H_MULTIPLICAND+2] + ld [de], a + inc de + xor a + ld [de], a ; box level + inc de + ld [de], a ; status ailments + inc de + jr .copyMonTypesAndMoves +.copyEnemyMonData + ld bc, wEnemyMon1DVs - wEnemyMon1 + add hl, bc + ld a, [wEnemyMonDVs] ; copy IVs from cur enemy mon + ld [hli], a + ld a, [wEnemyMonDVs + 1] + ld [hl], a + ld a, [wEnemyMonHP] ; copy HP from cur enemy mon + ld [de], a + inc de + ld a, [wEnemyMonHP+1] + ld [de], a + inc de + xor a + ld [de], a ; box level + inc de + ld a, [wEnemyMonStatus] ; copy status ailments from cur enemy mon + ld [de], a + inc de +.copyMonTypesAndMoves + ld hl, wMonHTypes + ld a, [hli] ; type 1 + ld [de], a + inc de + ld a, [hli] ; type 2 + ld [de], a + inc de + ld a, [hli] ; catch rate (held item in gen 2) + ld [de], a + ld hl, wMonHMoves + ld a, [hli] + inc de + push de + ld [de], a + ld a, [hli] + inc de + ld [de], a + ld a, [hli] + inc de + ld [de], a + ld a, [hli] + inc de + ld [de], a + push de + dec de + dec de + dec de + xor a + ld [wLearningMovesFromDayCare], a + predef WriteMonMoves + pop de + ld a, [wPlayerID] ; set trainer ID to player ID + inc de + ld [de], a + ld a, [wPlayerID + 1] + inc de + ld [de], a + push de + ld a, [wCurEnemyLVL] + ld d, a + callab CalcExperience + pop de + inc de + ld a, [hExperience] ; write experience + ld [de], a + inc de + ld a, [hExperience + 1] + ld [de], a + inc de + ld a, [hExperience + 2] + ld [de], a + xor a + ld b, NUM_STATS * 2 +.writeEVsLoop ; set all EVs to 0 + inc de + ld [de], a + dec b + jr nz, .writeEVsLoop + inc de + inc de + pop hl + call AddPartyMon_WriteMovePP + inc de + ld a, [wCurEnemyLVL] + ld [de], a + inc de + ld a, [wIsInBattle] + dec a + jr nz, .calcFreshStats + ld hl, wEnemyMonMaxHP + ld bc, $a + call CopyData ; copy stats of cur enemy mon + pop hl + jr .done +.calcFreshStats + pop hl + ld bc, wPartyMon1HPExp - 1 - wPartyMon1 + add hl, bc + ld b, $0 + call CalcStats ; calculate fresh set of stats +.done + scf + ret + +LoadMovePPs: + call GetPredefRegisters + ; fallthrough +AddPartyMon_WriteMovePP: + ld b, NUM_MOVES +.pploop + ld a, [hli] ; read move ID + and a + jr z, .empty + dec a + push hl + push de + push bc + ld hl, Moves + ld bc, MoveEnd - Moves + call AddNTimes + ld de, wcd6d + ld a, BANK(Moves) + call FarCopyData + pop bc + pop de + pop hl + ld a, [wcd6d + 5] ; PP is byte 5 of move data +.empty + inc de + ld [de], a + dec b + jr nz, .pploop ; there are still moves to read + ret + +; adds enemy mon [wcf91] (at position [wWhichPokemon] in enemy list) to own party +; used in the cable club trade center +_AddEnemyMonToPlayerParty:: + ld hl, wPartyCount + ld a, [hl] + cp PARTY_LENGTH + scf + ret z ; party full, return failure + inc a + ld [hl], a ; add 1 to party members + ld c, a + ld b, $0 + add hl, bc + ld a, [wcf91] + ld [hli], a ; add mon as last list entry + ld [hl], $ff ; write new sentinel + ld hl, wPartyMons + ld a, [wPartyCount] + dec a + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld e, l + ld d, h + ld hl, wLoadedMon + call CopyData ; write new mon's data (from wLoadedMon) + ld hl, wPartyMonOT + ld a, [wPartyCount] + dec a + call SkipFixedLengthTextEntries + ld d, h + ld e, l + ld hl, wEnemyMonOT + ld a, [wWhichPokemon] + call SkipFixedLengthTextEntries + ld bc, NAME_LENGTH + call CopyData ; write new mon's OT name (from an enemy mon) + ld hl, wPartyMonNicks + ld a, [wPartyCount] + dec a + call SkipFixedLengthTextEntries + ld d, h + ld e, l + ld hl, wEnemyMonNicks + ld a, [wWhichPokemon] + call SkipFixedLengthTextEntries + ld bc, NAME_LENGTH + call CopyData ; write new mon's nickname (from an enemy mon) + ld a, [wcf91] + ld [wd11e], a + predef IndexToPokedex + ld a, [wd11e] + dec a + ld c, a + ld b, FLAG_SET + ld hl, wPokedexOwned + push bc + call FlagAction ; add to owned pokemon + pop bc + ld hl, wPokedexSeen + call FlagAction ; add to seen pokemon + and a + ret ; return success + +_MoveMon:: + ld a, [wMoveMonType] + and a ; BOX_TO_PARTY + jr z, .checkPartyMonSlots + cp DAYCARE_TO_PARTY + jr z, .checkPartyMonSlots + cp PARTY_TO_DAYCARE + ld hl, wDayCareMon + jr z, .findMonDataSrc + ; else it's PARTY_TO_BOX + ld hl, wNumInBox + ld a, [hl] + cp MONS_PER_BOX + jr nz, .partyOrBoxNotFull + jr .boxFull +.checkPartyMonSlots + ld hl, wPartyCount + ld a, [hl] + cp PARTY_LENGTH + jr nz, .partyOrBoxNotFull +.boxFull + scf + ret +.partyOrBoxNotFull + inc a + ld [hl], a ; increment number of mons in party/box + ld c, a + ld b, 0 + add hl, bc + ld a, [wMoveMonType] + cp DAYCARE_TO_PARTY + ld a, [wDayCareMon] + jr z, .copySpecies + ld a, [wcf91] +.copySpecies + ld [hli], a ; write new mon ID + ld [hl], $ff ; write new sentinel +.findMonDataDest + ld a, [wMoveMonType] + dec a + ld hl, wPartyMons + ld bc, wPartyMon2 - wPartyMon1 ; $2c + ld a, [wPartyCount] + jr nz, .addMonOffset + ; if it's PARTY_TO_BOX + ld hl, wBoxMons + ld bc, wBoxMon2 - wBoxMon1 ; $21 + ld a, [wNumInBox] +.addMonOffset + dec a + call AddNTimes +.findMonDataSrc + push hl + ld e, l + ld d, h + ld a, [wMoveMonType] + and a + ld hl, wBoxMons + ld bc, wBoxMon2 - wBoxMon1 ; $21 + jr z, .addMonOffset2 + cp DAYCARE_TO_PARTY + ld hl, wDayCareMon + jr z, .copyMonData + ld hl, wPartyMons + ld bc, wPartyMon2 - wPartyMon1 ; $2c +.addMonOffset2 + ld a, [wWhichPokemon] + call AddNTimes +.copyMonData + push hl + push de + ld bc, wBoxMon2 - wBoxMon1 + call CopyData + pop de + pop hl + ld a, [wMoveMonType] + and a ; BOX_TO_PARTY + jr z, .findOTdest + cp DAYCARE_TO_PARTY + jr z, .findOTdest + ld bc, wBoxMon2 - wBoxMon1 + add hl, bc + ld a, [hl] ; hl = Level + inc de + inc de + inc de + ld [de], a ; de = BoxLevel +.findOTdest + ld a, [wMoveMonType] + cp PARTY_TO_DAYCARE + ld de, wDayCareMonOT + jr z, .findOTsrc + dec a + ld hl, wPartyMonOT + ld a, [wPartyCount] + jr nz, .addOToffset + ld hl, wBoxMonOT + ld a, [wNumInBox] +.addOToffset + dec a + call SkipFixedLengthTextEntries + ld d, h + ld e, l +.findOTsrc + ld hl, wBoxMonOT + ld a, [wMoveMonType] + and a + jr z, .addOToffset2 + ld hl, wDayCareMonOT + cp DAYCARE_TO_PARTY + jr z, .copyOT + ld hl, wPartyMonOT +.addOToffset2 + ld a, [wWhichPokemon] + call SkipFixedLengthTextEntries +.copyOT + ld bc, NAME_LENGTH + call CopyData + ld a, [wMoveMonType] +.findNickDest + cp PARTY_TO_DAYCARE + ld de, wDayCareMonName + jr z, .findNickSrc + dec a + ld hl, wPartyMonNicks + ld a, [wPartyCount] + jr nz, .addNickOffset + ld hl, wBoxMonNicks + ld a, [wNumInBox] +.addNickOffset + dec a + call SkipFixedLengthTextEntries + ld d, h + ld e, l +.findNickSrc + ld hl, wBoxMonNicks + ld a, [wMoveMonType] + and a + jr z, .addNickOffset2 + ld hl, wDayCareMonName + cp DAYCARE_TO_PARTY + jr z, .copyNick + ld hl, wPartyMonNicks +.addNickOffset2 + ld a, [wWhichPokemon] + call SkipFixedLengthTextEntries +.copyNick + ld bc, NAME_LENGTH + call CopyData + pop hl + ld a, [wMoveMonType] + cp PARTY_TO_BOX + jr z, .done + cp PARTY_TO_DAYCARE + jr z, .done + push hl + srl a + add $2 + ld [wMonDataLocation], a + call LoadMonData + callba CalcLevelFromExperience + ld a, d + ld [wCurEnemyLVL], a + pop hl + ld bc, wBoxMon2 - wBoxMon1 + add hl, bc + ld [hli], a + ld d, h + ld e, l + ld bc, -18 + add hl, bc + ld b, $1 + call CalcStats +.done + and a + ret diff --git a/engine/pokemon/bills_pc.asm b/engine/pokemon/bills_pc.asm new file mode 100644 index 00000000..e5855f1d --- /dev/null +++ b/engine/pokemon/bills_pc.asm @@ -0,0 +1,548 @@ +DisplayPCMainMenu:: + xor a + ld [H_AUTOBGTRANSFERENABLED], a + call SaveScreenTilesToBuffer2 + ld a, [wNumHoFTeams] + and a + jr nz, .leaguePCAvailable + CheckEvent EVENT_GOT_POKEDEX + jr z, .noOaksPC + ld a, [wNumHoFTeams] + and a + jr nz, .leaguePCAvailable + coord hl, 0, 0 + ld b, 8 + ld c, 14 + jr .next +.noOaksPC + coord hl, 0, 0 + ld b, 6 + ld c, 14 + jr .next +.leaguePCAvailable + coord hl, 0, 0 + ld b, 10 + ld c, 14 +.next + call TextBoxBorder + call UpdateSprites + ld a, 3 + ld [wMaxMenuItem], a + CheckEvent EVENT_MET_BILL + jr nz, .metBill + coord hl, 2, 2 + ld de, SomeonesPCText + jr .next2 +.metBill + coord hl, 2, 2 + ld de, BillsPCText +.next2 + call PlaceString + coord hl, 2, 4 + ld de, wPlayerName + call PlaceString + ld l, c + ld h, b + ld de, PlayersPCText + call PlaceString + CheckEvent EVENT_GOT_POKEDEX + jr z, .noOaksPC2 + coord hl, 2, 6 + ld de, OaksPCText + call PlaceString + ld a, [wNumHoFTeams] + and a + jr z, .noLeaguePC + ld a, 4 + ld [wMaxMenuItem], a + coord hl, 2, 8 + ld de, PKMNLeaguePCText + call PlaceString + coord hl, 2, 10 + ld de, LogOffPCText + jr .next3 +.noLeaguePC + coord hl, 2, 8 + ld de, LogOffPCText + jr .next3 +.noOaksPC2 + ld a, $2 + ld [wMaxMenuItem], a + coord hl, 2, 6 + ld de, LogOffPCText +.next3 + call PlaceString + ld a, A_BUTTON | B_BUTTON + ld [wMenuWatchedKeys], a + ld a, 2 + ld [wTopMenuItemY], a + ld a, 1 + ld [wTopMenuItemX], a + xor a + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + ld a, 1 + ld [H_AUTOBGTRANSFERENABLED], a + ret + +SomeonesPCText: db "SOMEONE's PC@" +BillsPCText: db "BILL's PC@" +PlayersPCText: db "'s PC@" +OaksPCText: db "PROF.OAK's PC@" +PKMNLeaguePCText: db "LEAGUE@" +LogOffPCText: db "LOG OFF@" + +BillsPC_:: + ld hl, wd730 + set 6, [hl] + xor a + ld [wParentMenuItem], a + inc a ; MONSTER_NAME + ld [wNameListType], a + call LoadHpBarAndStatusTilePatterns + ld a, [wListScrollOffset] + push af + ld a, [wFlags_0xcd60] + bit 3, a ; accessing Bill's PC through another PC? + jr nz, BillsPCMenu +; accessing it directly + ld a, SFX_TURN_ON_PC + call PlaySound + ld hl, SwitchOnText + call PrintText + +BillsPCMenu: + ld a, [wParentMenuItem] + ld [wCurrentMenuItem], a + ld hl, vChars2 + $780 + ld de, PokeballTileGraphics + lb bc, BANK(PokeballTileGraphics), $01 + call CopyVideoData + call LoadScreenTilesFromBuffer2DisableBGTransfer + coord hl, 0, 0 + ld b, 10 + ld c, 12 + call TextBoxBorder + coord hl, 2, 2 + ld de, BillsPCMenuText + call PlaceString + ld hl, wTopMenuItemY + ld a, 2 + ld [hli], a ; wTopMenuItemY + dec a + ld [hli], a ; wTopMenuItemX + inc hl + inc hl + ld a, 4 + ld [hli], a ; wMaxMenuItem + ld a, A_BUTTON | B_BUTTON + ld [hli], a ; wMenuWatchedKeys + xor a + ld [hli], a ; wLastMenuItem + ld [hli], a ; wPartyAndBillsPCSavedMenuItem + ld hl, wListScrollOffset + ld [hli], a ; wListScrollOffset + ld [hl], a ; wMenuWatchMovingOutOfBounds + ld [wPlayerMonNumber], a + ld hl, WhatText + call PrintText + coord hl, 9, 14 + ld b, 2 + ld c, 9 + call TextBoxBorder + ld a, [wCurrentBoxNum] + and $7f + cp 9 + jr c, .singleDigitBoxNum +; two digit box num + sub 9 + coord hl, 17, 16 + ld [hl], "1" + add "0" + jr .next +.singleDigitBoxNum + add "1" +.next + Coorda 18, 16 + coord hl, 10, 16 + ld de, BoxNoPCText + call PlaceString + ld a, 1 + ld [H_AUTOBGTRANSFERENABLED], a + call Delay3 + call HandleMenuInput + bit 1, a + jp nz, ExitBillsPC ; b button + call PlaceUnfilledArrowMenuCursor + ld a, [wCurrentMenuItem] + ld [wParentMenuItem], a + and a + jp z, BillsPCWithdraw ; withdraw + cp $1 + jp z, BillsPCDeposit ; deposit + cp $2 + jp z, BillsPCRelease ; release + cp $3 + jp z, BillsPCChangeBox ; change box + +ExitBillsPC: + ld a, [wFlags_0xcd60] + bit 3, a ; accessing Bill's PC through another PC? + jr nz, .next +; accessing it directly + call LoadTextBoxTilePatterns + ld a, SFX_TURN_OFF_PC + call PlaySound + call WaitForSoundToFinish +.next + ld hl, wFlags_0xcd60 + res 5, [hl] + call LoadScreenTilesFromBuffer2 + pop af + ld [wListScrollOffset], a + ld hl, wd730 + res 6, [hl] + ret + +BillsPCDeposit: + ld a, [wPartyCount] + dec a + jr nz, .partyLargeEnough + ld hl, CantDepositLastMonText + call PrintText + jp BillsPCMenu +.partyLargeEnough + ld a, [wNumInBox] + cp MONS_PER_BOX + jr nz, .boxNotFull + ld hl, BoxFullText + call PrintText + jp BillsPCMenu +.boxNotFull + ld hl, wPartyCount + call DisplayMonListMenu + jp c, BillsPCMenu + call DisplayDepositWithdrawMenu + jp nc, BillsPCMenu + ld a, [wcf91] + call GetCryData + call PlaySoundWaitForCurrent + ld a, PARTY_TO_BOX + ld [wMoveMonType], a + call MoveMon + xor a + ld [wRemoveMonFromBox], a + call RemovePokemon + call WaitForSoundToFinish + ld hl, wBoxNumString + ld a, [wCurrentBoxNum] + and $7f + cp 9 + jr c, .singleDigitBoxNum + sub 9 + ld [hl], "1" + inc hl + add "0" + jr .next +.singleDigitBoxNum + add "1" +.next + ld [hli], a + ld [hl], "@" + ld hl, MonWasStoredText + call PrintText + jp BillsPCMenu + +BillsPCWithdraw: + ld a, [wNumInBox] + and a + jr nz, .boxNotEmpty + ld hl, NoMonText + call PrintText + jp BillsPCMenu +.boxNotEmpty + ld a, [wPartyCount] + cp PARTY_LENGTH + jr nz, .partyNotFull + ld hl, CantTakeMonText + call PrintText + jp BillsPCMenu +.partyNotFull + ld hl, wNumInBox + call DisplayMonListMenu + jp c, BillsPCMenu + call DisplayDepositWithdrawMenu + jp nc, BillsPCMenu + ld a, [wWhichPokemon] + ld hl, wBoxMonNicks + call GetPartyMonName + ld a, [wcf91] + call GetCryData + call PlaySoundWaitForCurrent + xor a ; BOX_TO_PARTY + ld [wMoveMonType], a + call MoveMon + ld a, 1 + ld [wRemoveMonFromBox], a + call RemovePokemon + call WaitForSoundToFinish + ld hl, MonIsTakenOutText + call PrintText + jp BillsPCMenu + +BillsPCRelease: + ld a, [wNumInBox] + and a + jr nz, .loop + ld hl, NoMonText + call PrintText + jp BillsPCMenu +.loop + ld hl, wNumInBox + call DisplayMonListMenu + jp c, BillsPCMenu + ld hl, OnceReleasedText + call PrintText + call YesNoChoice + ld a, [wCurrentMenuItem] + and a + jr nz, .loop + inc a + ld [wRemoveMonFromBox], a + call RemovePokemon + call WaitForSoundToFinish + ld a, [wcf91] + call PlayCry + ld hl, MonWasReleasedText + call PrintText + jp BillsPCMenu + +BillsPCChangeBox: + callba ChangeBox + jp BillsPCMenu + +DisplayMonListMenu: + ld a, l + ld [wListPointer], a + ld a, h + ld [wListPointer + 1], a + xor a + ld [wPrintItemPrices], a + ld [wListMenuID], a + inc a ; MONSTER_NAME + ld [wNameListType], a + ld a, [wPartyAndBillsPCSavedMenuItem] + ld [wCurrentMenuItem], a + call DisplayListMenuID + ld a, [wCurrentMenuItem] + ld [wPartyAndBillsPCSavedMenuItem], a + ret + +BillsPCMenuText: + db "WITHDRAW " + next "DEPOSIT " + next "RELEASE " + next "CHANGE BOX" + next "SEE YA!" + db "@" + +BoxNoPCText: + db "BOX No.@" + +KnowsHMMove:: +; returns whether mon with party index [wWhichPokemon] knows an HM move + ld hl, wPartyMon1Moves + ld bc, wPartyMon2 - wPartyMon1 + jr .next +; unreachable + ld hl, wBoxMon1Moves + ld bc, wBoxMon2 - wBoxMon1 +.next + ld a, [wWhichPokemon] + call AddNTimes + ld b, NUM_MOVES +.loop + ld a, [hli] + push hl + push bc + ld hl, HMMoveArray + ld de, 1 + call IsInArray + pop bc + pop hl + ret c + dec b + jr nz, .loop + and a + ret + +INCLUDE "data/hm_moves.asm" + +DisplayDepositWithdrawMenu: + coord hl, 9, 10 + ld b, 6 + ld c, 9 + call TextBoxBorder + ld a, [wParentMenuItem] + and a ; was the Deposit or Withdraw item selected in the parent menu? + ld de, DepositPCText + jr nz, .next + ld de, WithdrawPCText +.next + coord hl, 11, 12 + call PlaceString + coord hl, 11, 14 + ld de, StatsCancelPCText + call PlaceString + ld hl, wTopMenuItemY + ld a, 12 + ld [hli], a ; wTopMenuItemY + ld a, 10 + ld [hli], a ; wTopMenuItemX + xor a + ld [hli], a ; wCurrentMenuItem + inc hl + ld a, 2 + ld [hli], a ; wMaxMenuItem + ld a, A_BUTTON | B_BUTTON + ld [hli], a ; wMenuWatchedKeys + xor a + ld [hl], a ; wLastMenuItem + ld hl, wListScrollOffset + ld [hli], a ; wListScrollOffset + ld [hl], a ; wMenuWatchMovingOutOfBounds + ld [wPlayerMonNumber], a + ld [wPartyAndBillsPCSavedMenuItem], a +.loop + call HandleMenuInput + bit 1, a ; pressed B? + jr nz, .exit + ld a, [wCurrentMenuItem] + and a + jr z, .choseDepositWithdraw + dec a + jr z, .viewStats +.exit + and a + ret +.choseDepositWithdraw + scf + ret +.viewStats + call SaveScreenTilesToBuffer1 + ld a, [wParentMenuItem] + and a + ld a, PLAYER_PARTY_DATA + jr nz, .next2 + ld a, BOX_DATA +.next2 + ld [wMonDataLocation], a + predef StatusScreen + predef StatusScreen2 + call LoadScreenTilesFromBuffer1 + call ReloadTilesetTilePatterns + call RunDefaultPaletteCommand + call LoadGBPal + jr .loop + +DepositPCText: db "DEPOSIT@" +WithdrawPCText: db "WITHDRAW@" +StatsCancelPCText: + db "STATS" + next "CANCEL@" + +SwitchOnText: + TX_FAR _SwitchOnText + db "@" + +WhatText: + TX_FAR _WhatText + db "@" + +DepositWhichMonText: + TX_FAR _DepositWhichMonText + db "@" + +MonWasStoredText: + TX_FAR _MonWasStoredText + db "@" + +CantDepositLastMonText: + TX_FAR _CantDepositLastMonText + db "@" + +BoxFullText: + TX_FAR _BoxFullText + db "@" + +MonIsTakenOutText: + TX_FAR _MonIsTakenOutText + db "@" + +NoMonText: + TX_FAR _NoMonText + db "@" + +CantTakeMonText: + TX_FAR _CantTakeMonText + db "@" + +ReleaseWhichMonText: + TX_FAR _ReleaseWhichMonText + db "@" + +OnceReleasedText: + TX_FAR _OnceReleasedText + db "@" + +MonWasReleasedText: + TX_FAR _MonWasReleasedText + db "@" + +CableClubLeftGameboy:: + ld a, [hSerialConnectionStatus] + cp USING_EXTERNAL_CLOCK + ret z + ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction + cp SPRITE_FACING_RIGHT + ret nz + ld a, [wCurMap] + cp TRADE_CENTER + ld a, LINK_STATE_START_TRADE + jr z, .next + inc a ; LINK_STATE_START_BATTLE +.next + ld [wLinkState], a + call EnableAutoTextBoxDrawing + tx_pre_jump JustAMomentText + +CableClubRightGameboy:: + ld a, [hSerialConnectionStatus] + cp USING_INTERNAL_CLOCK + ret z + ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction + cp SPRITE_FACING_LEFT + ret nz + ld a, [wCurMap] + cp TRADE_CENTER + ld a, LINK_STATE_START_TRADE + jr z, .next + inc a ; LINK_STATE_START_BATTLE +.next + ld [wLinkState], a + call EnableAutoTextBoxDrawing + tx_pre_jump JustAMomentText + +JustAMomentText:: + TX_FAR _JustAMomentText + db "@" + + ld a, [wSpriteStateData1 + 9] ; player's sprite facing direction + cp SPRITE_FACING_UP + ret nz + call EnableAutoTextBoxDrawing + tx_pre_jump OpenBillsPCText + +OpenBillsPCText:: + TX_BILLS_PC + diff --git a/engine/pokemon/evos_moves.asm b/engine/pokemon/evos_moves.asm new file mode 100755 index 00000000..f50f8081 --- /dev/null +++ b/engine/pokemon/evos_moves.asm @@ -0,0 +1,513 @@ +; try to evolve the mon in [wWhichPokemon] +TryEvolvingMon: + ld hl, wCanEvolveFlags + xor a + ld [hl], a + ld a, [wWhichPokemon] + ld c, a + ld b, FLAG_SET + call Evolution_FlagAction + +; this is only called after battle +; it is supposed to do level up evolutions, though there is a bug that allows item evolutions to occur +EvolutionAfterBattle: + ld a, [hTilesetType] + push af + xor a + ld [wEvolutionOccurred], a + dec a + ld [wWhichPokemon], a + push hl + push bc + push de + ld hl, wPartyCount + push hl + +Evolution_PartyMonLoop: ; loop over party mons + ld hl, wWhichPokemon + inc [hl] + pop hl + inc hl + ld a, [hl] + cp $ff ; have we reached the end of the party? + jp z, .done + ld [wEvoOldSpecies], a + push hl + ld a, [wWhichPokemon] + ld c, a + ld hl, wCanEvolveFlags + ld b, FLAG_TEST + call Evolution_FlagAction + ld a, c + and a ; is the mon's bit set? + jp z, Evolution_PartyMonLoop ; if not, go to the next mon + ld a, [wEvoOldSpecies] + dec a + ld b, 0 + ld hl, EvosMovesPointerTable + add a + rl b + ld c, a + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + push hl + ld a, [wcf91] + push af + xor a ; PLAYER_PARTY_DATA + ld [wMonDataLocation], a + call LoadMonData + pop af + ld [wcf91], a + pop hl + +.evoEntryLoop ; loop over evolution entries + ld a, [hli] + and a ; have we reached the end of the evolution data? + jr z, Evolution_PartyMonLoop + ld b, a ; evolution type + cp EV_TRADE + jr z, .checkTradeEvo +; not trade evolution + ld a, [wLinkState] + cp LINK_STATE_TRADING + jr z, Evolution_PartyMonLoop ; if trading, go the next mon + ld a, b + cp EV_ITEM + jr z, .checkItemEvo + ld a, [wForceEvolution] + and a + jr nz, Evolution_PartyMonLoop + ld a, b + cp EV_LEVEL + jr z, .checkLevel +.checkTradeEvo + ld a, [wLinkState] + cp LINK_STATE_TRADING + jp nz, .nextEvoEntry1 ; if not trading, go to the next evolution entry + ld a, [hli] ; level requirement + ld b, a + ld a, [wLoadedMonLevel] + cp b ; is the mon's level greater than the evolution requirement? + jp c, Evolution_PartyMonLoop ; if so, go the next mon + jr .doEvolution +.checkItemEvo + ld a, [hli] + 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 + cp b ; was the evolution item in this entry used? + jp nz, .nextEvoEntry1 ; if not, go to the next evolution entry +.checkLevel + ld a, [hli] ; level requirement + ld b, a + ld a, [wLoadedMonLevel] + cp b ; is the mon's level greater than the evolution requirement? + jp c, .nextEvoEntry2 ; if so, go the next evolution entry +.doEvolution + ld [wCurEnemyLVL], a + ld a, 1 + ld [wEvolutionOccurred], a + push hl + ld a, [hl] + ld [wEvoNewSpecies], a + ld a, [wWhichPokemon] + ld hl, wPartyMonNicks + call GetPartyMonName + call CopyStringToCF4B + ld hl, IsEvolvingText + call PrintText + ld c, 50 + call DelayFrames + xor a + ld [H_AUTOBGTRANSFERENABLED], a + coord hl, 0, 0 + lb bc, 12, 20 + call ClearScreenArea + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + ld a, $ff + ld [wUpdateSpritesEnabled], a + call ClearSprites + callab EvolveMon + jp c, CancelledEvolution + ld hl, EvolvedText + call PrintText + pop hl + ld a, [hl] + ld [wd0b5], a + ld [wLoadedMonSpecies], a + ld [wEvoNewSpecies], a + ld a, MONSTER_NAME + ld [wNameListType], a + ld a, BANK(TrainerNames) ; bank is not used for monster names + ld [wPredefBank], a + call GetName + push hl + ld hl, IntoText + call PrintText_NoCreatingTextBox + ld a, SFX_GET_ITEM_2 + call PlaySoundWaitForCurrent + call WaitForSoundToFinish + ld c, 40 + call DelayFrames + call ClearScreen + call RenameEvolvedMon + ld a, [wd11e] + push af + ld a, [wd0b5] + ld [wd11e], a + predef IndexToPokedex + ld a, [wd11e] + dec a + ld hl, BaseStats + ld bc, MonBaseStatsEnd - MonBaseStats + call AddNTimes + ld de, wMonHeader + call CopyData + ld a, [wd0b5] + ld [wMonHIndex], a + pop af + ld [wd11e], a + ld hl, wLoadedMonHPExp - 1 + ld de, wLoadedMonStats + ld b, $1 + call CalcStats + ld a, [wWhichPokemon] + ld hl, wPartyMon1 + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes + ld e, l + ld d, h + push hl + push bc + ld bc, wPartyMon1MaxHP - wPartyMon1 + add hl, bc + ld a, [hli] + ld b, a + ld c, [hl] + ld hl, wLoadedMonMaxHP + 1 + ld a, [hld] + sub c + ld c, a + ld a, [hl] + sbc b + ld b, a + ld hl, wLoadedMonHP + 1 + ld a, [hl] + add c + ld [hld], a + ld a, [hl] + adc b + ld [hl], a + dec hl + pop bc + call CopyData + ld a, [wd0b5] + ld [wd11e], a + xor a + ld [wMonDataLocation], a + call LearnMoveFromLevelUp + pop hl + predef SetPartyMonTypes + ld a, [wIsInBattle] + and a + call z, Evolution_ReloadTilesetTilePatterns + predef IndexToPokedex + ld a, [wd11e] + dec a + ld c, a + ld b, FLAG_SET + ld hl, wPokedexOwned + push bc + call Evolution_FlagAction + pop bc + ld hl, wPokedexSeen + call Evolution_FlagAction + pop de + pop hl + ld a, [wLoadedMonSpecies] + ld [hl], a + push hl + ld l, e + ld h, d + jr .nextEvoEntry2 + +.nextEvoEntry1 + inc hl + +.nextEvoEntry2 + inc hl + jp .evoEntryLoop + +.done + pop de + pop bc + pop hl + pop af + ld [hTilesetType], a + ld a, [wLinkState] + cp LINK_STATE_TRADING + ret z + ld a, [wIsInBattle] + and a + ret nz + ld a, [wEvolutionOccurred] + and a + call nz, PlayDefaultMusic + ret + +RenameEvolvedMon: +; Renames the mon to its new, evolved form's standard name unless it had a +; nickname, in which case the nickname is kept. + ld a, [wd0b5] + push af + ld a, [wMonHIndex] + ld [wd0b5], a + call GetName + pop af + ld [wd0b5], a + ld hl, wcd6d + ld de, wcf4b +.compareNamesLoop + ld a, [de] + inc de + cp [hl] + inc hl + ret nz + cp "@" + jr nz, .compareNamesLoop + ld a, [wWhichPokemon] + ld bc, NAME_LENGTH + ld hl, wPartyMonNicks + call AddNTimes + push hl + call GetName + ld hl, wcd6d + pop de + jp CopyData + +CancelledEvolution: + ld hl, StoppedEvolvingText + call PrintText + call ClearScreen + pop hl + call Evolution_ReloadTilesetTilePatterns + jp Evolution_PartyMonLoop + +EvolvedText: + TX_FAR _EvolvedText + db "@" + +IntoText: + TX_FAR _IntoText + db "@" + +StoppedEvolvingText: + TX_FAR _StoppedEvolvingText + db "@" + +IsEvolvingText: + TX_FAR _IsEvolvingText + db "@" + +Evolution_ReloadTilesetTilePatterns: + ld a, [wLinkState] + cp LINK_STATE_TRADING + ret z + 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 +.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? + jr z, .done ; if we've reached the end of the learn set, jump + ld b, a ; level the move is learnt at + ld a, [wCurEnemyLVL] + cp b ; is the move learnt at the mon's current level? + ld a, [hli] ; move ID + jr nz, .learnSetLoop + ld d, a ; ID of move to learn + ld a, [wMonDataLocation] + and a + jr nz, .next +; If [wMonDataLocation] is 0 (PLAYER_PARTY_DATA), get the address of the mon's +; current moves in party data. Every call to this function sets +; [wMonDataLocation] to 0 because other data locations are not supported. +; If it is not 0, this function will not work properly. + ld hl, wPartyMon1Moves + ld a, [wWhichPokemon] + ld bc, wPartyMon2 - wPartyMon1 + call AddNTimes +.next + ld b, NUM_MOVES +.checkCurrentMovesLoop ; check if the move to learn is already known + ld a, [hli] + cp d + jr z, .done ; if already known, jump + dec b + jr nz, .checkCurrentMovesLoop + ld a, d + ld [wMoveNum], a + ld [wd11e], a + call GetMoveName + call CopyStringToCF4B + predef LearnMove +.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 + ld hl, EvosMovesPointerTable + ld b, 0 + ld a, [wcf91] ; cur mon ID + dec a + add a + rl b + ld c, a + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a +.skipEvoEntriesLoop + ld a, [hli] + and a + jr nz, .skipEvoEntriesLoop + jr .firstMove +.nextMove + pop de +.nextMove2 + inc hl +.firstMove + ld a, [hli] ; read level of next move in learnset + and a + jp z, .done ; end of list + ld b, a + ld a, [wCurEnemyLVL] + cp b + jp c, .done ; mon level < move level (assumption: learnset is sorted by level) + ld a, [wLearningMovesFromDayCare] + and a + jr z, .skipMinLevelCheck + ld a, [wDayCareStartLevel] + cp b + jr nc, .nextMove2 ; min level >= move level + +.skipMinLevelCheck + +; check if the move is already known + push de + ld c, NUM_MOVES +.alreadyKnowsCheckLoop + ld a, [de] + inc de + cp [hl] + jr z, .nextMove + dec c + jr nz, .alreadyKnowsCheckLoop + +; try to find an empty move slot + pop de + push de + ld c, NUM_MOVES +.findEmptySlotLoop + ld a, [de] + and a + jr z, .writeMoveToSlot2 + inc de + dec c + jr nz, .findEmptySlotLoop + +; no empty move slots found + pop de + push de + push hl + ld h, d + ld l, e + call WriteMonMoves_ShiftMoveData ; shift all moves one up (deleting move 1) + ld a, [wLearningMovesFromDayCare] + and a + jr z, .writeMoveToSlot + +; shift PP as well if learning moves from day care + push de + ld bc, wPartyMon1PP - (wPartyMon1Moves + 3) + add hl, bc + ld d, h + ld e, l + call WriteMonMoves_ShiftMoveData ; shift all move PP data one up + pop de + +.writeMoveToSlot + pop hl +.writeMoveToSlot2 + ld a, [hl] + ld [de], a + ld a, [wLearningMovesFromDayCare] + and a + jr z, .nextMove + +; write move PP value if learning moves from day care + push hl + ld a, [hl] + ld hl, wPartyMon1PP - wPartyMon1Moves + add hl, de + push hl + dec a + ld hl, Moves + ld bc, MoveEnd - Moves + call AddNTimes + ld de, wBuffer + ld a, BANK(Moves) + call FarCopyData + ld a, [wBuffer + 5] + pop hl + ld [hl], a + pop hl + jr .nextMove + +.done + pop bc + pop de + pop hl + ret + +; shifts all move data one up (freeing 4th move slot) +WriteMonMoves_ShiftMoveData: + ld c, NUM_MOVES - 1 +.loop + inc de + ld a, [de] + ld [hli], a + dec c + jr nz, .loop + ret + +Evolution_FlagAction: + predef_jump FlagActionPredef + +INCLUDE "data/evos_moves.asm" diff --git a/engine/pokemon/experience.asm b/engine/pokemon/experience.asm new file mode 100755 index 00000000..3ee4b2a8 --- /dev/null +++ b/engine/pokemon/experience.asm @@ -0,0 +1,149 @@ +; calculates the level a mon should be based on its current exp +CalcLevelFromExperience:: + ld a, [wLoadedMonSpecies] + ld [wd0b5], a + call GetMonHeader + ld d, $1 ; init level to 1 +.loop + inc d ; increment level + call CalcExperience + push hl + ld hl, wLoadedMonExp + 2 ; current exp +; compare exp needed for level d with current exp + ld a, [hExperience + 2] + ld c, a + ld a, [hld] + sub c + ld a, [hExperience + 1] + ld c, a + ld a, [hld] + sbc c + ld a, [hExperience] + ld c, a + ld a, [hl] + sbc c + pop hl + jr nc, .loop ; if exp needed for level d is not greater than exp, try the next level + dec d ; since the exp was too high on the last loop iteration, go back to the previous value and return + ret + +; calculates the amount of experience needed for level d +CalcExperience:: + ld a, [wMonHGrowthRate] + add a + add a + ld c, a + ld b, 0 + ld hl, GrowthRateTable + add hl, bc + call CalcDSquared + ld a, d + ld [H_MULTIPLIER], a + call Multiply + ld a, [hl] + and $f0 + swap a + ld [H_MULTIPLIER], a + call Multiply + ld a, [hli] + and $f + ld [H_DIVISOR], a + ld b, $4 + call Divide + ld a, [H_QUOTIENT + 1] + push af + ld a, [H_QUOTIENT + 2] + push af + ld a, [H_QUOTIENT + 3] + push af + call CalcDSquared + ld a, [hl] + and $7f + ld [H_MULTIPLIER], a + call Multiply + ld a, [H_PRODUCT + 1] + push af + ld a, [H_PRODUCT + 2] + push af + ld a, [H_PRODUCT + 3] + push af + ld a, [hli] + push af + xor a + ld [H_MULTIPLICAND], a + ld [H_MULTIPLICAND + 1], a + ld a, d + ld [H_MULTIPLICAND + 2], a + ld a, [hli] + ld [H_MULTIPLIER], a + call Multiply + ld b, [hl] + ld a, [H_PRODUCT + 3] + sub b + ld [H_PRODUCT + 3], a + ld b, $0 + ld a, [H_PRODUCT + 2] + sbc b + ld [H_PRODUCT + 2], a + ld a, [H_PRODUCT + 1] + sbc b + ld [H_PRODUCT + 1], a +; The difference of the linear term and the constant term consists of 3 bytes +; starting at H_PRODUCT + 1. Below, hExperience (an alias of that address) will +; be used instead for the further work of adding or subtracting the squared +; term and adding the cubed term. + pop af + and $80 + jr nz, .subtractSquaredTerm ; check sign + pop bc + ld a, [hExperience + 2] + add b + ld [hExperience + 2], a + pop bc + ld a, [hExperience + 1] + adc b + ld [hExperience + 1], a + pop bc + ld a, [hExperience] + adc b + ld [hExperience], a + jr .addCubedTerm +.subtractSquaredTerm + pop bc + ld a, [hExperience + 2] + sub b + ld [hExperience + 2], a + pop bc + ld a, [hExperience + 1] + sbc b + ld [hExperience + 1], a + pop bc + ld a, [hExperience] + sbc b + ld [hExperience], a +.addCubedTerm + pop bc + ld a, [hExperience + 2] + add b + ld [hExperience + 2], a + pop bc + ld a, [hExperience + 1] + adc b + ld [hExperience + 1], a + pop bc + ld a, [hExperience] + adc b + ld [hExperience], a + ret + +; calculates d*d +CalcDSquared: + xor a + ld [H_MULTIPLICAND], a + ld [H_MULTIPLICAND + 1], a + ld a, d + ld [H_MULTIPLICAND + 2], a + ld [H_MULTIPLIER], a + jp Multiply + +INCLUDE "data/growth_rates.asm" diff --git a/engine/pokemon/learn_move.asm b/engine/pokemon/learn_move.asm new file mode 100755 index 00000000..53c7f87e --- /dev/null +++ b/engine/pokemon/learn_move.asm @@ -0,0 +1,226 @@ +LearnMove: + call SaveScreenTilesToBuffer1 + ld a, [wWhichPokemon] + ld hl, wPartyMonNicks + call GetPartyMonName + ld hl, wcd6d + ld de, wLearnMoveMonName + ld bc, NAME_LENGTH + call CopyData + +DontAbandonLearning: + ld hl, wPartyMon1Moves + ld bc, wPartyMon2Moves - wPartyMon1Moves + ld a, [wWhichPokemon] + call AddNTimes + ld d, h + ld e, l + ld b, NUM_MOVES +.findEmptyMoveSlotLoop + ld a, [hl] + and a + jr z, .next + inc hl + dec b + jr nz, .findEmptyMoveSlotLoop + push de + call TryingToLearn + pop de + jp c, AbandonLearning + push hl + push de + ld [wd11e], a + call GetMoveName + ld hl, OneTwoAndText + call PrintText + pop de + pop hl +.next + ld a, [wMoveNum] + ld [hl], a + ld bc, wPartyMon1PP - wPartyMon1Moves + add hl, bc + push hl + push de + dec a + ld hl, Moves + ld bc, MoveEnd - Moves + call AddNTimes + ld de, wBuffer + ld a, BANK(Moves) + call FarCopyData + ld a, [wBuffer + 5] ; a = move's max PP + pop de + pop hl + ld [hl], a + ld a, [wIsInBattle] + and a + jp z, PrintLearnedMove + ld a, [wWhichPokemon] + ld b, a + ld a, [wPlayerMonNumber] + cp b + jp nz, PrintLearnedMove + ld h, d + ld l, e + ld de, wBattleMonMoves + ld bc, NUM_MOVES + call CopyData + ld bc, wPartyMon1PP - wPartyMon1OTID + add hl, bc + ld de, wBattleMonPP + ld bc, NUM_MOVES + call CopyData + jp PrintLearnedMove + +AbandonLearning: + ld hl, AbandonLearningText + call PrintText + coord hl, 14, 7 + lb bc, 8, 15 + ld a, TWO_OPTION_MENU + ld [wTextBoxID], a + call DisplayTextBoxID ; yes/no menu + ld a, [wCurrentMenuItem] + and a + jp nz, DontAbandonLearning + ld hl, DidNotLearnText + call PrintText + ld b, 0 + ret + +PrintLearnedMove: + ld hl, LearnedMove1Text + call PrintText + ld b, 1 + ret + +TryingToLearn: + push hl + ld hl, TryingToLearnText + call PrintText + coord hl, 14, 7 + lb bc, 8, 15 + ld a, TWO_OPTION_MENU + ld [wTextBoxID], a + call DisplayTextBoxID ; yes/no menu + pop hl + ld a, [wCurrentMenuItem] + rra + ret c + ld bc, -NUM_MOVES + add hl, bc + push hl + ld de, wMoves + ld bc, NUM_MOVES + call CopyData + callab FormatMovesString + pop hl +.loop + push hl + ld hl, WhichMoveToForgetText + call PrintText + coord hl, 4, 7 + ld b, 4 + ld c, 14 + call TextBoxBorder + coord hl, 6, 8 + ld de, wMovesString + ld a, [hFlags_0xFFF6] + set 2, a + ld [hFlags_0xFFF6], a + call PlaceString + ld a, [hFlags_0xFFF6] + res 2, a + ld [hFlags_0xFFF6], a + ld hl, wTopMenuItemY + ld a, 8 + ld [hli], a ; wTopMenuItemY + ld a, 5 + ld [hli], a ; wTopMenuItemX + xor a + ld [hli], a ; wCurrentMenuItem + inc hl + ld a, [wNumMovesMinusOne] + ld [hli], a ; wMaxMenuItem + ld a, A_BUTTON | B_BUTTON + ld [hli], a ; wMenuWatchedKeys + ld [hl], 0 ; wLastMenuItem + ld hl, hFlags_0xFFF6 + set 1, [hl] + call HandleMenuInput + ld hl, hFlags_0xFFF6 + res 1, [hl] + push af + call LoadScreenTilesFromBuffer1 + pop af + pop hl + bit 1, a ; pressed b + jr nz, .cancel + push hl + ld a, [wCurrentMenuItem] + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + push af + push bc + call IsMoveHM + pop bc + pop de + ld a, d + jr c, .hm + pop hl + add hl, bc + and a + ret +.hm + ld hl, HMCantDeleteText + call PrintText + pop hl + jr .loop +.cancel + scf + ret + +LearnedMove1Text: + TX_FAR _LearnedMove1Text + TX_SFX_ITEM_1 ; plays SFX_GET_ITEM_1 in the party menu (rare candy) and plays SFX_LEVEL_UP in battle + TX_BLINK + db "@" + +WhichMoveToForgetText: + TX_FAR _WhichMoveToForgetText + db "@" + +AbandonLearningText: + TX_FAR _AbandonLearningText + db "@" + +DidNotLearnText: + TX_FAR _DidNotLearnText + db "@" + +TryingToLearnText: + TX_FAR _TryingToLearnText + db "@" + +OneTwoAndText: + TX_FAR _OneTwoAndText + TX_DELAY + TX_ASM + ld a, SFX_SWAP + call PlaySoundWaitForCurrent + ld hl, PoofText + ret + +PoofText: + TX_FAR _PoofText + TX_DELAY +ForgotAndText: + TX_FAR _ForgotAndText + db "@" + +HMCantDeleteText: + TX_FAR _HMCantDeleteText + db "@" diff --git a/engine/pokemon/load_mon_data.asm b/engine/pokemon/load_mon_data.asm new file mode 100644 index 00000000..480ab1ca --- /dev/null +++ b/engine/pokemon/load_mon_data.asm @@ -0,0 +1,49 @@ +LoadMonData_:: +; Load monster [wWhichPokemon] from list [wMonDataLocation]: +; 0: partymon +; 1: enemymon +; 2: boxmon +; 3: daycaremon +; Return monster id at wcf91 and its data at wLoadedMon. +; Also load base stats at wMonHeader for convenience. + + ld a, [wDayCareMonSpecies] + ld [wcf91], a + ld a, [wMonDataLocation] + cp DAYCARE_DATA + jr z, .GetMonHeader + + ld a, [wWhichPokemon] + ld e, a + callab GetMonSpecies + +.GetMonHeader + ld a, [wcf91] + ld [wd0b5], a ; input for GetMonHeader + call GetMonHeader + + ld hl, wPartyMons + ld bc, wPartyMon2 - wPartyMon1 + ld a, [wMonDataLocation] + cp ENEMY_PARTY_DATA + jr c, .getMonEntry + + ld hl, wEnemyMons + jr z, .getMonEntry + + cp 2 + ld hl, wBoxMons + ld bc, wBoxMon2 - wBoxMon1 + jr z, .getMonEntry + + ld hl, wDayCareMon + jr .copyMonData + +.getMonEntry + ld a, [wWhichPokemon] + call AddNTimes + +.copyMonData + ld de, wLoadedMon + ld bc, wPartyMon2 - wPartyMon1 + jp CopyData diff --git a/engine/pokemon/remove_mon.asm b/engine/pokemon/remove_mon.asm new file mode 100644 index 00000000..6f7e91d6 --- /dev/null +++ b/engine/pokemon/remove_mon.asm @@ -0,0 +1,95 @@ +_RemovePokemon:: + ld hl, wPartyCount + ld a, [wRemoveMonFromBox] + and a + jr z, .asm_7b74 + ld hl, wNumInBox +.asm_7b74 + ld a, [hl] + dec a + ld [hli], a + ld a, [wWhichPokemon] + ld c, a + ld b, $0 + add hl, bc + ld e, l + ld d, h + inc de +.asm_7b81 + ld a, [de] + inc de + ld [hli], a + inc a + jr nz, .asm_7b81 + ld hl, wPartyMonOT + ld d, $5 + ld a, [wRemoveMonFromBox] + and a + jr z, .asm_7b97 + ld hl, wBoxMonOT + ld d, $13 +.asm_7b97 + ld a, [wWhichPokemon] + call SkipFixedLengthTextEntries + ld a, [wWhichPokemon] + cp d + jr nz, .asm_7ba6 + ld [hl], $ff + ret +.asm_7ba6 + ld d, h + ld e, l + ld bc, NAME_LENGTH + add hl, bc + ld bc, wPartyMonNicks + ld a, [wRemoveMonFromBox] + and a + jr z, .asm_7bb8 + ld bc, wBoxMonNicks +.asm_7bb8 + call CopyDataUntil + ld hl, wPartyMons + ld bc, wPartyMon2 - wPartyMon1 + ld a, [wRemoveMonFromBox] + and a + jr z, .asm_7bcd + ld hl, wBoxMons + ld bc, wBoxMon2 - wBoxMon1 +.asm_7bcd + ld a, [wWhichPokemon] + call AddNTimes + ld d, h + ld e, l + ld a, [wRemoveMonFromBox] + and a + jr z, .asm_7be4 + ld bc, wBoxMon2 - wBoxMon1 + add hl, bc + ld bc, wBoxMonOT + jr .asm_7beb +.asm_7be4 + ld bc, wPartyMon2 - wPartyMon1 + add hl, bc + ld bc, wPartyMonOT +.asm_7beb + call CopyDataUntil + ld hl, wPartyMonNicks + ld a, [wRemoveMonFromBox] + and a + jr z, .asm_7bfa + ld hl, wBoxMonNicks +.asm_7bfa + ld bc, NAME_LENGTH + ld a, [wWhichPokemon] + call AddNTimes + ld d, h + ld e, l + ld bc, NAME_LENGTH + add hl, bc + ld bc, wPokedexOwned + ld a, [wRemoveMonFromBox] + and a + jr z, .asm_7c15 + ld bc, wBoxMonNicksEnd +.asm_7c15 + jp CopyDataUntil diff --git a/engine/pokemon/set_types.asm b/engine/pokemon/set_types.asm new file mode 100755 index 00000000..e9235f13 --- /dev/null +++ b/engine/pokemon/set_types.asm @@ -0,0 +1,15 @@ +; updates the types of a party mon (pointed to in hl) to the ones of the mon specified in wd11e +SetPartyMonTypes: + call GetPredefRegisters + ld bc, wPartyMon1Type - wPartyMon1 ; $5 + add hl, bc + ld a, [wd11e] + ld [wd0b5], a + push hl + call GetMonHeader + pop hl + ld a, [wMonHType1] + ld [hli], a + ld a, [wMonHType2] + ld [hl], a + ret diff --git a/engine/pokemon/status_ailments.asm b/engine/pokemon/status_ailments.asm new file mode 100755 index 00000000..3da1fc43 --- /dev/null +++ b/engine/pokemon/status_ailments.asm @@ -0,0 +1,46 @@ +PrintStatusAilment:: + ld a, [de] + bit PSN, a + jr nz, .psn + bit BRN, a + jr nz, .brn + bit FRZ, a + jr nz, .frz + bit PAR, a + jr nz, .par + and SLP + ret z + ld a, "S" + ld [hli], a + ld a, "L" + ld [hli], a + ld [hl], "P" + ret +.psn + ld a, "P" + ld [hli], a + ld a, "S" + ld [hli], a + ld [hl], "N" + ret +.brn + ld a, "B" + ld [hli], a + ld a, "R" + ld [hli], a + ld [hl], "N" + ret +.frz + ld a, "F" + ld [hli], a + ld a, "R" + ld [hli], a + ld [hl], "Z" + ret +.par + ld a, "P" + ld [hli], a + ld a, "A" + ld [hli], a + ld [hl], "R" + ret diff --git a/engine/pokemon/status_screen.asm b/engine/pokemon/status_screen.asm new file mode 100755 index 00000000..20bee0ee --- /dev/null +++ b/engine/pokemon/status_screen.asm @@ -0,0 +1,481 @@ +DrawHP: +; Draws the HP bar in the stats screen + call GetPredefRegisters + ld a, $1 + jr DrawHP_ + +DrawHP2: +; Draws the HP bar in the party screen + call GetPredefRegisters + ld a, $2 + +DrawHP_: + ld [wHPBarType], a + push hl + ld a, [wLoadedMonHP] + ld b, a + ld a, [wLoadedMonHP + 1] + ld c, a + or b + jr nz, .nonzeroHP + xor a + ld c, a + ld e, a + ld a, $6 + ld d, a + jp .drawHPBarAndPrintFraction +.nonzeroHP + ld a, [wLoadedMonMaxHP] + ld d, a + ld a, [wLoadedMonMaxHP + 1] + ld e, a + predef HPBarLength + ld a, $6 + ld d, a + ld c, a +.drawHPBarAndPrintFraction + pop hl + push de + push hl + push hl + call DrawHPBar + pop hl + ld a, [hFlags_0xFFF6] + bit 0, a + jr z, .printFractionBelowBar + ld bc, $9 ; right of bar + jr .printFraction +.printFractionBelowBar + ld bc, SCREEN_WIDTH + 1 ; below bar +.printFraction + add hl, bc + ld de, wLoadedMonHP + lb bc, 2, 3 + call PrintNumber + ld a, "/" + ld [hli], a + ld de, wLoadedMonMaxHP + lb bc, 2, 3 + call PrintNumber + pop hl + pop de + ret + + +; Predef 0x37 +StatusScreen: + call LoadMonData + ld a, [wMonDataLocation] + cp BOX_DATA + jr c, .DontRecalculate +; mon is in a box or daycare + ld a, [wLoadedMonBoxLevel] + ld [wLoadedMonLevel], a + ld [wCurEnemyLVL], a + ld hl, wLoadedMonHPExp - 1 + ld de, wLoadedMonStats + ld b, $1 + call CalcStats ; Recalculate stats +.DontRecalculate + ld hl, wd72c + set 1, [hl] + ld a, $33 + ld [rNR50], a ; Reduce the volume + call GBPalWhiteOutWithDelay3 + call ClearScreen + call UpdateSprites + call LoadHpBarAndStatusTilePatterns + ld de, BattleHudTiles1 ; source + ld hl, vChars2 + $6d0 ; dest + lb bc, BANK(BattleHudTiles1), $03 + call CopyVideoDataDouble ; ·│ :L and halfarrow line end + ld de, BattleHudTiles2 + ld hl, vChars2 + $780 + lb bc, BANK(BattleHudTiles2), $01 + call CopyVideoDataDouble ; │ + ld de, BattleHudTiles3 + ld hl, vChars2 + $760 + lb bc, BANK(BattleHudTiles3), $02 + call CopyVideoDataDouble ; ─┘ + ld de, PTile + ld hl, vChars2 + $720 + lb bc, BANK(PTile), (PTileEnd - PTile) / $8 + call CopyVideoDataDouble ; P (for PP), inline + ld a, [hTilesetType] + push af + xor a + ld [hTilesetType], a + coord hl, 19, 1 + lb bc, 6, 10 + call DrawLineBox ; Draws the box around name, HP and status + ld de, -6 + add hl, de + ld [hl], "⠄" ; . after No ("." is a different one) + dec hl + ld [hl], "№" + coord hl, 19, 9 + lb bc, 8, 6 + call DrawLineBox ; Draws the box around types, ID No. and OT + coord hl, 10, 9 + ld de, Type1Text + call PlaceString ; "TYPE1/" + coord hl, 11, 3 + predef DrawHP + ld hl, wStatusScreenHPBarColor + call GetHealthBarColor + ld b, SET_PAL_STATUS_SCREEN + call RunPaletteCommand + coord hl, 16, 6 + ld de, wLoadedMonStatus + call PrintStatusCondition + jr nz, .StatusWritten + coord hl, 16, 6 + ld de, OKText + call PlaceString ; "OK" +.StatusWritten + coord hl, 9, 6 + ld de, StatusText + call PlaceString ; "STATUS/" + coord hl, 14, 2 + call PrintLevel ; Pokémon level + ld a, [wMonHIndex] + ld [wd11e], a + ld [wd0b5], a + predef IndexToPokedex + coord hl, 3, 7 + ld de, wd11e + lb bc, LEADING_ZEROES | 1, 3 + call PrintNumber ; Pokémon no. + coord hl, 11, 10 + predef PrintMonType + ld hl, NamePointers2 + call .GetStringPointer + ld d, h + ld e, l + coord hl, 9, 1 + call PlaceString ; Pokémon name + ld hl, OTPointers + call .GetStringPointer + ld d, h + ld e, l + coord hl, 12, 16 + call PlaceString ; OT + coord hl, 12, 14 + ld de, wLoadedMonOTID + lb bc, LEADING_ZEROES | 2, 5 + call PrintNumber ; ID Number + ld d, $0 + call PrintStatsBox + call Delay3 + call GBPalNormal + coord hl, 1, 0 + call LoadFlippedFrontSpriteByMonIndex ; draw Pokémon picture + ld a, [wcf91] + call PlayCry ; play Pokémon cry + call WaitForTextScrollButtonPress ; wait for button + pop af + ld [hTilesetType], a + ret + +.GetStringPointer + ld a, [wMonDataLocation] + add a + ld c, a + ld b, 0 + add hl, bc + ld a, [hli] + ld h, [hl] + ld l, a + ld a, [wMonDataLocation] + cp DAYCARE_DATA + ret z + ld a, [wWhichPokemon] + jp SkipFixedLengthTextEntries + +OTPointers: + dw wPartyMonOT + dw wEnemyMonOT + dw wBoxMonOT + dw wDayCareMonOT + +NamePointers2: + dw wPartyMonNicks + dw wEnemyMonNicks + dw wBoxMonNicks + dw wDayCareMonName + +Type1Text: + db "TYPE1/", $4e + +Type2Text: + db "TYPE2/", $4e + +IDNoText: + db $73, "№/", $4e + +OTText: + db "OT/" + next "@" + +StatusText: + db "STATUS/@" + +OKText: + db "OK@" + +; Draws a line starting from hl high b and wide c +DrawLineBox: + ld de, SCREEN_WIDTH ; New line +.PrintVerticalLine + ld [hl], $78 ; │ + add hl, de + dec b + jr nz, .PrintVerticalLine + ld [hl], $77 ; ┘ + dec hl +.PrintHorizLine + ld [hl], $76 ; ─ + dec hl + dec c + jr nz, .PrintHorizLine + ld [hl], $6f ; ← (halfarrow ending) + ret + +PTile: + INCBIN "gfx/font/P.1bpp" +PTileEnd: + +PrintStatsBox: + ld a, d + and a ; a is 0 from the status screen + jr nz, .DifferentBox + coord hl, 0, 8 + ld b, 8 + ld c, 8 + call TextBoxBorder ; Draws the box + coord hl, 1, 9 ; Start printing stats from here + ld bc, $0019 ; Number offset + jr .PrintStats +.DifferentBox + coord hl, 9, 2 + ld b, 8 + ld c, 9 + call TextBoxBorder + coord hl, 11, 3 + ld bc, $0018 +.PrintStats + push bc + push hl + ld de, StatsText + call PlaceString + pop hl + pop bc + add hl, bc + ld de, wLoadedMonAttack + lb bc, 2, 3 + call PrintStat + ld de, wLoadedMonDefense + call PrintStat + ld de, wLoadedMonSpeed + call PrintStat + ld de, wLoadedMonSpecial + jp PrintNumber +PrintStat: + push hl + call PrintNumber + pop hl + ld de, SCREEN_WIDTH * 2 + add hl, de + ret + +StatsText: + db "ATTACK" + next "DEFENSE" + next "SPEED" + next "SPECIAL@" + +StatusScreen2: + ld a, [hTilesetType] + push af + xor a + ld [hTilesetType], a + ld [H_AUTOBGTRANSFERENABLED], a + ld bc, NUM_MOVES + 1 + ld hl, wMoves + call FillMemory + ld hl, wLoadedMonMoves + ld de, wMoves + ld bc, NUM_MOVES + call CopyData + callab FormatMovesString + coord hl, 9, 2 + lb bc, 5, 10 + call ClearScreenArea ; Clear under name + coord hl, 19, 3 + ld [hl], $78 + coord hl, 0, 8 + ld b, 8 + ld c, 18 + call TextBoxBorder ; Draw move container + coord hl, 2, 9 + ld de, wMovesString + call PlaceString ; Print moves + ld a, [wNumMovesMinusOne] + inc a + ld c, a + ld a, $4 + sub c + ld b, a ; Number of moves ? + coord hl, 11, 10 + ld de, SCREEN_WIDTH * 2 + ld a, $72 ; special P tile id + call StatusScreen_PrintPP ; Print "PP" + ld a, b + and a + jr z, .InitPP + ld c, a + ld a, "-" + call StatusScreen_PrintPP ; Fill the rest with -- +.InitPP + ld hl, wLoadedMonMoves + coord de, 14, 10 + ld b, 0 +.PrintPP + ld a, [hli] + and a + jr z, .PPDone + push bc + push hl + push de + ld hl, wCurrentMenuItem + ld a, [hl] + push af + ld a, b + ld [hl], a + push hl + callab GetMaxPP + pop hl + pop af + ld [hl], a + pop de + pop hl + push hl + ld bc, wPartyMon1PP - wPartyMon1Moves - 1 + add hl, bc + ld a, [hl] + and $3f + ld [wStatusScreenCurrentPP], a + ld h, d + ld l, e + push hl + ld de, wStatusScreenCurrentPP + lb bc, 1, 2 + call PrintNumber + ld a, "/" + ld [hli], a + ld de, wMaxPP + lb bc, 1, 2 + call PrintNumber + pop hl + ld de, SCREEN_WIDTH * 2 + add hl, de + ld d, h + ld e, l + pop hl + pop bc + inc b + ld a, b + cp $4 + jr nz, .PrintPP +.PPDone + coord hl, 9, 3 + ld de, StatusScreenExpText + call PlaceString + ld a, [wLoadedMonLevel] + push af + cp MAX_LEVEL + jr z, .Level100 + inc a + ld [wLoadedMonLevel], a ; Increase temporarily if not 100 +.Level100 + coord hl, 14, 6 + ld [hl], $70 ; 1-tile "to" + inc hl + inc hl + call PrintLevel + pop af + ld [wLoadedMonLevel], a + ld de, wLoadedMonExp + coord hl, 12, 4 + lb bc, 3, 7 + call PrintNumber ; exp + call CalcExpToLevelUp + ld de, wLoadedMonExp + coord hl, 7, 6 + lb bc, 3, 7 + call PrintNumber ; exp needed to level up + coord hl, 9, 0 + call StatusScreen_ClearName + coord hl, 9, 1 + call StatusScreen_ClearName + ld a, [wMonHIndex] + ld [wd11e], a + call GetMonName + coord hl, 9, 1 + call PlaceString + ld a, $1 + ld [H_AUTOBGTRANSFERENABLED], a + call Delay3 + call WaitForTextScrollButtonPress ; wait for button + pop af + ld [hTilesetType], a + ld hl, wd72c + res 1, [hl] + ld a, $77 + ld [rNR50], a + call GBPalWhiteOut + jp ClearScreen + +CalcExpToLevelUp: + ld a, [wLoadedMonLevel] + cp MAX_LEVEL + jr z, .atMaxLevel + inc a + ld d, a + callab CalcExperience + ld hl, wLoadedMonExp + 2 + ld a, [hExperience + 2] + sub [hl] + ld [hld], a + ld a, [hExperience + 1] + sbc [hl] + ld [hld], a + ld a, [hExperience] + sbc [hl] + ld [hld], a + ret +.atMaxLevel + ld hl, wLoadedMonExp + xor a + ld [hli], a + ld [hli], a + ld [hl], a + ret + +StatusScreenExpText: + db "EXP POINTS" + next "LEVEL UP@" + +StatusScreen_ClearName: + ld bc, 10 + ld a, " " + jp FillMemory + +StatusScreen_PrintPP: +; print PP or -- c times, going down two rows each time + ld [hli], a + ld [hld], a + add hl, de + dec c + jr nz, StatusScreen_PrintPP + ret diff --git a/engine/predefs12.asm b/engine/predefs12.asm deleted file mode 100755 index 95f0ea25..00000000 --- a/engine/predefs12.asm +++ /dev/null @@ -1,71 +0,0 @@ -; b = new colour for BG colour 0 (usually white) for 4 frames -ChangeBGPalColor0_4Frames: - call GetPredefRegisters - ld a, [rBGP] - or b - ld [rBGP], a - ld c, 4 - call DelayFrames - ld a, [rBGP] - and %11111100 - ld [rBGP], a - ret - -PredefShakeScreenVertically: -; Moves the window down and then back in a sequence of progressively smaller -; numbers of pixels, starting at b. - call GetPredefRegisters - ld a, 1 - ld [wDisableVBlankWYUpdate], a - xor a -.loop - ld [$ff96], a - call .MutateWY - call .MutateWY - dec b - ld a, b - jr nz, .loop - xor a - ld [wDisableVBlankWYUpdate], a - ret - -.MutateWY - ld a, [$ff96] - xor b - ld [$ff96], a - ld [rWY], a - ld c, 3 - jp DelayFrames - -PredefShakeScreenHorizontally: -; Moves the window right and then back in a sequence of progressively smaller -; numbers of pixels, starting at b. - call GetPredefRegisters - xor a -.loop - ld [$ff97], a - call .MutateWX - ld c, 1 - call DelayFrames - call .MutateWX - dec b - ld a, b - jr nz, .loop - -; restore normal WX - ld a, 7 - ld [rWX], a - ret - -.MutateWX - ld a, [$ff97] - xor b - ld [$ff97], a - bit 7, a - jr z, .skipZeroing - xor a ; zero a if it's negative -.skipZeroing - add 7 - ld [rWX], a - ld c, 4 - jp DelayFrames diff --git a/engine/predefs17.asm b/engine/predefs17.asm deleted file mode 100755 index 21289c6a..00000000 --- a/engine/predefs17.asm +++ /dev/null @@ -1,9 +0,0 @@ -; this function temporarily makes the starters (and Ivysaur) seen -; so that the full Pokedex information gets displayed in Oak's lab -StarterDex: - ld a, %01001011 ; set starter flags - ld [wPokedexOwned], a - predef ShowPokedexData - xor a ; unset starter flags - ld [wPokedexOwned], a - ret diff --git a/engine/predefs17_2.asm b/engine/predefs17_2.asm deleted file mode 100755 index e9235f13..00000000 --- a/engine/predefs17_2.asm +++ /dev/null @@ -1,15 +0,0 @@ -; updates the types of a party mon (pointed to in hl) to the ones of the mon specified in wd11e -SetPartyMonTypes: - call GetPredefRegisters - ld bc, wPartyMon1Type - wPartyMon1 ; $5 - add hl, bc - ld a, [wd11e] - ld [wd0b5], a - push hl - call GetMonHeader - pop hl - ld a, [wMonHType1] - ld [hli], a - ld a, [wMonHType2] - ld [hl], a - ret diff --git a/engine/predefs7.asm b/engine/predefs7.asm deleted file mode 100755 index 752bdd1a..00000000 --- a/engine/predefs7.asm +++ /dev/null @@ -1,48 +0,0 @@ -DisplayElevatorFloorMenu: - ld hl, WhichFloorText - call PrintText - ld hl, wItemList - ld a, l - ld [wListPointer], a - ld a, h - ld [wListPointer + 1], a - ld a, [wListScrollOffset] - push af - xor a - ld [wCurrentMenuItem], a - ld [wListScrollOffset], a - ld [wPrintItemPrices], a - ld a, SPECIALLISTMENU - ld [wListMenuID], a - call DisplayListMenuID - pop bc - ld a, b - ld [wListScrollOffset], a - ret c - ld hl, wCurrentMapScriptFlags - set 7, [hl] - ld hl, wElevatorWarpMaps - ld a, [wWhichPokemon] - add a - ld d, 0 - ld e, a - add hl, de - ld a, [hli] - ld b, a - ld a, [hl] - ld c, a - ld hl, wWarpEntries - call .UpdateWarp - -.UpdateWarp - inc hl - inc hl - ld a, b - ld [hli], a ; destination warp ID - ld a, c - ld [hli], a ; destination map ID - ret - -WhichFloorText: - TX_FAR _WhichFloorText - db "@" diff --git a/engine/print_waiting_text.asm b/engine/print_waiting_text.asm deleted file mode 100644 index c48459d3..00000000 --- a/engine/print_waiting_text.asm +++ /dev/null @@ -1,20 +0,0 @@ -PrintWaitingText:: - coord hl, 3, 10 - ld b, $1 - ld c, $b - ld a, [wIsInBattle] - and a - jr z, .asm_4c17 - call TextBoxBorder - jr .asm_4c1a -.asm_4c17 - call CableClub_TextBoxBorder -.asm_4c1a - coord hl, 4, 11 - ld de, WaitingText - call PlaceString - ld c, 50 - jp DelayFrames - -WaitingText: - db "Waiting...!@" diff --git a/engine/random.asm b/engine/random.asm deleted file mode 100755 index 2fc83f6f..00000000 --- a/engine/random.asm +++ /dev/null @@ -1,13 +0,0 @@ -Random_:: -; Generate a random 16-bit value. - ld a, [rDIV] - ld b, a - ld a, [hRandomAdd] - adc b - ld [hRandomAdd], a - ld a, [rDIV] - ld b, a - ld a, [hRandomSub] - sbc b - ld [hRandomSub], a - ret diff --git a/engine/remove_pokemon.asm b/engine/remove_pokemon.asm deleted file mode 100644 index 6f7e91d6..00000000 --- a/engine/remove_pokemon.asm +++ /dev/null @@ -1,95 +0,0 @@ -_RemovePokemon:: - ld hl, wPartyCount - ld a, [wRemoveMonFromBox] - and a - jr z, .asm_7b74 - ld hl, wNumInBox -.asm_7b74 - ld a, [hl] - dec a - ld [hli], a - ld a, [wWhichPokemon] - ld c, a - ld b, $0 - add hl, bc - ld e, l - ld d, h - inc de -.asm_7b81 - ld a, [de] - inc de - ld [hli], a - inc a - jr nz, .asm_7b81 - ld hl, wPartyMonOT - ld d, $5 - ld a, [wRemoveMonFromBox] - and a - jr z, .asm_7b97 - ld hl, wBoxMonOT - ld d, $13 -.asm_7b97 - ld a, [wWhichPokemon] - call SkipFixedLengthTextEntries - ld a, [wWhichPokemon] - cp d - jr nz, .asm_7ba6 - ld [hl], $ff - ret -.asm_7ba6 - ld d, h - ld e, l - ld bc, NAME_LENGTH - add hl, bc - ld bc, wPartyMonNicks - ld a, [wRemoveMonFromBox] - and a - jr z, .asm_7bb8 - ld bc, wBoxMonNicks -.asm_7bb8 - call CopyDataUntil - ld hl, wPartyMons - ld bc, wPartyMon2 - wPartyMon1 - ld a, [wRemoveMonFromBox] - and a - jr z, .asm_7bcd - ld hl, wBoxMons - ld bc, wBoxMon2 - wBoxMon1 -.asm_7bcd - ld a, [wWhichPokemon] - call AddNTimes - ld d, h - ld e, l - ld a, [wRemoveMonFromBox] - and a - jr z, .asm_7be4 - ld bc, wBoxMon2 - wBoxMon1 - add hl, bc - ld bc, wBoxMonOT - jr .asm_7beb -.asm_7be4 - ld bc, wPartyMon2 - wPartyMon1 - add hl, bc - ld bc, wPartyMonOT -.asm_7beb - call CopyDataUntil - ld hl, wPartyMonNicks - ld a, [wRemoveMonFromBox] - and a - jr z, .asm_7bfa - ld hl, wBoxMonNicks -.asm_7bfa - ld bc, NAME_LENGTH - ld a, [wWhichPokemon] - call AddNTimes - ld d, h - ld e, l - ld bc, NAME_LENGTH - add hl, bc - ld bc, wPokedexOwned - ld a, [wRemoveMonFromBox] - and a - jr z, .asm_7c15 - ld bc, wBoxMonNicksEnd -.asm_7c15 - jp CopyDataUntil diff --git a/engine/save.asm b/engine/save.asm deleted file mode 100755 index 33a7ba8d..00000000 --- a/engine/save.asm +++ /dev/null @@ -1,708 +0,0 @@ -LoadSAV: -;(if carry -> write -;"the file data is destroyed") - call ClearScreen - call LoadFontTilePatterns - call LoadTextBoxTilePatterns - call LoadSAV0 - jr c, .badsum - call LoadSAV1 - jr c, .badsum - call LoadSAV2 - jr c, .badsum - ld a, $2 ; good checksum - jr .goodsum -.badsum - ld hl, wd730 - push hl - set 6, [hl] - ld hl, FileDataDestroyedText - call PrintText - ld c, 100 - call DelayFrames - pop hl - res 6, [hl] - ld a, $1 ; bad checksum -.goodsum - ld [wSaveFileStatus], a - ret - -FileDataDestroyedText: - TX_FAR _FileDataDestroyedText - db "@" - -LoadSAV0: - ld a, SRAM_ENABLE - ld [MBC1SRamEnable], a - 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 - call SAVCheckSum - ld c, a - ld a, [sMainDataCheckSum] ; SAV's checksum - cp c - jp z, .checkSumsMatched - -; If the computed checksum didn't match the saved on, try again. - ld hl, sPlayerName - ld bc, sMainDataCheckSum - sPlayerName - call SAVCheckSum - ld c, a - ld a, [sMainDataCheckSum] ; SAV's checksum - cp c - jp nz, SAVBadCheckSum - -.checkSumsMatched - ld hl, sPlayerName - ld de, wPlayerName - ld bc, NAME_LENGTH - call CopyData - ld hl, sMainData - ld de, wMainDataStart - ld bc, wMainDataEnd - wMainDataStart - call CopyData - ld hl, wCurMapTileset - set 7, [hl] - ld hl, sSpriteData - ld de, wSpriteDataStart - ld bc, wSpriteDataEnd - wSpriteDataStart - call CopyData - ld a, [sTilesetType] - ld [hTilesetType], a - ld hl, sCurBoxData - ld de, wBoxDataStart - ld bc, wBoxDataEnd - wBoxDataStart - call CopyData - and a - jp SAVGoodChecksum - -LoadSAV1: - ld a, SRAM_ENABLE - ld [MBC1SRamEnable], a - 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 - call SAVCheckSum - ld c, a - ld a, [sMainDataCheckSum] ; SAV's checksum - cp c - jr nz, SAVBadCheckSum - ld hl, sCurBoxData - ld de, wBoxDataStart - ld bc, wBoxDataEnd - wBoxDataStart - call CopyData - and a - jp SAVGoodChecksum - -LoadSAV2: - ld a, SRAM_ENABLE - ld [MBC1SRamEnable], a - 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 - call SAVCheckSum - ld c, a - ld a, [sMainDataCheckSum] ; SAV's checksum - cp c - jp nz, SAVBadCheckSum - ld hl, sPartyData - ld de, wPartyDataStart - ld bc, wPartyDataEnd - wPartyDataStart - call CopyData - ld hl, sMainData - ld de, wPokedexOwned - ld bc, wPokedexSeenEnd - wPokedexOwned - call CopyData - and a - jp SAVGoodChecksum - -SAVBadCheckSum: - scf - -SAVGoodChecksum: - ld a, $0 - ld [MBC1SRamBankingMode], a - ld [MBC1SRamEnable], a - ret - -LoadSAVIgnoreBadCheckSum: -; unused function that loads save data and ignores bad checksums - call LoadSAV0 - call LoadSAV1 - jp LoadSAV2 - -SaveSAV: - callba PrintSaveScreenText - ld hl, WouldYouLikeToSaveText - call SaveSAVConfirm - and a ;|0 = Yes|1 = No| - ret nz - ld a, [wSaveFileStatus] - dec a - jr z, .save - call SAVCheckRandomID - jr z, .save - ld hl, OlderFileWillBeErasedText - call SaveSAVConfirm - and a - ret nz -.save - call SaveSAVtoSRAM - coord hl, 1, 13 - lb bc, 4, 18 - call ClearScreenArea - coord hl, 1, 14 - ld de, NowSavingString - call PlaceString - ld c, 120 - call DelayFrames - ld hl, GameSavedText - call PrintText - ld a, SFX_SAVE - call PlaySoundWaitForCurrent - call WaitForSoundToFinish - ld c, 30 - jp DelayFrames - -NowSavingString: - db "Now saving...@" - -SaveSAVConfirm: - call PrintText - coord hl, 0, 7 - lb bc, 8, 1 - ld a, TWO_OPTION_MENU - ld [wTextBoxID], a - call DisplayTextBoxID ; yes/no menu - ld a, [wCurrentMenuItem] - ret - -WouldYouLikeToSaveText: - TX_FAR _WouldYouLikeToSaveText - db "@" - -GameSavedText: - TX_FAR _GameSavedText - db "@" - -OlderFileWillBeErasedText: - TX_FAR _OlderFileWillBeErasedText - db "@" - -SaveSAVtoSRAM0: - ld a, SRAM_ENABLE - ld [MBC1SRamEnable], a - ld a, $1 - ld [MBC1SRamBankingMode], a - ld [MBC1SRamBank], a - ld hl, wPlayerName - ld de, sPlayerName - ld bc, NAME_LENGTH - call CopyData - ld hl, wMainDataStart - ld de, sMainData - ld bc, wMainDataEnd - wMainDataStart - call CopyData - ld hl, wSpriteDataStart - ld de, sSpriteData - ld bc, wSpriteDataEnd - wSpriteDataStart - call CopyData - ld hl, wBoxDataStart - ld de, sCurBoxData - ld bc, wBoxDataEnd - wBoxDataStart - call CopyData - ld a, [hTilesetType] - ld [sTilesetType], a - ld hl, sPlayerName - ld bc, sMainDataCheckSum - sPlayerName - call SAVCheckSum - ld [sMainDataCheckSum], a - xor a - ld [MBC1SRamBankingMode], a - ld [MBC1SRamEnable], a - ret - -SaveSAVtoSRAM1: -; stored pokémon - ld a, SRAM_ENABLE - ld [MBC1SRamEnable], a - ld a, $1 - ld [MBC1SRamBankingMode], a - ld [MBC1SRamBank], a - ld hl, wBoxDataStart - ld de, sCurBoxData - ld bc, wBoxDataEnd - wBoxDataStart - call CopyData - ld hl, sPlayerName - ld bc, sMainDataCheckSum - sPlayerName - call SAVCheckSum - ld [sMainDataCheckSum], a - xor a - ld [MBC1SRamBankingMode], a - ld [MBC1SRamEnable], a - ret - -SaveSAVtoSRAM2: - ld a, SRAM_ENABLE - ld [MBC1SRamEnable], a - ld a, $1 - ld [MBC1SRamBankingMode], a - ld [MBC1SRamBank], a - ld hl, wPartyDataStart - ld de, sPartyData - ld bc, wPartyDataEnd - wPartyDataStart - call CopyData - ld hl, wPokedexOwned ; pokédex only - ld de, sMainData - ld bc, wPokedexSeenEnd - wPokedexOwned - call CopyData - ld hl, sPlayerName - ld bc, sMainDataCheckSum - sPlayerName - call SAVCheckSum - ld [sMainDataCheckSum], a - xor a - ld [MBC1SRamBankingMode], a - ld [MBC1SRamEnable], a - ret - -SaveSAVtoSRAM:: - ld a, $2 - ld [wSaveFileStatus], a - call SaveSAVtoSRAM0 - call SaveSAVtoSRAM1 - jp SaveSAVtoSRAM2 - -SAVCheckSum: -;Check Sum (result[1 byte] is complemented) - ld d, 0 -.loop - ld a, [hli] - add d - ld d, a - dec bc - ld a, b - or c - jr nz, .loop - ld a, d - cpl - ret - -CalcIndividualBoxCheckSums: - ld hl, sBox1 ; sBox7 - ld de, sBank2IndividualBoxChecksums ; sBank3IndividualBoxChecksums - ld b, NUM_BOXES / 2 -.loop - push bc - push de - ld bc, wBoxDataEnd - wBoxDataStart - call SAVCheckSum - pop de - ld [de], a - inc de - pop bc - dec b - jr nz, .loop - ret - -GetBoxSRAMLocation: -; in: a = box num -; out: b = box SRAM bank, hl = pointer to start of box - ld hl, BoxSRAMPointerTable - ld a, [wCurrentBoxNum] - and $7f - cp NUM_BOXES / 2 - ld b, 2 - jr c, .next - inc b - sub NUM_BOXES / 2 -.next - ld e, a - ld d, 0 - add hl, de - add hl, de - ld a, [hli] - ld h, [hl] - ld l, a - ret - -BoxSRAMPointerTable: - dw sBox1 ; sBox7 - dw sBox2 ; sBox8 - dw sBox3 ; sBox9 - dw sBox4 ; sBox10 - dw sBox5 ; sBox11 - dw sBox6 ; sBox12 - -ChangeBox:: - ld hl, WhenYouChangeBoxText - call PrintText - call YesNoChoice - ld a, [wCurrentMenuItem] - and a - ret nz ; return if No was chosen - ld hl, wCurrentBoxNum - bit 7, [hl] ; is it the first time player is changing the box? - call z, EmptyAllSRAMBoxes ; if so, empty all boxes in SRAM - call DisplayChangeBoxMenu - call UpdateSprites - ld hl, hFlags_0xFFF6 - set 1, [hl] - call HandleMenuInput - ld hl, hFlags_0xFFF6 - res 1, [hl] - bit 1, a ; pressed b - ret nz - call GetBoxSRAMLocation - ld e, l - ld d, h - ld hl, wBoxDataStart - call CopyBoxToOrFromSRAM ; copy old box from WRAM to SRAM - ld a, [wCurrentMenuItem] - set 7, a - ld [wCurrentBoxNum], a - call GetBoxSRAMLocation - ld de, wBoxDataStart - call CopyBoxToOrFromSRAM ; copy new box from SRAM to WRAM - ld hl, wMapTextPtr - ld de, wChangeBoxSavedMapTextPointer - ld a, [hli] - ld [de], a - inc de - ld a, [hl] - ld [de], a - call RestoreMapTextPointer - call SaveSAVtoSRAM - ld hl, wChangeBoxSavedMapTextPointer - call SetMapTextPointer - ld a, SFX_SAVE - call PlaySoundWaitForCurrent - call WaitForSoundToFinish - ret - -WhenYouChangeBoxText: - TX_FAR _WhenYouChangeBoxText - db "@" - -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 - ld a, b - ld [MBC1SRamBank], a - ld bc, wBoxDataEnd - wBoxDataStart - call CopyData - pop hl - -; mark the memory that the box was copied from as am empty box - xor a - ld [hli], a - dec a - ld [hl], a - - ld hl, sBox1 ; sBox7 - ld bc, sBank2AllBoxesChecksum - sBox1 - call SAVCheckSum - ld [sBank2AllBoxesChecksum], a ; sBank3AllBoxesChecksum - call CalcIndividualBoxCheckSums - xor a - ld [MBC1SRamBankingMode], a - ld [MBC1SRamEnable], a - ret - -DisplayChangeBoxMenu: - xor a - ld [H_AUTOBGTRANSFERENABLED], a - ld a, A_BUTTON | B_BUTTON - ld [wMenuWatchedKeys], a - ld a, 11 - ld [wMaxMenuItem], a - ld a, 1 - ld [wTopMenuItemY], a - ld a, 12 - ld [wTopMenuItemX], a - xor a - ld [wMenuWatchMovingOutOfBounds], a - ld a, [wCurrentBoxNum] - and $7f - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - coord hl, 0, 0 - ld b, 2 - ld c, 9 - call TextBoxBorder - ld hl, ChooseABoxText - call PrintText - coord hl, 11, 0 - ld b, 12 - ld c, 7 - call TextBoxBorder - ld hl, hFlags_0xFFF6 - set 2, [hl] - ld de, BoxNames - coord hl, 13, 1 - call PlaceString - ld hl, hFlags_0xFFF6 - res 2, [hl] - ld a, [wCurrentBoxNum] - and $7f - cp 9 - jr c, .singleDigitBoxNum - sub 9 - coord hl, 8, 2 - ld [hl], "1" - add "0" - jr .next -.singleDigitBoxNum - add "1" -.next - Coorda 9, 2 - coord hl, 1, 2 - ld de, BoxNoText - call PlaceString - call GetMonCountsForAllBoxes - coord hl, 18, 1 - ld de, wBoxMonCounts - ld bc, SCREEN_WIDTH - ld a, $c -.loop - push af - ld a, [de] - and a ; is the box empty? - jr z, .skipPlacingPokeball - ld [hl], $78 ; place pokeball tile next to box name if box not empty -.skipPlacingPokeball - add hl, bc - inc de - pop af - dec a - jr nz, .loop - ld a, 1 - ld [H_AUTOBGTRANSFERENABLED], a - ret - -ChooseABoxText: - TX_FAR _ChooseABoxText - db "@" - -BoxNames: - db "BOX 1" - next "BOX 2" - next "BOX 3" - next "BOX 4" - next "BOX 5" - next "BOX 6" - next "BOX 7" - next "BOX 8" - next "BOX 9" - next "BOX10" - next "BOX11" - next "BOX12@" - -BoxNoText: - db "BOX No.@" - -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 - ld a, 2 - ld [MBC1SRamBank], a - call EmptySRAMBoxesInBank - ld a, 3 - ld [MBC1SRamBank], a - call EmptySRAMBoxesInBank - xor a - ld [MBC1SRamBankingMode], a - ld [MBC1SRamEnable], a - ret - -EmptySRAMBoxesInBank: -; marks every box in the current SRAM bank as empty - ld hl, sBox1 ; sBox7 - call EmptySRAMBox - ld hl, sBox2 ; sBox8 - call EmptySRAMBox - ld hl, sBox3 ; sBox9 - call EmptySRAMBox - ld hl, sBox4 ; sBox10 - call EmptySRAMBox - ld hl, sBox5 ; sBox11 - call EmptySRAMBox - ld hl, sBox6 ; sBox12 - call EmptySRAMBox - ld hl, sBox1 ; sBox7 - ld bc, sBank2AllBoxesChecksum - sBox1 - call SAVCheckSum - ld [sBank2AllBoxesChecksum], a ; sBank3AllBoxesChecksum - call CalcIndividualBoxCheckSums - ret - -EmptySRAMBox: - xor a - ld [hli], a - dec a - ld [hl], a - ret - -GetMonCountsForAllBoxes: - ld hl, wBoxMonCounts - push hl - ld a, SRAM_ENABLE - ld [MBC1SRamEnable], a - ld a, $1 - ld [MBC1SRamBankingMode], a - ld a, $2 - ld [MBC1SRamBank], a - call GetMonCountsForBoxesInBank - ld a, $3 - ld [MBC1SRamBank], a - call GetMonCountsForBoxesInBank - xor a - ld [MBC1SRamBankingMode], a - ld [MBC1SRamEnable], a - pop hl - -; copy the count for the current box from WRAM - ld a, [wCurrentBoxNum] - and $7f - ld c, a - ld b, 0 - add hl, bc - ld a, [wNumInBox] - ld [hl], a - - ret - -GetMonCountsForBoxesInBank: - ld a, [sBox1] ; sBox7 - ld [hli], a - ld a, [sBox2] ; sBox8 - ld [hli], a - ld a, [sBox3] ; sBox9 - ld [hli], a - ld a, [sBox4] ; sBox10 - ld [hli], a - ld a, [sBox5] ; sBox11 - ld [hli], a - ld a, [sBox6] ; sBox12 - ld [hli], a - ret - -SAVCheckRandomID: -;checks if Sav file is the same by checking player's name 1st letter ($a598) -; and the two random numbers generated at game beginning -;(which are stored at wPlayerID)s - ld a, $0a - ld [MBC1SRamEnable], a - ld a, $01 - ld [MBC1SRamBankingMode], a - ld [MBC1SRamBank], a - ld a, [sPlayerName] - and a - jr z, .next - ld hl, sPlayerName - ld bc, sMainDataCheckSum - sPlayerName - call SAVCheckSum - ld c, a - ld a, [sMainDataCheckSum] - cp c - jr nz, .next - ld hl, sMainData + (wPlayerID - wMainDataStart) ; player ID - ld a, [hli] - ld h, [hl] - ld l, a - ld a, [wPlayerID] - cp l - jr nz, .next - ld a, [wPlayerID + 1] - cp h -.next - ld a, $00 - ld [MBC1SRamBankingMode], a - ld [MBC1SRamEnable], a - ret - -SaveHallOfFameTeams: - ld a, [wNumHoFTeams] - dec a - cp HOF_TEAM_CAPACITY - jr nc, .shiftHOFTeams - ld hl, sHallOfFame - ld bc, HOF_TEAM - call AddNTimes - ld e, l - ld d, h - ld hl, wHallOfFame - ld bc, HOF_TEAM - jr HallOfFame_Copy - -.shiftHOFTeams -; if the space designated for HOF teams is full, then shift all HOF teams to the next slot, making space for the new HOF team -; this deletes the last HOF team though - ld hl, sHallOfFame + HOF_TEAM - ld de, sHallOfFame - ld bc, HOF_TEAM * (HOF_TEAM_CAPACITY - 1) - call HallOfFame_Copy - ld hl, wHallOfFame - ld de, sHallOfFame + HOF_TEAM * (HOF_TEAM_CAPACITY - 1) - ld bc, HOF_TEAM - jr HallOfFame_Copy - -LoadHallOfFameTeams: - ld hl, sHallOfFame - ld bc, HOF_TEAM - ld a, [wHoFTeamIndex] - call AddNTimes - ld de, wHallOfFame - ld bc, HOF_TEAM - ; fallthrough - -HallOfFame_Copy: - ld a, SRAM_ENABLE - ld [MBC1SRamEnable], a - ld a, $1 - ld [MBC1SRamBankingMode], a - xor a - ld [MBC1SRamBank], a - call CopyData - xor a - ld [MBC1SRamBankingMode], a - ld [MBC1SRamEnable], a - 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 PadSRAM_FF - xor a - ld [MBC1SRamBankingMode], a - ld [MBC1SRamEnable], a - ret - -PadSRAM_FF: - ld [MBC1SRamBank], a - ld hl, $a000 - ld bc, $2000 - ld a, $ff - jp FillMemory diff --git a/engine/slot_machine.asm b/engine/slot_machine.asm deleted file mode 100755 index 0a92c69b..00000000 --- a/engine/slot_machine.asm +++ /dev/null @@ -1,892 +0,0 @@ -PromptUserToPlaySlots: - call SaveScreenTilesToBuffer2 - ld a, BANK(DisplayTextIDInit) - ld [wAutoTextBoxDrawingControl], a - ld b, a - ld hl, DisplayTextIDInit - call Bankswitch - ld hl, PlaySlotMachineText - call PrintText - call YesNoChoice - ld a, [wCurrentMenuItem] - and a - jr nz, .done ; if player chose No - dec a - ld [wUpdateSpritesEnabled], a - ld hl, wSlotMachineRerollCounter - xor a - ld [hli], a - ld [hl], SMILE_BUBBLE - predef EmotionBubble - call GBPalWhiteOutWithDelay3 - call LoadSlotMachineTiles - call LoadFontTilePatterns - ld b, SET_PAL_SLOTS - call RunPaletteCommand - call GBPalNormal - ld a, $e4 - ld [rOBP0], a - ld hl, wd730 - set 6, [hl] - xor a - ld [wSlotMachineAllowMatchesCounter], a - ld hl, wStoppingWhichSlotMachineWheel - ld bc, $0014 - call FillMemory - call MainSlotMachineLoop - ld hl, wd730 - res 6, [hl] - xor a - ld [wSlotMachineAllowMatchesCounter], a - call GBPalWhiteOutWithDelay3 - ld a, $1 - ld [wUpdateSpritesEnabled], a - call RunDefaultPaletteCommand - call ReloadMapSpriteTilePatterns - call ReloadTilesetTilePatterns -.done - call LoadScreenTilesFromBuffer2 - call Delay3 - call GBPalNormal - ld a, [wSlotMachineSavedROMBank] - push af - jp CloseTextDisplay - -PlaySlotMachineText: - TX_FAR _PlaySlotMachineText - db "@" - -MainSlotMachineLoop: - call SlotMachine_PrintCreditCoins - xor a - ld hl, wPayoutCoins - ld [hli], a - ld [hl], a - call SlotMachine_PrintPayoutCoins - ld hl, BetHowManySlotMachineText - call PrintText - call SaveScreenTilesToBuffer1 -.loop - ld a, A_BUTTON | B_BUTTON - ld [wMenuWatchedKeys], a - ld a, 2 - ld [wMaxMenuItem], a - ld a, 12 - ld [wTopMenuItemY], a - ld a, 15 - ld [wTopMenuItemX], a - xor a - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - ld [wMenuWatchMovingOutOfBounds], a - coord hl, 14, 11 - ld b, 5 - ld c, 4 - call TextBoxBorder - coord hl, 16, 12 - ld de, CoinMultiplierSlotMachineText - call PlaceString - call HandleMenuInput - and B_BUTTON - jp nz, LoadScreenTilesFromBuffer1 - ld a, [wCurrentMenuItem] - ld b, a - ld a, 3 - sub b - ld [wSlotMachineBet], a - ld hl, wPlayerCoins - ld c, a - ld a, [hli] - and a - jr nz, .skip1 - ld a, [hl] - cp c - jr nc, .skip1 - ld hl, NotEnoughCoinsSlotMachineText - call PrintText - jr .loop -.skip1 - call LoadScreenTilesFromBuffer1 - call SlotMachine_SubtractBetFromPlayerCoins - call SlotMachine_LightBalls - call SlotMachine_SetFlags - ld a, 4 - ld hl, wSlotMachineWheel1SlipCounter - ld [hli], a - ld [hli], a - ld [hl], a - call WaitForSoundToFinish - ld a, SFX_SLOTS_NEW_SPIN - call PlaySound - ld hl, StartSlotMachineText - call PrintText - call SlotMachine_SpinWheels - call SlotMachine_CheckForMatches - ld hl, wPlayerCoins - ld a, [hli] - or [hl] - jr nz, .skip2 - ld hl, OutOfCoinsSlotMachineText - call PrintText - ld c, 60 - jp DelayFrames -.skip2 - ld hl, OneMoreGoSlotMachineText - call PrintText - coord hl, 14, 12 - lb bc, 13, 15 - xor a ; YES_NO_MENU - ld [wTwoOptionMenuID], a - ld a, TWO_OPTION_MENU - ld [wTextBoxID], a - call DisplayTextBoxID - ld a, [wCurrentMenuItem] - and a - ret nz - call SlotMachine_PutOutLitBalls - jp MainSlotMachineLoop - -CoinMultiplierSlotMachineText: - db "×3" - next "×2" - next "×1@" - -OutOfCoinsSlotMachineText: - TX_FAR _OutOfCoinsSlotMachineText - db "@" - -BetHowManySlotMachineText: - TX_FAR _BetHowManySlotMachineText - db "@" - -StartSlotMachineText: - TX_FAR _StartSlotMachineText - db "@" - -NotEnoughCoinsSlotMachineText: - TX_FAR _NotEnoughCoinsSlotMachineText - db "@" - -OneMoreGoSlotMachineText: - TX_FAR _OneMoreGoSlotMachineText - db "@" - -SlotMachine_SetFlags: - ld hl, wSlotMachineFlags - bit 7, [hl] - ret nz - ld a, [wSlotMachineAllowMatchesCounter] - and a - jr nz, .allowMatches - call Random - and a - jr z, .setAllowMatchesCounter ; 1/256 (~0.4%) chance - ld b, a - ld a, [wSlotMachineSevenAndBarModeChance] - cp b - jr c, .allowSevenAndBarMatches - ld a, 210 - cp b - jr c, .allowMatches ; 55/256 (~21.5%) chance - ld [hl], 0 - ret -.allowMatches - set 6, [hl] - ret -.setAllowMatchesCounter - ld a, 60 - ld [wSlotMachineAllowMatchesCounter], a - ret -.allowSevenAndBarMatches - set 7, [hl] - ret - -SlotMachine_SpinWheels: - ld c, 20 -.loop1 - push bc - call SlotMachine_AnimWheel1 - call SlotMachine_AnimWheel2 - call SlotMachine_AnimWheel3 - ld c, 2 - call DelayFrames - pop bc - dec c - jr nz, .loop1 - xor a - ld [wStoppingWhichSlotMachineWheel], a -.loop2 - call SlotMachine_HandleInputWhileWheelsSpin - call SlotMachine_StopOrAnimWheel1 - call SlotMachine_StopOrAnimWheel2 - call SlotMachine_StopOrAnimWheel3 - ret c - ld a, [wOnSGB] - xor $1 - inc a - ld c, a - call DelayFrames - jr .loop2 - -; Note that the wheels can only stop when a symbol is centred in the wheel -; and thus 3 full symbols rather than 2 full symbols and 2 half symbols are -; visible. The 3 functions below ensure this by checking if the wheel offset -; is even before stopping the wheel. - -SlotMachine_StopOrAnimWheel1: - ld a, [wStoppingWhichSlotMachineWheel] - cp 1 - jr c, .animWheel - ld de, wSlotMachineWheel1Offset - ld a, [de] - rra - jr nc, .animWheel ; check that a symbol is centred in the wheel - ld hl, wSlotMachineWheel1SlipCounter - ld a, [hl] - and a - ret z - dec [hl] - call SlotMachine_StopWheel1Early - ret nz -.animWheel - jp SlotMachine_AnimWheel1 - -SlotMachine_StopOrAnimWheel2: - ld a, [wStoppingWhichSlotMachineWheel] - cp 2 - jr c, .animWheel - ld de, wSlotMachineWheel2Offset - ld a, [de] - rra - jr nc, .animWheel ; check that a symbol is centred in the wheel - ld hl, wSlotMachineWheel2SlipCounter - ld a, [hl] - and a - ret z - dec [hl] - call SlotMachine_StopWheel2Early - ret z -.animWheel - jp SlotMachine_AnimWheel2 - -SlotMachine_StopOrAnimWheel3: - ld a, [wStoppingWhichSlotMachineWheel] - cp 3 - jr c, .animWheel - ld de, wSlotMachineWheel3Offset - ld a, [de] - rra - jr nc, .animWheel ; check that a symbol is centred in the wheel -; wheel 3 stops as soon as possible - scf - ret -.animWheel - call SlotMachine_AnimWheel3 - and a - ret - -SlotMachine_StopWheel1Early: - call SlotMachine_GetWheel1Tiles - ld hl, wSlotMachineWheel1BottomTile - ld a, [wSlotMachineFlags] - and $80 - jr nz, .sevenAndBarMode -; Stop early if the middle symbol is not a cherry. - inc hl - ld a, [hl] - cp SLOTSCHERRY >> 8 - jr nz, .stopWheel - ret -; It looks like this was intended to make the wheel stop when a 7 symbol was -; visible, but it has a bug and so the wheel stops randomly. -.sevenAndBarMode - ld c, $3 -.loop - ld a, [hli] - cp SLOTS7 >> 8 - jr c, .stopWheel ; condition never true - dec c - jr nz, .loop - ret -.stopWheel - inc a - ld hl, wSlotMachineWheel1SlipCounter - ld [hl], 0 - ret - -SlotMachine_StopWheel2Early: - call SlotMachine_GetWheel2Tiles - ld a, [wSlotMachineFlags] - and $80 - jr nz, .sevenAndBarMode -; Stop early if any symbols are lined up in the first two wheels. - call SlotMachine_FindWheel1Wheel2Matches - ret nz - jr .stopWheel -; Stop early if two 7 symbols or two bar symbols are lined up in the first two -; wheels OR if no symbols are lined up and the bottom symbol in wheel 2 is a -; 7 symbol or bar symbol. The second part could be a bug or a way to reduce the -; player's odds. -.sevenAndBarMode - call SlotMachine_FindWheel1Wheel2Matches - ld a, [de] - cp (SLOTSBAR >> 8) + 1 - ret nc -.stopWheel - xor a - ld [wSlotMachineWheel2SlipCounter], a - ret - -SlotMachine_FindWheel1Wheel2Matches: -; return whether wheel 1 and wheel 2's current positions allow a match (given -; that wheel 3 stops in a good position) in Z - ld hl, wSlotMachineWheel1BottomTile - ld de, wSlotMachineWheel2BottomTile - ld a, [de] - cp [hl] ; wheel 1 bottom, wheel 2 bottom - ret z - inc de - ld a, [de] - cp [hl] ; wheel 1 bottom, wheel 2 middle - ret z - inc hl - cp [hl] ; wheel 1 middle, wheel 2 middle - ret z - inc hl - cp [hl] ; wheel 1 top, wheel 2 middle - ret z - inc de - ld a, [de] - cp [hl] ; wheel 1 top, wheel 2 top - ret z - dec de - dec de - ret - -SlotMachine_CheckForMatches: - call SlotMachine_GetWheel3Tiles - ld a, [wSlotMachineBet] - cp 2 - jr z, .checkMatchesFor2CoinBet - cp 1 - jr z, .checkMatchFor1CoinBet -; 3 coin bet allows diagonal matches (plus the matches for 1/2 coin bets) - ld hl, wSlotMachineWheel1BottomTile - ld de, wSlotMachineWheel2MiddleTile - ld bc, wSlotMachineWheel3TopTile - call SlotMachine_CheckForMatch - jp z, .foundMatch - ld hl, wSlotMachineWheel1TopTile - ld de, wSlotMachineWheel2MiddleTile - ld bc, wSlotMachineWheel3BottomTile - call SlotMachine_CheckForMatch - jr z, .foundMatch -; 2 coin bet allows top/bottom horizontal matches (plus the match for a 1 coin bet) -.checkMatchesFor2CoinBet - ld hl, wSlotMachineWheel1TopTile - ld de, wSlotMachineWheel2TopTile - ld bc, wSlotMachineWheel3TopTile - call SlotMachine_CheckForMatch - jr z, .foundMatch - ld hl, wSlotMachineWheel1BottomTile - ld de, wSlotMachineWheel2BottomTile - ld bc, wSlotMachineWheel3BottomTile - call SlotMachine_CheckForMatch - jr z, .foundMatch -; 1 coin bet only allows a middle horizontal match -.checkMatchFor1CoinBet - ld hl, wSlotMachineWheel1MiddleTile - ld de, wSlotMachineWheel2MiddleTile - ld bc, wSlotMachineWheel3MiddleTile - call SlotMachine_CheckForMatch - jr z, .foundMatch - ld a, [wSlotMachineFlags] - and $c0 - jr z, .noMatch - ld hl, wSlotMachineRerollCounter - dec [hl] - jr nz, .rollWheel3DownByOneSymbol -.noMatch - ld hl, NotThisTimeText - call PrintText -.done - xor a - ld [wMuteAudioAndPauseMusic], a - ret -.rollWheel3DownByOneSymbol - call SlotMachine_AnimWheel3 - call DelayFrame - call SlotMachine_AnimWheel3 - call DelayFrame - jp SlotMachine_CheckForMatches -.foundMatch - ld a, [wSlotMachineFlags] - and $c0 - jr z, .rollWheel3DownByOneSymbol ; roll wheel if player isn't allowed to win - and $80 - jr nz, .acceptMatch -; if 7/bar matches aren't enabled and the match was a 7/bar symbol, roll wheel - ld a, [hl] - cp (SLOTSBAR >> 8) + 1 - jr c, .rollWheel3DownByOneSymbol -.acceptMatch - ld a, [hl] - sub $2 - ld [wSlotMachineWinningSymbol], a - ld hl, SlotRewardPointers - ld c, a - ld b, 0 - add hl, bc - ld a, [hli] - ld e, a - ld a, [hli] - ld d, a - push de - ld a, [hli] - ld h, [hl] - ld l, a - ld de, wcf4b - ld bc, 4 - call CopyData - pop hl - ld de, .flashScreenLoop - push de - jp hl - -.flashScreenLoop - ld a, [rBGP] - xor $40 - ld [rBGP], a - ld c, 5 - call DelayFrames - dec b - jr nz, .flashScreenLoop - ld hl, wPayoutCoins - ld [hl], d - inc hl - ld [hl], e - call SlotMachine_PrintPayoutCoins - ld hl, SymbolLinedUpSlotMachineText - call PrintText - call WaitForTextScrollButtonPress - call SlotMachine_PayCoinsToPlayer - call SlotMachine_PrintPayoutCoins - ld a, $e4 - ld [rOBP0], a - jp .done - -SymbolLinedUpSlotMachineText: - TX_ASM - push bc - call SlotMachine_PrintWinningSymbol - ld hl, LinedUpText - pop bc - inc bc - inc bc - inc bc - inc bc - ret - -LinedUpText: - TX_FAR _LinedUpText - db "@" - -SlotRewardPointers: - dw SlotReward300Func - dw SlotReward300Text - dw SlotReward100Func - dw SlotReward100Text - dw SlotReward8Func - dw SlotReward8Text - dw SlotReward15Func - dw SlotReward15Text - dw SlotReward15Func - dw SlotReward15Text - dw SlotReward15Func - dw SlotReward15Text - -SlotReward300Text: - db "300@" - -SlotReward100Text: - db "100@" - -SlotReward8Text: - db "8@" - -SlotReward15Text: - db "15@" - -NotThisTimeText: - TX_FAR _NotThisTimeText - db "@" - -; compares the slot machine tiles at bc, de, and hl -SlotMachine_CheckForMatch: - ld a, [de] - cp [hl] - ret nz - ld a, [bc] - cp [hl] - ret - -SlotMachine_GetWheel3Tiles: - ld de, wSlotMachineWheel3BottomTile - ld hl, SlotMachineWheel3 - ld a, [wSlotMachineWheel3Offset] - call SlotMachine_GetWheelTiles - -SlotMachine_GetWheel2Tiles: - ld de, wSlotMachineWheel2BottomTile - ld hl, SlotMachineWheel2 - ld a, [wSlotMachineWheel2Offset] - call SlotMachine_GetWheelTiles - -SlotMachine_GetWheel1Tiles: - ld de, wSlotMachineWheel1BottomTile - ld hl, SlotMachineWheel1 - ld a, [wSlotMachineWheel1Offset] - -SlotMachine_GetWheelTiles: - ld c, a - ld b, 0 - add hl, bc - ld c, 3 -.loop - ld a, [hli] - ld [de], a - inc de - inc hl - dec c - jr nz, .loop - ret - -SlotReward8Func: - ld hl, wSlotMachineAllowMatchesCounter - ld a, [hl] - and a - jr z, .skip - dec [hl] -.skip - ld b, $2 - ld de, 8 - ret - -SlotReward15Func: - ld hl, wSlotMachineAllowMatchesCounter - ld a, [hl] - and a - jr z, .skip - dec [hl] -.skip - ld b, $4 - ld de, 15 - ret - -SlotReward100Func: - ld a, SFX_GET_KEY_ITEM - call PlaySound - xor a - ld [wSlotMachineFlags], a - ld b, $8 - ld de, 100 - ret - -SlotReward300Func: - ld hl, YeahText - call PrintText - ld a, SFX_GET_ITEM_2 - call PlaySound - call Random - cp $80 - ld a, $0 - jr c, .skip - ld [wSlotMachineFlags], a -.skip - ld [wSlotMachineAllowMatchesCounter], a - ld b, $14 - ld de, 300 - ret - -YeahText: - TX_FAR _YeahText - TX_DELAY - db "@" - -SlotMachine_PrintWinningSymbol: -; prints winning symbol and down arrow in text box - coord hl, 2, 14 - ld a, [wSlotMachineWinningSymbol] - add $25 - ld [hli], a - inc a - ld [hld], a - inc a - ld de, -SCREEN_WIDTH - add hl, de - ld [hli], a - inc a - ld [hl], a - coord hl, 18, 16 - ld [hl], "▼" - ret - -SlotMachine_SubtractBetFromPlayerCoins: - ld hl, wTempCoins2 + 1 - ld a, [wSlotMachineBet] - ld [hld], a - xor a - ld [hli], a - ld de, wPlayerCoins + 1 - ld c, $2 - predef SubBCDPredef - -SlotMachine_PrintCreditCoins: - coord hl, 5, 1 - ld de, wPlayerCoins - ld c, $2 - jp PrintBCDNumber - -SlotMachine_PrintPayoutCoins: - coord hl, 11, 1 - ld de, wPayoutCoins - lb bc, LEADING_ZEROES | 2, 4 ; 2 bytes, 4 digits - jp PrintNumber - -SlotMachine_PayCoinsToPlayer: - ld a, $1 - ld [wMuteAudioAndPauseMusic], a - call WaitForSoundToFinish - -; Put 1 in the temp coins variable. This value is added to the player's coins -; repeatedly so the player can watch the value go up 1 coin at a time. - ld hl, wTempCoins1 - xor a - ld [hli], a - inc a - ld [hl], a - - ld a, 5 - ld [wAnimCounter], a - -; Subtract 1 from the payout amount and add 1 to the player's coins each -; iteration until the payout amount reaches 0. -.loop - ld a, [wPayoutCoins + 1] - ld l, a - ld a, [wPayoutCoins] - ld h, a - or l - ret z - ld de, -1 - add hl, de - ld a, l - ld [wPayoutCoins + 1], a - ld a, h - ld [wPayoutCoins], a - ld hl, wTempCoins1 + 1 - ld de, wPlayerCoins + 1 - ld c, $2 - predef AddBCDPredef - call SlotMachine_PrintCreditCoins - call SlotMachine_PrintPayoutCoins - ld a, SFX_SLOTS_REWARD - call PlaySound - ld a, [wAnimCounter] - dec a - jr nz, .skip1 - ld a, [rOBP0] - xor $40 ; make the slot wheel symbols flash - ld [rOBP0], a - ld a, 5 -.skip1 - ld [wAnimCounter], a - ld a, [wSlotMachineWinningSymbol] - cp (SLOTSBAR >> 8) + 1 - ld c, 8 - jr nc, .skip2 - srl c ; c = 4 (make the the coins transfer faster if the symbol was 7 or bar) -.skip2 - call DelayFrames - jr .loop - -SlotMachine_PutOutLitBalls: - ld a, $23 - ld [wNewSlotMachineBallTile], a - jr SlotMachine_UpdateThreeCoinBallTiles - -SlotMachine_LightBalls: - ld a, $14 - ld [wNewSlotMachineBallTile], a - ld a, [wSlotMachineBet] - dec a - jr z, SlotMachine_UpdateOneCoinBallTiles - dec a - jr z, SlotMachine_UpdateTwoCoinBallTiles - -SlotMachine_UpdateThreeCoinBallTiles: - coord hl, 3, 2 - call SlotMachine_UpdateBallTiles - coord hl, 3, 10 - call SlotMachine_UpdateBallTiles - -SlotMachine_UpdateTwoCoinBallTiles: - coord hl, 3, 4 - call SlotMachine_UpdateBallTiles - coord hl, 3, 8 - call SlotMachine_UpdateBallTiles - -SlotMachine_UpdateOneCoinBallTiles: - coord hl, 3, 6 - -SlotMachine_UpdateBallTiles: - ld a, [wNewSlotMachineBallTile] - ld [hl], a - ld bc, 13 - add hl, bc - ld [hl], a - ld bc, 7 - add hl, bc - inc a - ld [hl], a - ld bc, 13 - add hl, bc - ld [hl], a - ret - -SlotMachine_AnimWheel1: - ld bc, SlotMachineWheel1 - ld de, wSlotMachineWheel1Offset - ld hl, wOAMBuffer - ld a, $30 - ld [wBaseCoordX], a - jr SlotMachine_AnimWheel - -SlotMachine_AnimWheel2: - ld bc, SlotMachineWheel2 - ld de, wSlotMachineWheel2Offset - ld hl, wOAMBuffer + $30 - ld a, $50 - ld [wBaseCoordX], a - jr SlotMachine_AnimWheel - -SlotMachine_AnimWheel3: - ld bc, SlotMachineWheel3 - ld de, wSlotMachineWheel3Offset - ld hl, wOAMBuffer + $60 - ld a, $70 - ld [wBaseCoordX], a - -SlotMachine_AnimWheel: - ld a, $58 - ld [wBaseCoordY], a - push de - ld a, [de] - ld d, b - add c - ld e, a - jr nc, .loop - inc d -.loop - ld a, [wBaseCoordY] - ld [hli], a - ld a, [wBaseCoordX] - ld [hli], a - ld a, [de] - ld [hli], a - ld a, $80 - ld [hli], a - ld a, [wBaseCoordY] - ld [hli], a - ld a, [wBaseCoordX] - add $8 - ld [hli], a - ld a, [de] - inc a - ld [hli], a - ld a, $80 - ld [hli], a - inc de - ld a, [wBaseCoordY] - sub $8 - ld [wBaseCoordY], a - cp $28 - jr nz, .loop - pop de - ld a, [de] - inc a ; advance the offset so that the wheel animates - cp 30 - jr nz, .skip - xor a ; wrap around to 0 when the offset reaches 30 -.skip - ld [de], a - ret - -SlotMachine_HandleInputWhileWheelsSpin: - call DelayFrame - call JoypadLowSensitivity - ld a, [hJoy5] - and A_BUTTON - ret z - ld hl, wStoppingWhichSlotMachineWheel - ld a, [hl] - dec a - ld de, wSlotMachineWheel1SlipCounter - jr z, .skip - dec a - ld de, wSlotMachineWheel2SlipCounter - jr z, .skip -.loop - inc [hl] - ld a, SFX_SLOTS_STOP_WHEEL - jp PlaySound -.skip - ld a, [de] - and a - ret nz - jr .loop - -LoadSlotMachineTiles: - call DisableLCD - ld hl, SlotMachineTiles2 - ld de, vChars0 - ld bc, $1c0 - ld a, BANK(SlotMachineTiles2) - call FarCopyData2 - ld hl, SlotMachineTiles1 - ld de, vChars2 - ld bc, $250 - ld a, BANK(SlotMachineTiles1) - call FarCopyData2 - ld hl, SlotMachineTiles2 - ld de, vChars2 + $250 - ld bc, $1c0 - ld a, BANK(SlotMachineTiles2) - call FarCopyData2 - ld hl, SlotMachineMap - coord de, 0, 0 - ld bc, SlotMachineMapEnd - SlotMachineMap - call CopyData - call EnableLCD - ld hl, wSlotMachineWheel1Offset - ld a, $1c - ld [hli], a - ld [hli], a - ld [hl], a - call SlotMachine_AnimWheel1 - call SlotMachine_AnimWheel2 - jp SlotMachine_AnimWheel3 - -SlotMachineMap: - INCBIN "gfx/slots/slots.tilemap" -SlotMachineMapEnd: - -INCLUDE "data/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 diff --git a/engine/slots/game_corner_slots.asm b/engine/slots/game_corner_slots.asm new file mode 100755 index 00000000..2108695f --- /dev/null +++ b/engine/slots/game_corner_slots.asm @@ -0,0 +1,54 @@ +StartSlotMachine: + ld a, [wHiddenObjectFunctionArgument] + cp $fd + jr z, .printOutOfOrder + cp $fe + jr z, .printOutToLunch + cp $ff + jr z, .printSomeonesKeys + callba AbleToPlaySlotsCheck + ld a, [wCanPlaySlots] + and a + ret z + ld a, [wLuckySlotHiddenObjectIndex] + ld b, a + ld a, [wHiddenObjectIndex] + inc a + cp b + jr z, .match + ld a, 253 + jr .next +.match + ld a, 250 +.next + ld [wSlotMachineSevenAndBarModeChance], a + ld a, [H_LOADEDROMBANK] + ld [wSlotMachineSavedROMBank], a + call PromptUserToPlaySlots + ret +.printOutOfOrder + tx_pre_id GameCornerOutOfOrderText + jr .printText +.printOutToLunch + tx_pre_id GameCornerOutToLunchText + jr .printText +.printSomeonesKeys + tx_pre_id GameCornerSomeonesKeysText +.printText + push af + call EnableAutoTextBoxDrawing + pop af + call PrintPredefTextID + ret + +GameCornerOutOfOrderText:: + TX_FAR _GameCornerOutOfOrderText + db "@" + +GameCornerOutToLunchText:: + TX_FAR _GameCornerOutToLunchText + db "@" + +GameCornerSomeonesKeysText:: + TX_FAR _GameCornerSomeonesKeysText + db "@" diff --git a/engine/slots/game_corner_slots2.asm b/engine/slots/game_corner_slots2.asm new file mode 100755 index 00000000..8f6e8374 --- /dev/null +++ b/engine/slots/game_corner_slots2.asm @@ -0,0 +1,31 @@ +AbleToPlaySlotsCheck: + ld a, [wSpriteStateData1 + 2] + and $8 + jr z, .done ; not able + ld b, COIN_CASE + predef GetQuantityOfItemInBag + ld a, b + and a + ld b, (GameCornerCoinCaseText_id - TextPredefs) / 2 + 1 + jr z, .printCoinCaseRequired + ld hl, wPlayerCoins + ld a, [hli] + or [hl] + jr nz, .done ; able to play + ld b, (GameCornerNoCoinsText_id - TextPredefs) / 2 + 1 +.printCoinCaseRequired + call EnableAutoTextBoxDrawing + ld a, b + call PrintPredefTextID + xor a +.done + ld [wCanPlaySlots], a + ret + +GameCornerCoinCaseText:: + TX_FAR _GameCornerCoinCaseText + db "@" + +GameCornerNoCoinsText:: + TX_FAR _GameCornerNoCoinsText + db "@" diff --git a/engine/slots/slot_machine.asm b/engine/slots/slot_machine.asm new file mode 100755 index 00000000..0a92c69b --- /dev/null +++ b/engine/slots/slot_machine.asm @@ -0,0 +1,892 @@ +PromptUserToPlaySlots: + call SaveScreenTilesToBuffer2 + ld a, BANK(DisplayTextIDInit) + ld [wAutoTextBoxDrawingControl], a + ld b, a + ld hl, DisplayTextIDInit + call Bankswitch + ld hl, PlaySlotMachineText + call PrintText + call YesNoChoice + ld a, [wCurrentMenuItem] + and a + jr nz, .done ; if player chose No + dec a + ld [wUpdateSpritesEnabled], a + ld hl, wSlotMachineRerollCounter + xor a + ld [hli], a + ld [hl], SMILE_BUBBLE + predef EmotionBubble + call GBPalWhiteOutWithDelay3 + call LoadSlotMachineTiles + call LoadFontTilePatterns + ld b, SET_PAL_SLOTS + call RunPaletteCommand + call GBPalNormal + ld a, $e4 + ld [rOBP0], a + ld hl, wd730 + set 6, [hl] + xor a + ld [wSlotMachineAllowMatchesCounter], a + ld hl, wStoppingWhichSlotMachineWheel + ld bc, $0014 + call FillMemory + call MainSlotMachineLoop + ld hl, wd730 + res 6, [hl] + xor a + ld [wSlotMachineAllowMatchesCounter], a + call GBPalWhiteOutWithDelay3 + ld a, $1 + ld [wUpdateSpritesEnabled], a + call RunDefaultPaletteCommand + call ReloadMapSpriteTilePatterns + call ReloadTilesetTilePatterns +.done + call LoadScreenTilesFromBuffer2 + call Delay3 + call GBPalNormal + ld a, [wSlotMachineSavedROMBank] + push af + jp CloseTextDisplay + +PlaySlotMachineText: + TX_FAR _PlaySlotMachineText + db "@" + +MainSlotMachineLoop: + call SlotMachine_PrintCreditCoins + xor a + ld hl, wPayoutCoins + ld [hli], a + ld [hl], a + call SlotMachine_PrintPayoutCoins + ld hl, BetHowManySlotMachineText + call PrintText + call SaveScreenTilesToBuffer1 +.loop + ld a, A_BUTTON | B_BUTTON + ld [wMenuWatchedKeys], a + ld a, 2 + ld [wMaxMenuItem], a + ld a, 12 + ld [wTopMenuItemY], a + ld a, 15 + ld [wTopMenuItemX], a + xor a + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + ld [wMenuWatchMovingOutOfBounds], a + coord hl, 14, 11 + ld b, 5 + ld c, 4 + call TextBoxBorder + coord hl, 16, 12 + ld de, CoinMultiplierSlotMachineText + call PlaceString + call HandleMenuInput + and B_BUTTON + jp nz, LoadScreenTilesFromBuffer1 + ld a, [wCurrentMenuItem] + ld b, a + ld a, 3 + sub b + ld [wSlotMachineBet], a + ld hl, wPlayerCoins + ld c, a + ld a, [hli] + and a + jr nz, .skip1 + ld a, [hl] + cp c + jr nc, .skip1 + ld hl, NotEnoughCoinsSlotMachineText + call PrintText + jr .loop +.skip1 + call LoadScreenTilesFromBuffer1 + call SlotMachine_SubtractBetFromPlayerCoins + call SlotMachine_LightBalls + call SlotMachine_SetFlags + ld a, 4 + ld hl, wSlotMachineWheel1SlipCounter + ld [hli], a + ld [hli], a + ld [hl], a + call WaitForSoundToFinish + ld a, SFX_SLOTS_NEW_SPIN + call PlaySound + ld hl, StartSlotMachineText + call PrintText + call SlotMachine_SpinWheels + call SlotMachine_CheckForMatches + ld hl, wPlayerCoins + ld a, [hli] + or [hl] + jr nz, .skip2 + ld hl, OutOfCoinsSlotMachineText + call PrintText + ld c, 60 + jp DelayFrames +.skip2 + ld hl, OneMoreGoSlotMachineText + call PrintText + coord hl, 14, 12 + lb bc, 13, 15 + xor a ; YES_NO_MENU + ld [wTwoOptionMenuID], a + ld a, TWO_OPTION_MENU + ld [wTextBoxID], a + call DisplayTextBoxID + ld a, [wCurrentMenuItem] + and a + ret nz + call SlotMachine_PutOutLitBalls + jp MainSlotMachineLoop + +CoinMultiplierSlotMachineText: + db "×3" + next "×2" + next "×1@" + +OutOfCoinsSlotMachineText: + TX_FAR _OutOfCoinsSlotMachineText + db "@" + +BetHowManySlotMachineText: + TX_FAR _BetHowManySlotMachineText + db "@" + +StartSlotMachineText: + TX_FAR _StartSlotMachineText + db "@" + +NotEnoughCoinsSlotMachineText: + TX_FAR _NotEnoughCoinsSlotMachineText + db "@" + +OneMoreGoSlotMachineText: + TX_FAR _OneMoreGoSlotMachineText + db "@" + +SlotMachine_SetFlags: + ld hl, wSlotMachineFlags + bit 7, [hl] + ret nz + ld a, [wSlotMachineAllowMatchesCounter] + and a + jr nz, .allowMatches + call Random + and a + jr z, .setAllowMatchesCounter ; 1/256 (~0.4%) chance + ld b, a + ld a, [wSlotMachineSevenAndBarModeChance] + cp b + jr c, .allowSevenAndBarMatches + ld a, 210 + cp b + jr c, .allowMatches ; 55/256 (~21.5%) chance + ld [hl], 0 + ret +.allowMatches + set 6, [hl] + ret +.setAllowMatchesCounter + ld a, 60 + ld [wSlotMachineAllowMatchesCounter], a + ret +.allowSevenAndBarMatches + set 7, [hl] + ret + +SlotMachine_SpinWheels: + ld c, 20 +.loop1 + push bc + call SlotMachine_AnimWheel1 + call SlotMachine_AnimWheel2 + call SlotMachine_AnimWheel3 + ld c, 2 + call DelayFrames + pop bc + dec c + jr nz, .loop1 + xor a + ld [wStoppingWhichSlotMachineWheel], a +.loop2 + call SlotMachine_HandleInputWhileWheelsSpin + call SlotMachine_StopOrAnimWheel1 + call SlotMachine_StopOrAnimWheel2 + call SlotMachine_StopOrAnimWheel3 + ret c + ld a, [wOnSGB] + xor $1 + inc a + ld c, a + call DelayFrames + jr .loop2 + +; Note that the wheels can only stop when a symbol is centred in the wheel +; and thus 3 full symbols rather than 2 full symbols and 2 half symbols are +; visible. The 3 functions below ensure this by checking if the wheel offset +; is even before stopping the wheel. + +SlotMachine_StopOrAnimWheel1: + ld a, [wStoppingWhichSlotMachineWheel] + cp 1 + jr c, .animWheel + ld de, wSlotMachineWheel1Offset + ld a, [de] + rra + jr nc, .animWheel ; check that a symbol is centred in the wheel + ld hl, wSlotMachineWheel1SlipCounter + ld a, [hl] + and a + ret z + dec [hl] + call SlotMachine_StopWheel1Early + ret nz +.animWheel + jp SlotMachine_AnimWheel1 + +SlotMachine_StopOrAnimWheel2: + ld a, [wStoppingWhichSlotMachineWheel] + cp 2 + jr c, .animWheel + ld de, wSlotMachineWheel2Offset + ld a, [de] + rra + jr nc, .animWheel ; check that a symbol is centred in the wheel + ld hl, wSlotMachineWheel2SlipCounter + ld a, [hl] + and a + ret z + dec [hl] + call SlotMachine_StopWheel2Early + ret z +.animWheel + jp SlotMachine_AnimWheel2 + +SlotMachine_StopOrAnimWheel3: + ld a, [wStoppingWhichSlotMachineWheel] + cp 3 + jr c, .animWheel + ld de, wSlotMachineWheel3Offset + ld a, [de] + rra + jr nc, .animWheel ; check that a symbol is centred in the wheel +; wheel 3 stops as soon as possible + scf + ret +.animWheel + call SlotMachine_AnimWheel3 + and a + ret + +SlotMachine_StopWheel1Early: + call SlotMachine_GetWheel1Tiles + ld hl, wSlotMachineWheel1BottomTile + ld a, [wSlotMachineFlags] + and $80 + jr nz, .sevenAndBarMode +; Stop early if the middle symbol is not a cherry. + inc hl + ld a, [hl] + cp SLOTSCHERRY >> 8 + jr nz, .stopWheel + ret +; It looks like this was intended to make the wheel stop when a 7 symbol was +; visible, but it has a bug and so the wheel stops randomly. +.sevenAndBarMode + ld c, $3 +.loop + ld a, [hli] + cp SLOTS7 >> 8 + jr c, .stopWheel ; condition never true + dec c + jr nz, .loop + ret +.stopWheel + inc a + ld hl, wSlotMachineWheel1SlipCounter + ld [hl], 0 + ret + +SlotMachine_StopWheel2Early: + call SlotMachine_GetWheel2Tiles + ld a, [wSlotMachineFlags] + and $80 + jr nz, .sevenAndBarMode +; Stop early if any symbols are lined up in the first two wheels. + call SlotMachine_FindWheel1Wheel2Matches + ret nz + jr .stopWheel +; Stop early if two 7 symbols or two bar symbols are lined up in the first two +; wheels OR if no symbols are lined up and the bottom symbol in wheel 2 is a +; 7 symbol or bar symbol. The second part could be a bug or a way to reduce the +; player's odds. +.sevenAndBarMode + call SlotMachine_FindWheel1Wheel2Matches + ld a, [de] + cp (SLOTSBAR >> 8) + 1 + ret nc +.stopWheel + xor a + ld [wSlotMachineWheel2SlipCounter], a + ret + +SlotMachine_FindWheel1Wheel2Matches: +; return whether wheel 1 and wheel 2's current positions allow a match (given +; that wheel 3 stops in a good position) in Z + ld hl, wSlotMachineWheel1BottomTile + ld de, wSlotMachineWheel2BottomTile + ld a, [de] + cp [hl] ; wheel 1 bottom, wheel 2 bottom + ret z + inc de + ld a, [de] + cp [hl] ; wheel 1 bottom, wheel 2 middle + ret z + inc hl + cp [hl] ; wheel 1 middle, wheel 2 middle + ret z + inc hl + cp [hl] ; wheel 1 top, wheel 2 middle + ret z + inc de + ld a, [de] + cp [hl] ; wheel 1 top, wheel 2 top + ret z + dec de + dec de + ret + +SlotMachine_CheckForMatches: + call SlotMachine_GetWheel3Tiles + ld a, [wSlotMachineBet] + cp 2 + jr z, .checkMatchesFor2CoinBet + cp 1 + jr z, .checkMatchFor1CoinBet +; 3 coin bet allows diagonal matches (plus the matches for 1/2 coin bets) + ld hl, wSlotMachineWheel1BottomTile + ld de, wSlotMachineWheel2MiddleTile + ld bc, wSlotMachineWheel3TopTile + call SlotMachine_CheckForMatch + jp z, .foundMatch + ld hl, wSlotMachineWheel1TopTile + ld de, wSlotMachineWheel2MiddleTile + ld bc, wSlotMachineWheel3BottomTile + call SlotMachine_CheckForMatch + jr z, .foundMatch +; 2 coin bet allows top/bottom horizontal matches (plus the match for a 1 coin bet) +.checkMatchesFor2CoinBet + ld hl, wSlotMachineWheel1TopTile + ld de, wSlotMachineWheel2TopTile + ld bc, wSlotMachineWheel3TopTile + call SlotMachine_CheckForMatch + jr z, .foundMatch + ld hl, wSlotMachineWheel1BottomTile + ld de, wSlotMachineWheel2BottomTile + ld bc, wSlotMachineWheel3BottomTile + call SlotMachine_CheckForMatch + jr z, .foundMatch +; 1 coin bet only allows a middle horizontal match +.checkMatchFor1CoinBet + ld hl, wSlotMachineWheel1MiddleTile + ld de, wSlotMachineWheel2MiddleTile + ld bc, wSlotMachineWheel3MiddleTile + call SlotMachine_CheckForMatch + jr z, .foundMatch + ld a, [wSlotMachineFlags] + and $c0 + jr z, .noMatch + ld hl, wSlotMachineRerollCounter + dec [hl] + jr nz, .rollWheel3DownByOneSymbol +.noMatch + ld hl, NotThisTimeText + call PrintText +.done + xor a + ld [wMuteAudioAndPauseMusic], a + ret +.rollWheel3DownByOneSymbol + call SlotMachine_AnimWheel3 + call DelayFrame + call SlotMachine_AnimWheel3 + call DelayFrame + jp SlotMachine_CheckForMatches +.foundMatch + ld a, [wSlotMachineFlags] + and $c0 + jr z, .rollWheel3DownByOneSymbol ; roll wheel if player isn't allowed to win + and $80 + jr nz, .acceptMatch +; if 7/bar matches aren't enabled and the match was a 7/bar symbol, roll wheel + ld a, [hl] + cp (SLOTSBAR >> 8) + 1 + jr c, .rollWheel3DownByOneSymbol +.acceptMatch + ld a, [hl] + sub $2 + ld [wSlotMachineWinningSymbol], a + ld hl, SlotRewardPointers + ld c, a + ld b, 0 + add hl, bc + ld a, [hli] + ld e, a + ld a, [hli] + ld d, a + push de + ld a, [hli] + ld h, [hl] + ld l, a + ld de, wcf4b + ld bc, 4 + call CopyData + pop hl + ld de, .flashScreenLoop + push de + jp hl + +.flashScreenLoop + ld a, [rBGP] + xor $40 + ld [rBGP], a + ld c, 5 + call DelayFrames + dec b + jr nz, .flashScreenLoop + ld hl, wPayoutCoins + ld [hl], d + inc hl + ld [hl], e + call SlotMachine_PrintPayoutCoins + ld hl, SymbolLinedUpSlotMachineText + call PrintText + call WaitForTextScrollButtonPress + call SlotMachine_PayCoinsToPlayer + call SlotMachine_PrintPayoutCoins + ld a, $e4 + ld [rOBP0], a + jp .done + +SymbolLinedUpSlotMachineText: + TX_ASM + push bc + call SlotMachine_PrintWinningSymbol + ld hl, LinedUpText + pop bc + inc bc + inc bc + inc bc + inc bc + ret + +LinedUpText: + TX_FAR _LinedUpText + db "@" + +SlotRewardPointers: + dw SlotReward300Func + dw SlotReward300Text + dw SlotReward100Func + dw SlotReward100Text + dw SlotReward8Func + dw SlotReward8Text + dw SlotReward15Func + dw SlotReward15Text + dw SlotReward15Func + dw SlotReward15Text + dw SlotReward15Func + dw SlotReward15Text + +SlotReward300Text: + db "300@" + +SlotReward100Text: + db "100@" + +SlotReward8Text: + db "8@" + +SlotReward15Text: + db "15@" + +NotThisTimeText: + TX_FAR _NotThisTimeText + db "@" + +; compares the slot machine tiles at bc, de, and hl +SlotMachine_CheckForMatch: + ld a, [de] + cp [hl] + ret nz + ld a, [bc] + cp [hl] + ret + +SlotMachine_GetWheel3Tiles: + ld de, wSlotMachineWheel3BottomTile + ld hl, SlotMachineWheel3 + ld a, [wSlotMachineWheel3Offset] + call SlotMachine_GetWheelTiles + +SlotMachine_GetWheel2Tiles: + ld de, wSlotMachineWheel2BottomTile + ld hl, SlotMachineWheel2 + ld a, [wSlotMachineWheel2Offset] + call SlotMachine_GetWheelTiles + +SlotMachine_GetWheel1Tiles: + ld de, wSlotMachineWheel1BottomTile + ld hl, SlotMachineWheel1 + ld a, [wSlotMachineWheel1Offset] + +SlotMachine_GetWheelTiles: + ld c, a + ld b, 0 + add hl, bc + ld c, 3 +.loop + ld a, [hli] + ld [de], a + inc de + inc hl + dec c + jr nz, .loop + ret + +SlotReward8Func: + ld hl, wSlotMachineAllowMatchesCounter + ld a, [hl] + and a + jr z, .skip + dec [hl] +.skip + ld b, $2 + ld de, 8 + ret + +SlotReward15Func: + ld hl, wSlotMachineAllowMatchesCounter + ld a, [hl] + and a + jr z, .skip + dec [hl] +.skip + ld b, $4 + ld de, 15 + ret + +SlotReward100Func: + ld a, SFX_GET_KEY_ITEM + call PlaySound + xor a + ld [wSlotMachineFlags], a + ld b, $8 + ld de, 100 + ret + +SlotReward300Func: + ld hl, YeahText + call PrintText + ld a, SFX_GET_ITEM_2 + call PlaySound + call Random + cp $80 + ld a, $0 + jr c, .skip + ld [wSlotMachineFlags], a +.skip + ld [wSlotMachineAllowMatchesCounter], a + ld b, $14 + ld de, 300 + ret + +YeahText: + TX_FAR _YeahText + TX_DELAY + db "@" + +SlotMachine_PrintWinningSymbol: +; prints winning symbol and down arrow in text box + coord hl, 2, 14 + ld a, [wSlotMachineWinningSymbol] + add $25 + ld [hli], a + inc a + ld [hld], a + inc a + ld de, -SCREEN_WIDTH + add hl, de + ld [hli], a + inc a + ld [hl], a + coord hl, 18, 16 + ld [hl], "▼" + ret + +SlotMachine_SubtractBetFromPlayerCoins: + ld hl, wTempCoins2 + 1 + ld a, [wSlotMachineBet] + ld [hld], a + xor a + ld [hli], a + ld de, wPlayerCoins + 1 + ld c, $2 + predef SubBCDPredef + +SlotMachine_PrintCreditCoins: + coord hl, 5, 1 + ld de, wPlayerCoins + ld c, $2 + jp PrintBCDNumber + +SlotMachine_PrintPayoutCoins: + coord hl, 11, 1 + ld de, wPayoutCoins + lb bc, LEADING_ZEROES | 2, 4 ; 2 bytes, 4 digits + jp PrintNumber + +SlotMachine_PayCoinsToPlayer: + ld a, $1 + ld [wMuteAudioAndPauseMusic], a + call WaitForSoundToFinish + +; Put 1 in the temp coins variable. This value is added to the player's coins +; repeatedly so the player can watch the value go up 1 coin at a time. + ld hl, wTempCoins1 + xor a + ld [hli], a + inc a + ld [hl], a + + ld a, 5 + ld [wAnimCounter], a + +; Subtract 1 from the payout amount and add 1 to the player's coins each +; iteration until the payout amount reaches 0. +.loop + ld a, [wPayoutCoins + 1] + ld l, a + ld a, [wPayoutCoins] + ld h, a + or l + ret z + ld de, -1 + add hl, de + ld a, l + ld [wPayoutCoins + 1], a + ld a, h + ld [wPayoutCoins], a + ld hl, wTempCoins1 + 1 + ld de, wPlayerCoins + 1 + ld c, $2 + predef AddBCDPredef + call SlotMachine_PrintCreditCoins + call SlotMachine_PrintPayoutCoins + ld a, SFX_SLOTS_REWARD + call PlaySound + ld a, [wAnimCounter] + dec a + jr nz, .skip1 + ld a, [rOBP0] + xor $40 ; make the slot wheel symbols flash + ld [rOBP0], a + ld a, 5 +.skip1 + ld [wAnimCounter], a + ld a, [wSlotMachineWinningSymbol] + cp (SLOTSBAR >> 8) + 1 + ld c, 8 + jr nc, .skip2 + srl c ; c = 4 (make the the coins transfer faster if the symbol was 7 or bar) +.skip2 + call DelayFrames + jr .loop + +SlotMachine_PutOutLitBalls: + ld a, $23 + ld [wNewSlotMachineBallTile], a + jr SlotMachine_UpdateThreeCoinBallTiles + +SlotMachine_LightBalls: + ld a, $14 + ld [wNewSlotMachineBallTile], a + ld a, [wSlotMachineBet] + dec a + jr z, SlotMachine_UpdateOneCoinBallTiles + dec a + jr z, SlotMachine_UpdateTwoCoinBallTiles + +SlotMachine_UpdateThreeCoinBallTiles: + coord hl, 3, 2 + call SlotMachine_UpdateBallTiles + coord hl, 3, 10 + call SlotMachine_UpdateBallTiles + +SlotMachine_UpdateTwoCoinBallTiles: + coord hl, 3, 4 + call SlotMachine_UpdateBallTiles + coord hl, 3, 8 + call SlotMachine_UpdateBallTiles + +SlotMachine_UpdateOneCoinBallTiles: + coord hl, 3, 6 + +SlotMachine_UpdateBallTiles: + ld a, [wNewSlotMachineBallTile] + ld [hl], a + ld bc, 13 + add hl, bc + ld [hl], a + ld bc, 7 + add hl, bc + inc a + ld [hl], a + ld bc, 13 + add hl, bc + ld [hl], a + ret + +SlotMachine_AnimWheel1: + ld bc, SlotMachineWheel1 + ld de, wSlotMachineWheel1Offset + ld hl, wOAMBuffer + ld a, $30 + ld [wBaseCoordX], a + jr SlotMachine_AnimWheel + +SlotMachine_AnimWheel2: + ld bc, SlotMachineWheel2 + ld de, wSlotMachineWheel2Offset + ld hl, wOAMBuffer + $30 + ld a, $50 + ld [wBaseCoordX], a + jr SlotMachine_AnimWheel + +SlotMachine_AnimWheel3: + ld bc, SlotMachineWheel3 + ld de, wSlotMachineWheel3Offset + ld hl, wOAMBuffer + $60 + ld a, $70 + ld [wBaseCoordX], a + +SlotMachine_AnimWheel: + ld a, $58 + ld [wBaseCoordY], a + push de + ld a, [de] + ld d, b + add c + ld e, a + jr nc, .loop + inc d +.loop + ld a, [wBaseCoordY] + ld [hli], a + ld a, [wBaseCoordX] + ld [hli], a + ld a, [de] + ld [hli], a + ld a, $80 + ld [hli], a + ld a, [wBaseCoordY] + ld [hli], a + ld a, [wBaseCoordX] + add $8 + ld [hli], a + ld a, [de] + inc a + ld [hli], a + ld a, $80 + ld [hli], a + inc de + ld a, [wBaseCoordY] + sub $8 + ld [wBaseCoordY], a + cp $28 + jr nz, .loop + pop de + ld a, [de] + inc a ; advance the offset so that the wheel animates + cp 30 + jr nz, .skip + xor a ; wrap around to 0 when the offset reaches 30 +.skip + ld [de], a + ret + +SlotMachine_HandleInputWhileWheelsSpin: + call DelayFrame + call JoypadLowSensitivity + ld a, [hJoy5] + and A_BUTTON + ret z + ld hl, wStoppingWhichSlotMachineWheel + ld a, [hl] + dec a + ld de, wSlotMachineWheel1SlipCounter + jr z, .skip + dec a + ld de, wSlotMachineWheel2SlipCounter + jr z, .skip +.loop + inc [hl] + ld a, SFX_SLOTS_STOP_WHEEL + jp PlaySound +.skip + ld a, [de] + and a + ret nz + jr .loop + +LoadSlotMachineTiles: + call DisableLCD + ld hl, SlotMachineTiles2 + ld de, vChars0 + ld bc, $1c0 + ld a, BANK(SlotMachineTiles2) + call FarCopyData2 + ld hl, SlotMachineTiles1 + ld de, vChars2 + ld bc, $250 + ld a, BANK(SlotMachineTiles1) + call FarCopyData2 + ld hl, SlotMachineTiles2 + ld de, vChars2 + $250 + ld bc, $1c0 + ld a, BANK(SlotMachineTiles2) + call FarCopyData2 + ld hl, SlotMachineMap + coord de, 0, 0 + ld bc, SlotMachineMapEnd - SlotMachineMap + call CopyData + call EnableLCD + ld hl, wSlotMachineWheel1Offset + ld a, $1c + ld [hli], a + ld [hli], a + ld [hl], a + call SlotMachine_AnimWheel1 + call SlotMachine_AnimWheel2 + jp SlotMachine_AnimWheel3 + +SlotMachineMap: + INCBIN "gfx/slots/slots.tilemap" +SlotMachineMapEnd: + +INCLUDE "data/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 diff --git a/engine/special_warps.asm b/engine/special_warps.asm deleted file mode 100644 index eee85402..00000000 --- a/engine/special_warps.asm +++ /dev/null @@ -1,149 +0,0 @@ -SpecialWarpIn:: - call LoadSpecialWarpData - predef LoadTilesetHeader - ld hl, wd732 - bit 2, [hl] ; dungeon warp or fly warp? - res 2, [hl] - jr z, .next -; if dungeon warp or fly warp - ld a, [wDestinationMap] - jr .next2 -.next - bit 1, [hl] - jr z, .next3 - call EmptyFunc -.next3 - ld a, 0 -.next2 - ld b, a - ld a, [wd72d] - and a - jr nz, .next4 - ld a, b -.next4 - ld hl, wd732 - bit 4, [hl] ; dungeon warp? - ret nz -; if not dungeon warp - ld [wLastMap], a - ret - -; gets the map ID, tile block map view pointer, tileset, and coordinates -LoadSpecialWarpData: - ld a, [wd72d] - cp TRADE_CENTER - jr nz, .notTradeCenter - ld hl, TradeCenterSpec1 - ld a, [hSerialConnectionStatus] - cp USING_INTERNAL_CLOCK ; which gameboy is clocking determines who is on the left and who is on the right - jr z, .copyWarpData - ld hl, TradeCenterSpec2 - jr .copyWarpData -.notTradeCenter - cp COLOSSEUM - jr nz, .notColosseum - ld hl, ColosseumSpec1 - ld a, [hSerialConnectionStatus] - cp USING_INTERNAL_CLOCK - jr z, .copyWarpData - ld hl, ColosseumSpec2 - jr .copyWarpData -.notColosseum - ld a, [wd732] - bit 1, a - jr nz, .notFirstMap - bit 2, a - jr nz, .notFirstMap - ld hl, FirstMapSpec -.copyWarpData - ld de, wCurMap - ld c, $7 -.copyWarpDataLoop - ld a, [hli] - ld [de], a - inc de - dec c - jr nz, .copyWarpDataLoop - ld a, [hli] - ld [wCurMapTileset], a - xor a - jr .done -.notFirstMap - ld a, [wLastMap] ; this value is overwritten before it's ever read - ld hl, wd732 - bit 4, [hl] ; used dungeon warp (jumped down hole/waterfall)? - jr nz, .usedDunegonWarp - bit 6, [hl] ; return to last pokemon center (or player's house)? - res 6, [hl] - jr z, .otherDestination -; return to last pokemon center or player's house - ld a, [wLastBlackoutMap] - jr .usedFlyWarp -.usedDunegonWarp - ld hl, wd72d - res 4, [hl] - ld a, [wDungeonWarpDestinationMap] - ld b, a - ld [wCurMap], a - ld a, [wWhichDungeonWarp] - ld c, a - ld hl, DungeonWarpList - ld de, 0 - ld a, 6 - ld [wDungeonWarpDataEntrySize], a -.dungeonWarpListLoop - ld a, [hli] - cp b - jr z, .matchedDungeonWarpDestinationMap - inc hl - jr .nextDungeonWarp -.matchedDungeonWarpDestinationMap - ld a, [hli] - cp c - jr z, .matchedDungeonWarpID -.nextDungeonWarp - ld a, [wDungeonWarpDataEntrySize] - add e - ld e, a - jr .dungeonWarpListLoop -.matchedDungeonWarpID - ld hl, DungeonWarpData - add hl, de - jr .copyWarpData2 -.otherDestination - ld a, [wDestinationMap] -.usedFlyWarp - ld b, a - ld [wCurMap], a - ld hl, FlyWarpDataPtr -.flyWarpDataPtrLoop - ld a, [hli] - inc hl - cp b - jr z, .foundFlyWarpMatch - inc hl - inc hl - jr .flyWarpDataPtrLoop -.foundFlyWarpMatch - ld a, [hli] - ld h, [hl] - ld l, a -.copyWarpData2 - ld de, wCurrentTileBlockMapViewPointer - ld c, $6 -.copyWarpDataLoop2 - ld a, [hli] - ld [de], a - inc de - dec c - jr nz, .copyWarpDataLoop2 - xor a ; OVERWORLD - ld [wCurMapTileset], a -.done - ld [wYOffsetSinceLastSpecialWarp], a - ld [wXOffsetSinceLastSpecialWarp], a - ld a, $ff ; the player's coordinates have already been updated using a special warp, so don't use any of the normal warps - ld [wDestinationWarpID], a - ret - -INCLUDE "data/special_warps.asm" diff --git a/engine/status_ailments.asm b/engine/status_ailments.asm deleted file mode 100755 index 3da1fc43..00000000 --- a/engine/status_ailments.asm +++ /dev/null @@ -1,46 +0,0 @@ -PrintStatusAilment:: - ld a, [de] - bit PSN, a - jr nz, .psn - bit BRN, a - jr nz, .brn - bit FRZ, a - jr nz, .frz - bit PAR, a - jr nz, .par - and SLP - ret z - ld a, "S" - ld [hli], a - ld a, "L" - ld [hli], a - ld [hl], "P" - ret -.psn - ld a, "P" - ld [hli], a - ld a, "S" - ld [hli], a - ld [hl], "N" - ret -.brn - ld a, "B" - ld [hli], a - ld a, "R" - ld [hli], a - ld [hl], "N" - ret -.frz - ld a, "F" - ld [hli], a - ld a, "R" - ld [hli], a - ld [hl], "Z" - ret -.par - ld a, "P" - ld [hli], a - ld a, "A" - ld [hli], a - ld [hl], "R" - ret diff --git a/engine/subtract_paid_money.asm b/engine/subtract_paid_money.asm deleted file mode 100644 index fdefe3d6..00000000 --- a/engine/subtract_paid_money.asm +++ /dev/null @@ -1,17 +0,0 @@ -; subtracts the amount the player paid from their money -; OUTPUT: carry = 0(success) or 1(fail because there is not enough money) -SubtractAmountPaidFromMoney_:: - ld de, wPlayerMoney - ld hl, hMoney ; total price of items - ld c, 3 ; length of money in bytes - call StringCmp - ret c - ld de, wPlayerMoney + 2 - ld hl, hMoney + 2 ; total price of items - ld c, 3 ; length of money in bytes - predef SubBCDPredef ; subtract total price from money - ld a, MONEY_BOX - ld [wTextBoxID], a - call DisplayTextBoxID ; redraw money text box - and a - ret diff --git a/engine/test_battle.asm b/engine/test_battle.asm deleted file mode 100644 index d9dcf1fa..00000000 --- a/engine/test_battle.asm +++ /dev/null @@ -1,45 +0,0 @@ -TestBattle: - ret - -.loop - call GBPalNormal - - ; Don't mess around - ; with obedience. - ld a, %10000000 ; EARTHBADGE - ld [wObtainedBadges], a - - ld hl, wFlags_D733 - set BIT_TEST_BATTLE, [hl] - - ; Reset the party. - ld hl, wPartyCount - xor a - ld [hli], a - dec a - ld [hl], a - - ; Give the player a - ; level 20 Rhydon. - ld a, RHYDON - ld [wcf91], a - ld a, 20 - ld [wCurEnemyLVL], a - xor a - ld [wMonDataLocation], a - ld [wCurMap], a - call AddPartyMon - - ; Fight against a - ; level 20 Rhydon. - ld a, RHYDON - ld [wCurOpponent], a - - predef InitOpponent - - ; When the battle ends, - ; do it all again. - ld a, 1 - ld [wUpdateSpritesEnabled], a - ld [H_AUTOBGTRANSFERENABLED], a - jr .loop diff --git a/engine/titlescreen.asm b/engine/titlescreen.asm deleted file mode 100755 index c30f83a9..00000000 --- a/engine/titlescreen.asm +++ /dev/null @@ -1,403 +0,0 @@ -; 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 - call CopyFixedLengthText - ld hl, SonyText - ld de, wRivalName - call CopyFixedLengthText - xor a - ld [hWY], a - ld [wLetterPrintingDelayFlags], a - ld hl, wd732 - ld [hli], a - ld [hli], a - ld [hl], a - ld a, BANK(Music_TitleScreen) - ld [wAudioROMBank], a - ld [wAudioSavedROMBank], a - -DisplayTitleScreen: - call GBPalWhiteOut - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a - xor a - ld [hTilesetType], a - ld [hSCX], a - ld a, $40 - ld [hSCY], a - ld a, $90 - ld [hWY], a - call ClearScreen - call DisableLCD - call LoadFontTilePatterns - ld hl, NintendoCopyrightLogoGraphics - ld de, vTitleLogo2 + $100 - ld bc, $50 - ld a, BANK(NintendoCopyrightLogoGraphics) - call FarCopyData2 - ld hl, GamefreakLogoGraphics - ld de, vTitleLogo2 + $100 + $50 - ld bc, $90 - ld a, BANK(GamefreakLogoGraphics) - call FarCopyData2 - ld hl, PokemonLogoGraphics - ld de, vTitleLogo - ld bc, $600 - ld a, BANK(PokemonLogoGraphics) - call FarCopyData2 ; first chunk - ld hl, PokemonLogoGraphics+$600 - ld de, vTitleLogo2 - ld bc, $100 - ld a, BANK(PokemonLogoGraphics) - call FarCopyData2 ; second chunk - ld hl, Version_GFX - ld de, vChars2 + $600 - (Version_GFXEnd - Version_GFX - $50) - ld bc, Version_GFXEnd - Version_GFX - ld a, BANK(Version_GFX) - call FarCopyDataDouble - call ClearBothBGMaps - -; place tiles for pokemon logo (except for the last row) - coord hl, 2, 1 - ld a, $80 - ld de, SCREEN_WIDTH - ld c, 6 -.pokemonLogoTileLoop - ld b, $10 - push hl -.pokemonLogoTileRowLoop ; place tiles for one row - ld [hli], a - inc a - dec b - jr nz, .pokemonLogoTileRowLoop - pop hl - add hl, de - dec c - jr nz, .pokemonLogoTileLoop - -; place tiles for the last row of the pokemon logo - coord hl, 2, 7 - ld a, $31 - ld b, $10 -.pokemonLogoLastTileRowLoop - ld [hli], a - inc a - dec b - jr nz, .pokemonLogoLastTileRowLoop - - call DrawPlayerCharacter - -; put a pokeball in the player's hand - ld hl, wOAMBuffer + $28 - ld a, $74 - ld [hl], a - -; place tiles for title screen copyright - coord hl, 2, 17 - ld de, .tileScreenCopyrightTiles - ld b, $10 -.tileScreenCopyrightTilesLoop - ld a, [de] - ld [hli], a - inc de - dec b - jr nz, .tileScreenCopyrightTilesLoop - - jr .next - -.tileScreenCopyrightTiles - db $41,$42,$43,$42,$44,$42,$45,$46,$47,$48,$49,$4A,$4B,$4C,$4D,$4E ; ©'95.'96.'98 GAME FREAK inc. - -.next - call SaveScreenTilesToBuffer2 - call LoadScreenTilesFromBuffer2 - call EnableLCD -IF DEF(_RED) - ld a, CHARMANDER ; which Pokemon to show first on the title screen -ENDC -IF DEF(_BLUE) - ld a, SQUIRTLE ; which Pokemon to show first on the title screen -ENDC - - ld [wTitleMonSpecies], a - call LoadTitleMonSprite - ld a, (vBGMap0 + $300) / $100 - call TitleScreenCopyTileMapToVRAM - call SaveScreenTilesToBuffer1 - ld a, $40 - ld [hWY], a - call LoadScreenTilesFromBuffer2 - ld a, vBGMap0 / $100 - call TitleScreenCopyTileMapToVRAM - ld b, SET_PAL_TITLE_SCREEN - call RunPaletteCommand - call GBPalNormal - ld a, %11100100 - ld [rOBP0], a - -; make pokemon logo bounce up and down - ld bc, hSCY ; background scroll Y - ld hl, .TitleScreenPokemonLogoYScrolls -.bouncePokemonLogoLoop - ld a, [hli] - and a - jr z, .finishedBouncingPokemonLogo - ld d, a - cp -3 - jr nz, .skipPlayingSound - ld a, SFX_INTRO_CRASH - call PlaySound -.skipPlayingSound - ld a, [hli] - ld e, a - call .ScrollTitleScreenPokemonLogo - jr .bouncePokemonLogoLoop - -.TitleScreenPokemonLogoYScrolls: -; Controls the bouncing effect of the Pokemon logo on the title screen - db -4,16 ; y scroll amount, number of times to scroll - db 3,4 - db -3,4 - db 2,2 - db -2,2 - db 1,2 - db -1,2 - db 0 ; terminate list with 0 - -.ScrollTitleScreenPokemonLogo: -; Scrolls the Pokemon logo on the title screen to create the bouncing effect -; Scrolls d pixels e times - call DelayFrame - ld a, [bc] ; background scroll Y - add d - ld [bc], a - dec e - jr nz, .ScrollTitleScreenPokemonLogo - ret - -.finishedBouncingPokemonLogo - call LoadScreenTilesFromBuffer1 - ld c, 36 - call DelayFrames - ld a, SFX_INTRO_WHOOSH - call PlaySound - -; scroll game version in from the right - call PrintGameVersionOnTitleScreen - ld a, SCREEN_HEIGHT_PIXELS - ld [hWY], a - ld d, 144 -.scrollTitleScreenGameVersionLoop - ld h, d - ld l, 64 - call ScrollTitleScreenGameVersion - ld h, 0 - ld l, 80 - call ScrollTitleScreenGameVersion - ld a, d - add 4 - ld d, a - and a - jr nz, .scrollTitleScreenGameVersionLoop - - ld a, vBGMap1 / $100 - call TitleScreenCopyTileMapToVRAM - call LoadScreenTilesFromBuffer2 - call PrintGameVersionOnTitleScreen - call Delay3 - call WaitForSoundToFinish - ld a, MUSIC_TITLE_SCREEN - ld [wNewSoundID], a - call PlaySound - xor a - ld [wUnusedCC5B], a - -; Keep scrolling in new mons indefinitely until the user performs input. -.awaitUserInterruptionLoop - ld c, 200 - call CheckForUserInterruption - jr c, .finishedWaiting - call TitleScreenScrollInMon - ld c, 1 - call CheckForUserInterruption - jr c, .finishedWaiting - callba TitleScreenAnimateBallIfStarterOut - call TitleScreenPickNewMon - jr .awaitUserInterruptionLoop - -.finishedWaiting - ld a, [wTitleMonSpecies] - call PlayCry - call WaitForSoundToFinish - call GBPalWhiteOutWithDelay3 - call ClearSprites - xor a - ld [hWY], a - inc a - ld [H_AUTOBGTRANSFERENABLED], a - call ClearScreen - ld a, vBGMap0 / $100 - call TitleScreenCopyTileMapToVRAM - ld a, vBGMap1 / $100 - call TitleScreenCopyTileMapToVRAM - call Delay3 - call LoadGBPal - ld a, [hJoyHeld] - ld b, a - and D_UP | SELECT | B_BUTTON - cp D_UP | SELECT | B_BUTTON - jp z, .doClearSaveDialogue - jp MainMenu - -.doClearSaveDialogue - jpba DoClearSaveDialogue - -TitleScreenPickNewMon: - ld a, vBGMap0 / $100 - call TitleScreenCopyTileMapToVRAM - -.loop -; Keep looping until a mon different from the current one is picked. - call Random - and $f - ld c, a - ld b, 0 - ld hl, TitleMons - add hl, bc - ld a, [hl] - ld hl, wTitleMonSpecies - -; Can't be the same as before. - cp [hl] - jr z, .loop - - ld [hl], a - call LoadTitleMonSprite - - ld a, $90 - ld [hWY], a - ld d, 1 ; scroll out - callba TitleScroll - ret - -TitleScreenScrollInMon: - ld d, 0 ; scroll in - callba TitleScroll - xor a - ld [hWY], a - ret - -ScrollTitleScreenGameVersion: -.wait - ld a, [rLY] - cp l - jr nz, .wait - - ld a, h - ld [rSCX], a - -.wait2 - ld a, [rLY] - cp h - jr z, .wait2 - ret - -DrawPlayerCharacter: - ld hl, PlayerCharacterTitleGraphics - ld de, vSprites - ld bc, PlayerCharacterTitleGraphicsEnd - PlayerCharacterTitleGraphics - ld a, BANK(PlayerCharacterTitleGraphics) - call FarCopyData2 - call ClearSprites - xor a - ld [wPlayerCharacterOAMTile], a - ld hl, wOAMBuffer - ld de, $605a - ld b, 7 -.loop - push de - ld c, 5 -.innerLoop - ld a, d - ld [hli], a ; Y - ld a, e - ld [hli], a ; X - add 8 - ld e, a - ld a, [wPlayerCharacterOAMTile] - ld [hli], a ; tile - 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 - -ClearBothBGMaps: - ld hl, vBGMap0 - ld bc, $400 * 2 - ld a, " " - jp FillMemory - -LoadTitleMonSprite: - ld [wcf91], a - ld [wd0b5], a - coord hl, 5, 10 - call GetMonHeader - jp LoadFrontSpriteByMonIndex - -TitleScreenCopyTileMapToVRAM: - ld [H_AUTOBGTRANSFERDEST + 1], a - jp Delay3 - -LoadCopyrightAndTextBoxTiles: - xor a - ld [hWY], a - call ClearScreen - call LoadTextBoxTilePatterns - -LoadCopyrightTiles: - ld de, NintendoCopyrightLogoGraphics - ld hl, vChars2 + $600 - lb bc, BANK(NintendoCopyrightLogoGraphics), (GamefreakLogoGraphicsEnd - NintendoCopyrightLogoGraphics) / $10 - call CopyVideoData - coord hl, 2, 7 - ld de, CopyrightTextString - jp PlaceString - -CopyrightTextString: - db $60,$61,$62,$61,$63,$61,$64,$7F,$65,$66,$67,$68,$69,$6A ; ©'95.'96.'98 Nintendo - next $60,$61,$62,$61,$63,$61,$64,$7F,$6B,$6C,$6D,$6E,$6F,$70,$71,$72 ; ©'95.'96.'98 Creatures inc. - next $60,$61,$62,$61,$63,$61,$64,$7F,$73,$74,$75,$76,$77,$78,$79,$7A,$7B ; ©'95.'96.'98 GAME FREAK inc. - db "@" - -INCLUDE "data/title_mons.asm" - -; prints version text (red, blue) -PrintGameVersionOnTitleScreen: - coord hl, 7, 8 - ld de, VersionOnTitleScreenText - jp PlaceString - -; 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 - -NintenText: db "NINTEN@" -SonyText: db "SONY@" diff --git a/engine/titlescreen2.asm b/engine/titlescreen2.asm deleted file mode 100755 index 2346fcc5..00000000 --- a/engine/titlescreen2.asm +++ /dev/null @@ -1,120 +0,0 @@ -TitleScroll_WaitBall: -; Wait around for the TitleBall animation to play out. -; hi: speed -; lo: duration - db $05, $05, 0 - -TitleScroll_In: -; Scroll a TitleMon in from the right. -; hi: speed -; lo: duration - db $a2, $94, $84, $63, $52, $31, $11, 0 - -TitleScroll_Out: -; Scroll a TitleMon out to the left. -; hi: speed -; lo: duration - db $12, $22, $32, $42, $52, $62, $83, $93, 0 - -TitleScroll: - ld a, d - - ld bc, TitleScroll_In - ld d, $88 - ld e, 0 ; don't animate titleball - - and a - jr nz, .ok - - ld bc, TitleScroll_Out - ld d, $00 - ld e, 0 ; don't animate titleball -.ok - -_TitleScroll: - ld a, [bc] - and a - ret z - - inc bc - push bc - - ld b, a - and $f - ld c, a - ld a, b - and $f0 - swap a - ld b, a - -.loop - ld h, d - ld l, $48 - call .ScrollBetween - - ld h, $00 - ld l, $88 - call .ScrollBetween - - ld a, d - add b - ld d, a - - call GetTitleBallY - dec c - jr nz, .loop - - pop bc - jr _TitleScroll - -.ScrollBetween: -.wait - ld a, [rLY] ; rLY - cp l - jr nz, .wait - - ld a, h - ld [rSCX], a - -.wait2 - ld a, [rLY] ; rLY - cp h - jr z, .wait2 - ret - -TitleBallYTable: -; OBJ y-positions for the Poke Ball held by Red in the title screen. -; This is really two 0-terminated lists. Initiated with an index of 1. - db 0, $71, $6f, $6e, $6d, $6c, $6d, $6e, $6f, $71, $74, 0 - -TitleScreenAnimateBallIfStarterOut: -; Animate the TitleBall if a starter just got scrolled out. - ld a, [wTitleMonSpecies] - cp STARTER1 - jr z, .ok - cp STARTER2 - jr z, .ok - cp STARTER3 - ret nz -.ok - ld e, 1 ; animate titleball - ld bc, TitleScroll_WaitBall - ld d, 0 - jp _TitleScroll - -GetTitleBallY: -; Get position e from TitleBallYTable - push de - push hl - xor a - ld d, a - ld hl, TitleBallYTable - add hl, de - ld a, [hl] - pop hl - pop de - and a - ret z - ld [wOAMBuffer + $28], a - inc e - ret diff --git a/engine/town_map.asm b/engine/town_map.asm deleted file mode 100755 index 84a92994..00000000 --- a/engine/town_map.asm +++ /dev/null @@ -1,618 +0,0 @@ -DisplayTownMap: - call LoadTownMap - ld hl, wUpdateSpritesEnabled - ld a, [hl] - push af - ld [hl], $ff - push hl - ld a, $1 - ld [hJoy7], a - ld a, [wCurMap] - push af - ld b, $0 - call DrawPlayerOrBirdSprite ; player sprite - coord hl, 1, 0 - ld de, wcd6d - call PlaceString - ld hl, wOAMBuffer - ld de, wTileMapBackup - ld bc, $10 - call CopyData - ld hl, vSprites + $40 - ld de, TownMapCursor - lb bc, BANK(TownMapCursor), (TownMapCursorEnd - TownMapCursor) / $8 - call CopyVideoDataDouble - xor a - ld [wWhichTownMapLocation], a - pop af - jr .enterLoop - -.townMapLoop - coord hl, 0, 0 - lb bc, 1, 20 - call ClearScreenArea - ld hl, TownMapOrder - ld a, [wWhichTownMapLocation] - ld c, a - ld b, 0 - add hl, bc - ld a, [hl] -.enterLoop - ld de, wTownMapCoords - call LoadTownMapEntry - ld a, [de] - push hl - call TownMapCoordsToOAMCoords - ld a, $4 - ld [wOAMBaseTile], a - ld hl, wOAMBuffer + $10 - call WriteTownMapSpriteOAM ; town map cursor sprite - pop hl - ld de, wcd6d -.copyMapName - ld a, [hli] - ld [de], a - inc de - cp $50 - jr nz, .copyMapName - coord hl, 1, 0 - ld de, wcd6d - call PlaceString - ld hl, wOAMBuffer + $10 - ld de, wTileMapBackup + 16 - ld bc, $10 - call CopyData -.inputLoop - call TownMapSpriteBlinkingAnimation - call JoypadLowSensitivity - ld a, [hJoy5] - ld b, a - and A_BUTTON | B_BUTTON | D_UP | D_DOWN - jr z, .inputLoop - ld a, SFX_TINK - call PlaySound - bit 6, b - jr nz, .pressedUp - bit 7, b - jr nz, .pressedDown - xor a - ld [wTownMapSpriteBlinkingEnabled], a - ld [hJoy7], a - ld [wAnimCounter], a - call ExitTownMap - pop hl - pop af - ld [hl], a - ret -.pressedUp - ld a, [wWhichTownMapLocation] - inc a - cp TownMapOrderEnd - TownMapOrder ; number of list items + 1 - jr nz, .noOverflow - xor a -.noOverflow - ld [wWhichTownMapLocation], a - jp .townMapLoop -.pressedDown - ld a, [wWhichTownMapLocation] - dec a - cp -1 - jr nz, .noUnderflow - ld a, TownMapOrderEnd - TownMapOrder - 1 ; number of list items -.noUnderflow - ld [wWhichTownMapLocation], a - jp .townMapLoop - -INCLUDE "data/town_map_order.asm" - -TownMapCursor: - INCBIN "gfx/town_map/town_map_cursor.1bpp" -TownMapCursorEnd: - -LoadTownMap_Nest: - call LoadTownMap - ld hl, wUpdateSpritesEnabled - ld a, [hl] - push af - ld [hl], $ff - push hl - call DisplayWildLocations - call GetMonName - coord hl, 1, 0 - call PlaceString - ld h, b - ld l, c - ld de, MonsNestText - call PlaceString - call WaitForTextScrollButtonPress - call ExitTownMap - pop hl - pop af - ld [hl], a - ret - -MonsNestText: - db "'s NEST@" - -LoadTownMap_Fly:: - call ClearSprites - call LoadTownMap - call LoadPlayerSpriteGraphics - call LoadFontTilePatterns - ld de, BirdSprite - ld hl, vSprites + $40 - lb bc, BANK(BirdSprite), $c - call CopyVideoData - ld de, TownMapUpArrow - ld hl, vChars1 + $6d0 - lb bc, BANK(TownMapUpArrow), (TownMapUpArrowEnd - TownMapUpArrow) / $8 - call CopyVideoDataDouble - call BuildFlyLocationsList - ld hl, wUpdateSpritesEnabled - ld a, [hl] - push af - ld [hl], $ff - push hl - coord hl, 0, 0 - ld de, ToText - call PlaceString - ld a, [wCurMap] - ld b, $0 - call DrawPlayerOrBirdSprite - ld hl, wFlyLocationsList - coord de, 18, 0 -.townMapFlyLoop - ld a, " " - ld [de], a - push hl - push hl - coord hl, 3, 0 - lb bc, 1, 15 - call ClearScreenArea - pop hl - ld a, [hl] - ld b, $4 - call DrawPlayerOrBirdSprite ; draw bird sprite - coord hl, 3, 0 - ld de, wcd6d - call PlaceString - ld c, 15 - call DelayFrames - coord hl, 18, 0 - ld [hl], "▲" - coord hl, 19, 0 - ld [hl], "▼" - pop hl -.inputLoop - push hl - call DelayFrame - call JoypadLowSensitivity - ld a, [hJoy5] - ld b, a - pop hl - and A_BUTTON | B_BUTTON | D_UP | D_DOWN - jr z, .inputLoop - bit 0, b - jr nz, .pressedA - ld a, SFX_TINK - call PlaySound - bit 6, b - jr nz, .pressedUp - bit 7, b - jr nz, .pressedDown - jr .pressedB -.pressedA - ld a, SFX_HEAL_AILMENT - call PlaySound - ld a, [hl] - ld [wDestinationMap], a - ld hl, wd732 - set 3, [hl] - inc hl - set 7, [hl] -.pressedB - xor a - ld [wTownMapSpriteBlinkingEnabled], a - call GBPalWhiteOutWithDelay3 - pop hl - pop af - ld [hl], a - ret -.pressedUp - coord de, 18, 0 - inc hl - ld a, [hl] - cp $ff - jr z, .wrapToStartOfList - cp $fe - jr z, .pressedUp ; skip past unvisited towns - jp .townMapFlyLoop -.wrapToStartOfList - ld hl, wFlyLocationsList - jp .townMapFlyLoop -.pressedDown - coord de, 19, 0 - dec hl - ld a, [hl] - cp $ff - jr z, .wrapToEndOfList - cp $fe - jr z, .pressedDown ; skip past unvisited towns - jp .townMapFlyLoop -.wrapToEndOfList - ld hl, wFlyLocationsList + 11 - jr .pressedDown - -ToText: - db "To@" - -BuildFlyLocationsList: - ld hl, wFlyLocationsList - 1 - ld [hl], $ff - inc hl - ld a, [wTownVisitedFlag] - ld e, a - ld a, [wTownVisitedFlag + 1] - ld d, a - ld bc, SAFFRON_CITY + 1 -.loop - srl d - rr e - ld a, $fe ; store $fe if the town hasn't been visited - jr nc, .notVisited - ld a, b ; store the map number of the town if it has been visited -.notVisited - ld [hl], a - inc hl - inc b - dec c - jr nz, .loop - ld [hl], $ff - ret - -TownMapUpArrow: - INCBIN "gfx/town_map/up_arrow.1bpp" -TownMapUpArrowEnd: - -LoadTownMap: - call GBPalWhiteOutWithDelay3 - call ClearScreen - call UpdateSprites - coord hl, 0, 0 - ld b, $12 - ld c, $12 - call TextBoxBorder - call DisableLCD - ld hl, WorldMapTileGraphics - ld de, vChars2 + $600 - ld bc, WorldMapTileGraphicsEnd - WorldMapTileGraphics - ld a, BANK(WorldMapTileGraphics) - call FarCopyData2 - ld hl, MonNestIcon - ld de, vSprites + $40 - ld bc, MonNestIconEnd - MonNestIcon - ld a, BANK(MonNestIcon) - call FarCopyDataDouble - coord hl, 0, 0 - ld de, CompressedMap -.nextTile - ld a, [de] - and a - jr z, .done - ld b, a - and $f - ld c, a - ld a, b - swap a - and $f - add $60 -.writeRunLoop - ld [hli], a - dec c - jr nz, .writeRunLoop - inc de - jr .nextTile -.done - call EnableLCD - ld b, SET_PAL_TOWN_MAP - call RunPaletteCommand - call Delay3 - call GBPalNormal - xor a - ld [wAnimCounter], a - inc a - ld [wTownMapSpriteBlinkingEnabled], a - ret - -CompressedMap: - INCBIN "gfx/town_map/town_map.rle" - -ExitTownMap: -; clear town map graphics data and load usual graphics data - xor a - ld [wTownMapSpriteBlinkingEnabled], a - call GBPalWhiteOut - call ClearScreen - call ClearSprites - call LoadPlayerSpriteGraphics - call LoadFontTilePatterns - call UpdateSprites - jp RunDefaultPaletteCommand - -DrawPlayerOrBirdSprite: -; a = map number -; b = OAM base tile - push af - ld a, b - ld [wOAMBaseTile], a - pop af - ld de, wTownMapCoords - call LoadTownMapEntry - ld a, [de] - push hl - call TownMapCoordsToOAMCoords - call WritePlayerOrBirdSpriteOAM - pop hl - ld de, wcd6d -.loop - ld a, [hli] - ld [de], a - inc de - cp "@" - jr nz, .loop - ld hl, wOAMBuffer - ld de, wTileMapBackup - ld bc, $a0 - jp CopyData - -DisplayWildLocations: - callba FindWildLocationsOfMon - call ZeroOutDuplicatesInList - ld hl, wOAMBuffer - ld de, wTownMapCoords -.loop - ld a, [de] - cp $ff - jr z, .exitLoop - and a - jr z, .nextEntry - push hl - call LoadTownMapEntry - pop hl - ld a, [de] - cp $19 ; Cerulean Cave's coordinates - jr z, .nextEntry ; skip Cerulean Cave - call TownMapCoordsToOAMCoords - ld a, $4 ; nest icon tile no. - ld [hli], a - xor a - ld [hli], a -.nextEntry - inc de - jr .loop -.exitLoop - ld a, l - and a ; were any OAM entries written? - jr nz, .drawPlayerSprite -; if no OAM entries were written, print area unknown text - coord hl, 1, 7 - ld b, 2 - ld c, 15 - call TextBoxBorder - coord hl, 2, 9 - ld de, AreaUnknownText - call PlaceString - jr .done -.drawPlayerSprite - ld a, [wCurMap] - ld b, $0 - call DrawPlayerOrBirdSprite -.done - ld hl, wOAMBuffer - ld de, wTileMapBackup - ld bc, $a0 - jp CopyData - -AreaUnknownText: - db " AREA UNKNOWN@" - -TownMapCoordsToOAMCoords: -; in: lower nybble of a = x, upper nybble of a = y -; out: b and [hl] = (y * 8) + 24, c and [hl+1] = (x * 8) + 24 - push af - and $f0 - srl a - add 24 - ld b, a - ld [hli], a - pop af - and $f - swap a - srl a - add 24 - ld c, a - ld [hli], a - ret - -WritePlayerOrBirdSpriteOAM: - ld a, [wOAMBaseTile] - and a - ld hl, wOAMBuffer + $90 ; for player sprite - jr z, WriteTownMapSpriteOAM - ld hl, wOAMBuffer + $80 ; for bird sprite - -WriteTownMapSpriteOAM: - push hl - -; Subtract 4 from c (X coord) and 4 from b (Y coord). However, the carry from c -; is added to b, so the net result is that only 3 is subtracted from b. - lb hl, -4, -4 - add hl, bc - - ld b, h - ld c, l - pop hl - -WriteAsymmetricMonPartySpriteOAM: -; Writes 4 OAM blocks for a helix mon party sprite, since it does not have -; a vertical line of symmetry. - lb de, 2, 2 -.loop - push de - push bc -.innerLoop - ld a, b - ld [hli], a - ld a, c - ld [hli], a - ld a, [wOAMBaseTile] - ld [hli], a - inc a - ld [wOAMBaseTile], a - xor a - ld [hli], a - inc d - ld a, 8 - add c - ld c, a - dec e - jr nz, .innerLoop - pop bc - pop de - ld a, 8 - add b - ld b, a - dec d - jr nz, .loop - ret - -WriteSymmetricMonPartySpriteOAM: -; Writes 4 OAM blocks for a mon party sprite other than a helix. All the -; sprites other than the helix one have a vertical line of symmetry which allows -; the X-flip OAM bit to be used so that only 2 rather than 4 tile patterns are -; needed. - xor a - ld [wSymmetricSpriteOAMAttributes], a - lb de, 2, 2 -.loop - push de - push bc -.innerLoop - ld a, b - ld [hli], a ; Y - ld a, c - ld [hli], a ; X - ld a, [wOAMBaseTile] - ld [hli], a ; tile - ld a, [wSymmetricSpriteOAMAttributes] - ld [hli], a ; attributes - xor (1 << OAM_X_FLIP) - ld [wSymmetricSpriteOAMAttributes], a - inc d - ld a, 8 - add c - ld c, a - dec e - jr nz, .innerLoop - pop bc - pop de - push hl - ld hl, wOAMBaseTile - inc [hl] - inc [hl] - pop hl - ld a, 8 - add b - ld b, a - dec d - jr nz, .loop - ret - -ZeroOutDuplicatesInList: -; replace duplicate bytes in the list of wild pokemon locations with 0 - ld de, wBuffer -.loop - ld a, [de] - inc de - cp $ff - ret z - ld c, a - ld l, e - ld h, d -.zeroDuplicatesLoop - ld a, [hl] - cp $ff - jr z, .loop - cp c - jr nz, .skipZeroing - xor a - ld [hl], a -.skipZeroing - inc hl - jr .zeroDuplicatesLoop - -LoadTownMapEntry: -; in: a = map number -; out: lower nybble of [de] = x, upper nybble of [de] = y, hl = address of name - cp REDS_HOUSE_1F - jr c, .external - ld bc, 4 - ld hl, InternalMapEntries -.loop - cp [hl] - jr c, .foundEntry - add hl, bc - jr .loop -.foundEntry - inc hl - jr .readEntry -.external - ld hl, ExternalMapEntries - ld c, a - ld b, 0 - add hl, bc - add hl, bc - add hl, bc -.readEntry - ld a, [hli] - ld [de], a - ld a, [hli] - ld h, [hl] - ld l, a - ret - -INCLUDE "data/town_map_entries.asm" - -INCLUDE "text/map_names.asm" - -MonNestIcon: - INCBIN "gfx/town_map/mon_nest_icon.1bpp" -MonNestIconEnd: - -TownMapSpriteBlinkingAnimation:: - ld a, [wAnimCounter] - inc a - cp 25 - jr z, .hideSprites - cp 50 - jr nz, .done -; show sprites when the counter reaches 50 - ld hl, wTileMapBackup - ld de, wOAMBuffer - ld bc, $90 - call CopyData - xor a - jr .done -.hideSprites - ld hl, wOAMBuffer - ld b, $24 - ld de, $4 -.hideSpritesLoop - ld [hl], $a0 - add hl, de - dec b - jr nz, .hideSpritesLoop - ld a, 25 -.done - ld [wAnimCounter], a - jp DelayFrame diff --git a/engine/trade.asm b/engine/trade.asm deleted file mode 100755 index 8bc8e3bc..00000000 --- a/engine/trade.asm +++ /dev/null @@ -1,853 +0,0 @@ -InternalClockTradeAnim: -; Do the trading animation with the player's gameboy on the left. -; In-game trades and internally clocked link cable trades use this. - ld a, [wTradedPlayerMonSpecies] - ld [wLeftGBMonSpecies], a - ld a, [wTradedEnemyMonSpecies] - ld [wRightGBMonSpecies], a - ld de, InternalClockTradeFuncSequence - jr TradeAnimCommon - -ExternalClockTradeAnim: -; Do the trading animation with the player's gameboy on the right. -; Externally clocked link cable trades use this. - ld a, [wTradedEnemyMonSpecies] - ld [wLeftGBMonSpecies], a - ld a, [wTradedPlayerMonSpecies] - ld [wRightGBMonSpecies], a - ld de, ExternalClockTradeFuncSequence - -TradeAnimCommon: - ld a, [wOptions] - push af - ld a, [hSCY] - push af - ld a, [hSCX] - push af - xor a - ld [wOptions], a - ld [hSCY], a - ld [hSCX], a - push de -.loop - pop de - ld a, [de] - cp $ff - jr z, .done - inc de - push de - ld hl, TradeFuncPointerTable - add a - ld c, a - ld b, $0 - add hl, bc - ld a, [hli] - ld h, [hl] - ld l, a - ld de, .loop - push de - jp hl ; call trade func, which will return to the top of the loop -.done - pop af - ld [hSCX], a - pop af - ld [hSCY], a - pop af - ld [wOptions], a - ret - -addtradefunc: MACRO -\1TradeFunc:: - dw \1 - ENDM - -tradefunc: MACRO - db (\1TradeFunc - TradeFuncPointerTable) / 2 - ENDM - -; The functions in the sequences below are executed in order by TradeFuncCommon. -; They are from opposite perspectives. The external clock one makes use of -; Trade_SwapNames to swap the player and enemy names for some functions. - -InternalClockTradeFuncSequence: - tradefunc LoadTradingGFXAndMonNames - tradefunc Trade_ShowPlayerMon - tradefunc Trade_DrawOpenEndOfLinkCable - tradefunc Trade_AnimateBallEnteringLinkCable - tradefunc Trade_AnimLeftToRight - tradefunc Trade_Delay100 - tradefunc Trade_ShowClearedWindow - tradefunc PrintTradeWentToText - tradefunc PrintTradeForSendsText - tradefunc PrintTradeFarewellText - tradefunc Trade_AnimRightToLeft - tradefunc Trade_ShowClearedWindow - tradefunc Trade_DrawOpenEndOfLinkCable - tradefunc Trade_ShowEnemyMon - tradefunc Trade_Delay100 - tradefunc Trade_Cleanup - db $FF - -ExternalClockTradeFuncSequence: - tradefunc LoadTradingGFXAndMonNames - tradefunc Trade_ShowClearedWindow - tradefunc PrintTradeWillTradeText - tradefunc PrintTradeFarewellText - tradefunc Trade_SwapNames - tradefunc Trade_AnimLeftToRight - tradefunc Trade_SwapNames - tradefunc Trade_ShowClearedWindow - tradefunc Trade_DrawOpenEndOfLinkCable - tradefunc Trade_ShowEnemyMon - tradefunc Trade_SlideTextBoxOffScreen - tradefunc Trade_ShowPlayerMon - tradefunc Trade_DrawOpenEndOfLinkCable - tradefunc Trade_AnimateBallEnteringLinkCable - tradefunc Trade_SwapNames - tradefunc Trade_AnimRightToLeft - tradefunc Trade_SwapNames - tradefunc Trade_Delay100 - tradefunc Trade_ShowClearedWindow - tradefunc PrintTradeWentToText - tradefunc Trade_Cleanup - db $FF - -TradeFuncPointerTable: - addtradefunc LoadTradingGFXAndMonNames - addtradefunc Trade_ShowPlayerMon - addtradefunc Trade_DrawOpenEndOfLinkCable - addtradefunc Trade_AnimateBallEnteringLinkCable - addtradefunc Trade_ShowEnemyMon - addtradefunc Trade_AnimLeftToRight - addtradefunc Trade_AnimRightToLeft - addtradefunc Trade_Delay100 - addtradefunc Trade_ShowClearedWindow - addtradefunc PrintTradeWentToText - addtradefunc PrintTradeForSendsText - addtradefunc PrintTradeFarewellText - addtradefunc PrintTradeTakeCareText - addtradefunc PrintTradeWillTradeText - addtradefunc Trade_Cleanup - addtradefunc Trade_SlideTextBoxOffScreen - addtradefunc Trade_SwapNames - -Trade_Delay100: - ld c, 100 - jp DelayFrames - -Trade_CopyTileMapToVRAM: - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a - call Delay3 - xor a - ld [H_AUTOBGTRANSFERENABLED], a - ret - -Trade_Delay80: - ld c, 80 - jp DelayFrames - -Trade_ClearTileMap: - coord hl, 0, 0 - ld bc, SCREEN_WIDTH * SCREEN_HEIGHT - ld a, " " - jp FillMemory - -LoadTradingGFXAndMonNames: - call Trade_ClearTileMap - call DisableLCD - ld hl, TradingAnimationGraphics - ld de, vChars2 + $310 - ld bc, TradingAnimationGraphicsEnd - TradingAnimationGraphics - ld a, BANK(TradingAnimationGraphics) - call FarCopyData2 - ld hl, TradingAnimationGraphics2 - ld de, vSprites + $7c0 - ld bc, TradingAnimationGraphics2End - TradingAnimationGraphics2 - ld a, BANK(TradingAnimationGraphics2) - call FarCopyData2 - ld hl, vBGMap0 - ld bc, $800 - ld a, " " - call FillMemory - call ClearSprites - ld a, $ff - ld [wUpdateSpritesEnabled], a - ld hl, wd730 - set 6, [hl] ; turn on instant text printing - ld a, [wOnSGB] - and a - ld a, $e4 ; non-SGB OBP0 - jr z, .next - ld a, $f0 ; SGB OBP0 -.next - ld [rOBP0], a - call EnableLCD - xor a - ld [H_AUTOBGTRANSFERENABLED], a - ld a, [wTradedPlayerMonSpecies] - ld [wd11e], a - call GetMonName - ld hl, wcd6d - ld de, wcf4b - ld bc, NAME_LENGTH - call CopyData - ld a, [wTradedEnemyMonSpecies] - ld [wd11e], a - jp GetMonName - -Trade_LoadMonPartySpriteGfx: - ld a, %11010000 - ld [rOBP1], a - jpba LoadMonPartySpriteGfx - -Trade_SwapNames: - ld hl, wPlayerName - ld de, wBuffer - ld bc, NAME_LENGTH - call CopyData - ld hl, wLinkEnemyTrainerName - ld de, wPlayerName - ld bc, NAME_LENGTH - call CopyData - ld hl, wBuffer - ld de, wLinkEnemyTrainerName - ld bc, NAME_LENGTH - jp CopyData - -Trade_Cleanup: - xor a - call LoadGBPal - ld hl, wd730 - res 6, [hl] ; turn off instant text printing - ret - -Trade_ShowPlayerMon: - ld a, %10101011 - ld [rLCDC], a - ld a, $50 - ld [hWY], a - ld a, $86 - ld [rWX], a - ld [hSCX], a - xor a - ld [H_AUTOBGTRANSFERENABLED], a - coord hl, 4, 0 - ld b, 6 - ld c, 10 - call TextBoxBorder - call Trade_PrintPlayerMonInfoText - ld b, vBGMap0 / $100 - call CopyScreenTileBufferToVRAM - call ClearScreen - ld a, [wTradedPlayerMonSpecies] - call Trade_LoadMonSprite - ld a, $7e -.slideScreenLoop - push af - call DelayFrame - pop af - ld [rWX], a - ld [hSCX], a - dec a - dec a - and a - jr nz, .slideScreenLoop - call Trade_Delay80 - ld a, TRADE_BALL_POOF_ANIM - call Trade_ShowAnimation - ld a, TRADE_BALL_DROP_ANIM - call Trade_ShowAnimation ; clears mon pic - ld a, [wTradedPlayerMonSpecies] - call PlayCry - xor a - ld [H_AUTOBGTRANSFERENABLED], a - ret - -Trade_DrawOpenEndOfLinkCable: - call Trade_ClearTileMap - ld b, vBGMap0 / $100 - call CopyScreenTileBufferToVRAM - ld b, SET_PAL_GENERIC - call RunPaletteCommand - -; This function call is pointless. It just copies blank tiles to VRAM that was -; already filled with blank tiles. - ld hl, vBGMap1 + $8c - call Trade_CopyCableTilesOffScreen - - ld a, $a0 - ld [hSCX], a - call DelayFrame - ld a, %10001011 - ld [rLCDC], a - coord hl, 6, 2 - ld b, $7 ; open end of link cable tile ID list index - call CopyTileIDsFromList_ZeroBaseTileID - call Trade_CopyTileMapToVRAM - ld a, SFX_HEAL_HP - call PlaySound - ld c, 20 -.loop - ld a, [hSCX] - add 4 - ld [hSCX], a - dec c - jr nz, .loop - ret - -Trade_AnimateBallEnteringLinkCable: - ld a, TRADE_BALL_SHAKE_ANIM - call Trade_ShowAnimation - ld c, 10 - call DelayFrames - ld a, %11100100 - ld [rOBP0], a - xor a - ld [wLinkCableAnimBulgeToggle], a - lb bc, $20, $60 -.moveBallInsideLinkCableLoop - push bc - xor a - ld de, Trade_BallInsideLinkCableOAM - call WriteOAMBlock - ld a, [wLinkCableAnimBulgeToggle] - xor $1 - ld [wLinkCableAnimBulgeToggle], a - add $7e - ld hl, wOAMBuffer + $02 - ld de, 4 - ld c, e -.cycleLinkCableBulgeTile - ld [hl], a - add hl, de - dec c - jr nz, .cycleLinkCableBulgeTile - call Delay3 - pop bc - ld a, c - add $4 - ld c, a - cp $a0 - jr nc, .ballSpriteReachedEdgeOfScreen - ld a, SFX_TINK - call PlaySound - jr .moveBallInsideLinkCableLoop -.ballSpriteReachedEdgeOfScreen - call ClearSprites - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a - call ClearScreen - ld b, $98 - call CopyScreenTileBufferToVRAM - call Delay3 - xor a - ld [H_AUTOBGTRANSFERENABLED], a - ret - -Trade_BallInsideLinkCableOAM: - db $7E,$00,$7E,$20 - db $7E,$40,$7E,$60 - -Trade_ShowEnemyMon: - ld a, TRADE_BALL_TILT_ANIM - call Trade_ShowAnimation - call Trade_ShowClearedWindow - coord hl, 4, 10 - ld b, 6 - ld c, 10 - call TextBoxBorder - call Trade_PrintEnemyMonInfoText - call Trade_CopyTileMapToVRAM - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a - ld a, [wTradedEnemyMonSpecies] - call Trade_LoadMonSprite - ld a, TRADE_BALL_POOF_ANIM - call Trade_ShowAnimation - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a - ld a, [wTradedEnemyMonSpecies] - call PlayCry - call Trade_Delay100 - coord hl, 4, 10 - lb bc, 8, 12 - call ClearScreenArea - jp PrintTradeTakeCareText - -Trade_AnimLeftToRight: -; Animates the mon moving from the left GB to the right one. - call Trade_InitGameboyTransferGfx - ld a, $1 - ld [wTradedMonMovingRight], a - ld a, %11100100 - ld [rOBP0], a - ld a, $54 - ld [wBaseCoordX], a - ld a, $1c - ld [wBaseCoordY], a - ld a, [wLeftGBMonSpecies] - ld [wMonPartySpriteSpecies], a - call Trade_WriteCircledMonOAM - call Trade_DrawLeftGameboy - call Trade_CopyTileMapToVRAM - call Trade_DrawCableAcrossScreen - ld hl, vBGMap1 + $8c - call Trade_CopyCableTilesOffScreen - ld b, $6 - call Trade_AnimMonMoveHorizontal - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a - call Trade_DrawCableAcrossScreen - ld b, $4 - call Trade_AnimMonMoveHorizontal - call Trade_DrawRightGameboy - ld b, $6 - call Trade_AnimMonMoveHorizontal - xor a - ld [H_AUTOBGTRANSFERENABLED], a - call Trade_AnimMonMoveVertical - jp ClearSprites - -Trade_AnimRightToLeft: -; Animates the mon moving from the right GB to the left one. - call Trade_InitGameboyTransferGfx - xor a - ld [wTradedMonMovingRight], a - ld a, $64 - ld [wBaseCoordX], a - ld a, $44 - ld [wBaseCoordY], a - ld a, [wRightGBMonSpecies] - ld [wMonPartySpriteSpecies], a - call Trade_WriteCircledMonOAM - call Trade_DrawRightGameboy - call Trade_CopyTileMapToVRAM - call Trade_DrawCableAcrossScreen - ld hl, vBGMap1 + $94 - call Trade_CopyCableTilesOffScreen - call Trade_AnimMonMoveVertical - ld b, $6 - call Trade_AnimMonMoveHorizontal - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a - call Trade_DrawCableAcrossScreen - ld b, $4 - call Trade_AnimMonMoveHorizontal - call Trade_DrawLeftGameboy - ld b, $6 - call Trade_AnimMonMoveHorizontal - xor a - ld [H_AUTOBGTRANSFERENABLED], a - jp ClearSprites - -Trade_InitGameboyTransferGfx: -; Initialises the graphics for showing a mon moving between gameboys. - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a - call ClearScreen - xor a - ld [H_AUTOBGTRANSFERENABLED], a - call Trade_LoadMonPartySpriteGfx - call DelayFrame - ld a, %10101011 - ld [rLCDC], a - xor a - ld [hSCX], a - ld a, $90 - ld [hWY], a - ret - -Trade_DrawLeftGameboy: - call Trade_ClearTileMap - -; draw link cable - coord hl, 11, 4 - ld a, $5d - ld [hli], a - ld a, $5e - ld c, 8 -.loop - ld [hli], a - dec c - jr nz, .loop - -; draw gameboy pic - coord hl, 5, 3 - ld b, $6 - call CopyTileIDsFromList_ZeroBaseTileID - -; draw text box with player name below gameboy pic - coord hl, 4, 12 - ld b, 2 - ld c, 7 - call TextBoxBorder - coord hl, 5, 14 - ld de, wPlayerName - call PlaceString - - jp DelayFrame - -Trade_DrawRightGameboy: - call Trade_ClearTileMap - -; draw horizontal segment of link cable - coord hl, 0, 4 - ld a, $5e - ld c, $e -.loop - ld [hli], a - dec c - jr nz, .loop - -; draw vertical segment of link cable - ld a, $5f - ld [hl], a - ld de, SCREEN_WIDTH - add hl, de - ld a, $61 - ld [hl], a - add hl, de - ld [hl], a - add hl, de - ld [hl], a - add hl, de - ld [hl], a - add hl, de - ld a, $60 - ld [hld], a - ld a, $5d - ld [hl], a - -; draw gameboy pic - coord hl, 7, 8 - ld b, $6 - call CopyTileIDsFromList_ZeroBaseTileID - -; draw text box with enemy name above link cable - coord hl, 6, 0 - ld b, 2 - ld c, 7 - call TextBoxBorder - coord hl, 7, 2 - ld de, wLinkEnemyTrainerName - call PlaceString - - jp DelayFrame - -Trade_DrawCableAcrossScreen: -; Draws the link cable across the screen. - call Trade_ClearTileMap - coord hl, 0, 4 - ld a, $5e - ld c, SCREEN_WIDTH -.loop - ld [hli], a - dec c - jr nz, .loop - ret - -Trade_CopyCableTilesOffScreen: -; This is used to copy the link cable tiles off screen so that the cable -; continues when the screen is scrolled. - push hl - coord hl, 0, 4 - call CopyToRedrawRowOrColumnSrcTiles - pop hl - ld a, h - ld [hRedrawRowOrColumnDest + 1], a - ld a, l - ld [hRedrawRowOrColumnDest], a - ld a, REDRAW_ROW - ld [hRedrawRowOrColumnMode], a - ld c, 10 - jp DelayFrames - -Trade_AnimMonMoveHorizontal: -; Animates the mon going through the link cable horizontally over a distance of -; b 16-pixel units. - ld a, [wTradedMonMovingRight] - ld e, a - ld d, $8 -.scrollLoop - ld a, e - dec a - jr z, .movingRight -; moving left - ld a, [hSCX] - sub $2 - jr .next -.movingRight - ld a, [hSCX] - add $2 -.next - ld [hSCX], a - call DelayFrame - dec d - jr nz, .scrollLoop - call Trade_AnimCircledMon - dec b - jr nz, Trade_AnimMonMoveHorizontal - ret - -Trade_AnimCircledMon: -; Cycles between the two animation frames of the mon party sprite, cycles -; between a circle and an oval around the mon sprite, and makes the cable flash. - push de - push bc - push hl - ld a, [rBGP] - xor $3c ; make link cable flash - ld [rBGP], a - ld hl, wOAMBuffer + $02 - ld de, $4 - ld c, $14 -.loop - ld a, [hl] - xor $40 - ld [hl], a - add hl, de - dec c - jr nz, .loop - pop hl - pop bc - pop de - ret - -Trade_WriteCircledMonOAM: - callba WriteMonPartySpriteOAMBySpecies - call Trade_WriteCircleOAM - -Trade_AddOffsetsToOAMCoords: - ld hl, wOAMBuffer - ld c, $14 -.loop - ld a, [wBaseCoordY] - add [hl] - ld [hli], a - ld a, [wBaseCoordX] - add [hl] - ld [hli], a - inc hl - inc hl - dec c - jr nz, .loop - ret - -Trade_AnimMonMoveVertical: -; Animates the mon going through the link cable vertically as well as -; horizontally for a bit. The last bit of horizontal movement (when moving -; right) or the first bit of horizontal movement (when moving left) are done -; here instead of Trade_AnimMonMoveHorizontal because this function moves the -; sprite itself rather than scrolling the screen around the sprite. Moving the -; sprite itself is necessary because the vertical segment of the link cable is -; to the right of the screen position that the mon sprite has when -; Trade_AnimMonMoveHorizontal is executing. - ld a, [wTradedMonMovingRight] - and a - jr z, .movingLeft -; moving right - lb bc, 4, 0 ; move right - call .doAnim - lb bc, 0, 10 ; move down - jr .doAnim -.movingLeft - lb bc, 0, -10 ; move up - call .doAnim - lb bc, -4, 0 ; move left -.doAnim - ld a, b - ld [wBaseCoordX], a - ld a, c - ld [wBaseCoordY], a - ld d, $4 -.loop - call Trade_AddOffsetsToOAMCoords - call Trade_AnimCircledMon - ld c, 8 - call DelayFrames - dec d - jr nz, .loop - ret - -Trade_WriteCircleOAM: -; Writes the OAM blocks for the circle around the traded mon as it passes -; the link cable. - ld hl, Trade_CircleOAMPointers - ld c, $4 - xor a -.loop - push bc - ld e, [hl] - inc hl - ld d, [hl] - inc hl - ld c, [hl] - inc hl - ld b, [hl] - inc hl - push hl - inc a - push af - call WriteOAMBlock - pop af - pop hl - pop bc - dec c - jr nz, .loop - ret - -Trade_CircleOAMPointers: - dw Trade_CircleOAM0 - db $08,$08 - dw Trade_CircleOAM1 - db $18,$08 - dw Trade_CircleOAM2 - db $08,$18 - dw Trade_CircleOAM3 - db $18,$18 - -Trade_CircleOAM0: - db $38,$10,$39,$10 - db $3A,$10,$3B,$10 - -Trade_CircleOAM1: - db $39,$30,$38,$30 - db $3B,$30,$3A,$30 - -Trade_CircleOAM2: - db $3A,$50,$3B,$50 - db $38,$50,$39,$50 - -Trade_CircleOAM3: - db $3B,$70,$3A,$70 - db $39,$70,$38,$70 - -; a = species -Trade_LoadMonSprite: - ld [wcf91], a - ld [wd0b5], a - ld [wWholeScreenPaletteMonSpecies], a - ld b, SET_PAL_POKEMON_WHOLE_SCREEN - ld c, 0 - call RunPaletteCommand - ld a, [H_AUTOBGTRANSFERENABLED] - xor $1 - ld [H_AUTOBGTRANSFERENABLED], a - call GetMonHeader - coord hl, 7, 2 - call LoadFlippedFrontSpriteByMonIndex - ld c, 10 - jp DelayFrames - -Trade_ShowClearedWindow: -; clears the window and covers the BG entirely with the window - ld a, $1 - ld [H_AUTOBGTRANSFERENABLED], a - call ClearScreen - ld a, %11100011 - ld [rLCDC], a - ld a, $7 - ld [rWX], a - xor a - ld [hWY], a - ld a, $90 - ld [hSCX], a - ret - -Trade_SlideTextBoxOffScreen: -; Slides the window right until it's off screen. The window usually just has -; a text box at the bottom when this is called. However, when this is called -; after Trade_ShowEnemyMon in the external clock sequence, there is a mon pic -; above the text box and it is also scrolled off the screen. - ld c, 50 - call DelayFrames -.loop - call DelayFrame - ld a, [rWX] - inc a - inc a - ld [rWX], a - cp $a1 - jr nz, .loop - call Trade_ClearTileMap - ld c, 10 - call DelayFrames - ld a, $7 - ld [rWX], a - ret - -PrintTradeWentToText: - ld hl, TradeWentToText - call PrintText - ld c, 200 - call DelayFrames - jp Trade_SlideTextBoxOffScreen - -TradeWentToText: - TX_FAR _TradeWentToText - db "@" - -PrintTradeForSendsText: - ld hl, TradeForText - call PrintText - call Trade_Delay80 - ld hl, TradeSendsText - call PrintText - jp Trade_Delay80 - -TradeForText: - TX_FAR _TradeForText - db "@" - -TradeSendsText: - TX_FAR _TradeSendsText - db "@" - -PrintTradeFarewellText: - ld hl, TradeWavesFarewellText - call PrintText - call Trade_Delay80 - ld hl, TradeTransferredText - call PrintText - call Trade_Delay80 - jp Trade_SlideTextBoxOffScreen - -TradeWavesFarewellText: - TX_FAR _TradeWavesFarewellText - db "@" - -TradeTransferredText: - TX_FAR _TradeTransferredText - db "@" - -PrintTradeTakeCareText: - ld hl, TradeTakeCareText - call PrintText - jp Trade_Delay80 - -TradeTakeCareText: - TX_FAR _TradeTakeCareText - db "@" - -PrintTradeWillTradeText: - ld hl, TradeWillTradeText - call PrintText - call Trade_Delay80 - ld hl, TradeforText - call PrintText - jp Trade_Delay80 - -TradeWillTradeText: - TX_FAR _TradeWillTradeText - db "@" - -TradeforText: - TX_FAR _TradeforText - db "@" - -Trade_ShowAnimation: - ld [wAnimationID], a - xor a - ld [wAnimationType], a - predef_jump MoveAnimation diff --git a/engine/trade2.asm b/engine/trade2.asm deleted file mode 100755 index 2c79e077..00000000 --- a/engine/trade2.asm +++ /dev/null @@ -1,48 +0,0 @@ -Trade_PrintPlayerMonInfoText: - coord hl, 5, 0 - ld de, Trade_MonInfoText - call PlaceString - ld a, [wTradedPlayerMonSpecies] - ld [wd11e], a - predef IndexToPokedex - coord hl, 9, 0 - ld de, wd11e - lb bc, LEADING_ZEROES | 1, 3 - call PrintNumber - coord hl, 5, 2 - ld de, wcf4b - call PlaceString - coord hl, 8, 4 - ld de, wTradedPlayerMonOT - call PlaceString - coord hl, 8, 6 - ld de, wTradedPlayerMonOTID - lb bc, LEADING_ZEROES | 2, 5 - jp PrintNumber - -Trade_PrintEnemyMonInfoText: - coord hl, 5, 10 - ld de, Trade_MonInfoText - call PlaceString - ld a, [wTradedEnemyMonSpecies] - ld [wd11e], a - predef IndexToPokedex - coord hl, 9, 10 - ld de, wd11e - lb bc, LEADING_ZEROES | 1, 3 - call PrintNumber - coord hl, 5, 12 - ld de, wcd6d - call PlaceString - coord hl, 8, 14 - ld de, wTradedEnemyMonOT - call PlaceString - coord hl, 8, 16 - ld de, wTradedEnemyMonOTID - lb bc, LEADING_ZEROES | 2, 5 - jp PrintNumber - -Trade_MonInfoText: - db "──№⠄",$4E - next "OT/" - next $73,"№⠄","@" diff --git a/engine/turn_sprite.asm b/engine/turn_sprite.asm deleted file mode 100755 index c7f7712b..00000000 --- a/engine/turn_sprite.asm +++ /dev/null @@ -1,25 +0,0 @@ -UpdateSpriteFacingOffsetAndDelayMovement:: - ld h, $c2 - ld a, [H_CURRENTSPRITEOFFSET] - add $8 - ld l, a - ld a, $7f ; maximum movement delay - ld [hl], a ; c2x8 (movement delay) - dec h - ld a, [H_CURRENTSPRITEOFFSET] - add $9 - ld l, a - ld a, [hld] ; c1x9 (facing direction) - ld b, a - xor a - ld [hld], a - ld [hl], a ; c1x8 (walk animation frame) - ld a, [H_CURRENTSPRITEOFFSET] - add $2 - ld l, a - ld a, [hl] ; c1x2 (facing and animation table offset) - or b ; or in the facing direction - ld [hld], a - ld a, $2 ; delayed movement status - ld [hl], a ; c1x1 (movement status) - ret diff --git a/home.asm b/home.asm index cd5352cb..dfa1bec2 100644 --- a/home.asm +++ b/home.asm @@ -1282,7 +1282,7 @@ RepelWoreOffText:: TX_FAR _RepelWoreOffText db "@" -INCLUDE "engine/menu/start_menu.asm" +INCLUDE "home/start_menu.asm" ; function to count how many bits are set in a string of bytes ; INPUT: diff --git a/home/start_menu.asm b/home/start_menu.asm new file mode 100755 index 00000000..eb4b4f2d --- /dev/null +++ b/home/start_menu.asm @@ -0,0 +1,85 @@ +DisplayStartMenu:: + ld a, BANK(StartMenu_Pokedex) + ld [H_LOADEDROMBANK], a + ld [MBC1RomBank], a + ld a, [wWalkBikeSurfState] ; walking/biking/surfing + ld [wWalkBikeSurfStateCopy], a + ld a, SFX_START_MENU + call PlaySound + +RedisplayStartMenu:: + callba DrawStartMenu + callba PrintSafariZoneSteps ; print Safari Zone info, if in Safari Zone + call UpdateSprites +.loop + call HandleMenuInput + ld b, a +.checkIfUpPressed + bit 6, a ; was Up pressed? + jr z, .checkIfDownPressed + ld a, [wCurrentMenuItem] ; menu selection + and a + jr nz, .loop + ld a, [wLastMenuItem] + and a + jr nz, .loop +; if the player pressed tried to go past the top item, wrap around to the bottom + CheckEvent EVENT_GOT_POKEDEX + ld a, 6 ; there are 7 menu items with the pokedex, so the max index is 6 + jr nz, .wrapMenuItemId + dec a ; there are only 6 menu items without the pokedex +.wrapMenuItemId + ld [wCurrentMenuItem], a + call EraseMenuCursor + jr .loop +.checkIfDownPressed + bit 7, a + jr z, .buttonPressed +; if the player pressed tried to go past the bottom item, wrap around to the top + CheckEvent EVENT_GOT_POKEDEX + ld a, [wCurrentMenuItem] + ld c, 7 ; there are 7 menu items with the pokedex + jr nz, .checkIfPastBottom + dec c ; there are only 6 menu items without the pokedex +.checkIfPastBottom + cp c + jr nz, .loop +; the player went past the bottom, so wrap to the top + xor a + ld [wCurrentMenuItem], a + call EraseMenuCursor + jr .loop +.buttonPressed ; A, B, or Start button pressed + call PlaceUnfilledArrowMenuCursor + ld a, [wCurrentMenuItem] + ld [wBattleAndStartSavedMenuItem], a ; save current menu selection + ld a, b + and %00001010 ; was the Start button or B button pressed? + jp nz, CloseStartMenu + call SaveScreenTilesToBuffer2 ; copy background from wTileMap to wTileMapBackup2 + CheckEvent EVENT_GOT_POKEDEX + ld a, [wCurrentMenuItem] + jr nz, .displayMenuItem + inc a ; adjust position to account for missing pokedex menu item +.displayMenuItem + cp 0 + jp z, StartMenu_Pokedex + cp 1 + jp z, StartMenu_Pokemon + cp 2 + jp z, StartMenu_Item + cp 3 + jp z, StartMenu_TrainerInfo + cp 4 + jp z, StartMenu_SaveReset + cp 5 + jp z, StartMenu_Option + +; EXIT falls through to here +CloseStartMenu:: + call Joypad + ld a, [hJoyPressed] + bit 0, a ; was A button newly pressed? + jr nz, CloseStartMenu + call LoadTextBoxTilePatterns + jp CloseTextDisplay diff --git a/main.asm b/main.asm index 126bf943..be29dfd7 100755 --- a/main.asm +++ b/main.asm @@ -4,46 +4,46 @@ INCLUDE "constants.asm" SECTION "bank1", ROMX INCLUDE "data/facing.asm" -INCLUDE "engine/black_out.asm" +INCLUDE "engine/events/black_out.asm" MewPicFront:: INCBIN "gfx/pokemon/front/mew.pic" MewPicBack:: INCBIN "gfx/pokemon/back/mewb.pic" INCLUDE "data/baseStats/mew.asm" INCLUDE "engine/battle/safari_zone.asm" -INCLUDE "engine/titlescreen.asm" -INCLUDE "engine/load_mon_data.asm" +INCLUDE "engine/movie/titlescreen.asm" +INCLUDE "engine/pokemon/load_mon_data.asm" INCLUDE "data/item_prices.asm" INCLUDE "text/item_names.asm" INCLUDE "text/unused_names.asm" -INCLUDE "engine/overworld/oam.asm" -INCLUDE "engine/oam_dma.asm" -INCLUDE "engine/print_waiting_text.asm" -INCLUDE "engine/overworld/map_sprite_functions1.asm" -INCLUDE "engine/test_battle.asm" -INCLUDE "engine/overworld/item.asm" +INCLUDE "engine/gfx/sprite_oam.asm" +INCLUDE "engine/gfx/oam_dma.asm" +INCLUDE "engine/link/print_waiting_text.asm" +INCLUDE "engine/overworld/sprite_collisions.asm" +INCLUDE "engine/debug/test_battle.asm" +INCLUDE "engine/events/pick_up_item.asm" INCLUDE "engine/overworld/movement.asm" -INCLUDE "engine/cable_club.asm" -INCLUDE "engine/menu/main_menu.asm" -INCLUDE "engine/oak_speech.asm" -INCLUDE "engine/special_warps.asm" -INCLUDE "engine/debug1.asm" -INCLUDE "engine/menu/naming_screen.asm" -INCLUDE "engine/oak_speech2.asm" -INCLUDE "engine/subtract_paid_money.asm" -INCLUDE "engine/menu/swap_items.asm" -INCLUDE "engine/overworld/pokemart.asm" -INCLUDE "engine/learn_move.asm" -INCLUDE "engine/overworld/pokecenter.asm" -INCLUDE "engine/overworld/set_blackout_map.asm" -INCLUDE "engine/display_text_id_init.asm" -INCLUDE "engine/menu/draw_start_menu.asm" -INCLUDE "engine/overworld/cable_club_npc.asm" -INCLUDE "engine/menu/text_box.asm" -INCLUDE "engine/battle/moveEffects/drain_hp_effect.asm" -INCLUDE "engine/menu/players_pc.asm" -INCLUDE "engine/remove_pokemon.asm" -INCLUDE "engine/display_pokedex.asm" +INCLUDE "engine/link/cable_club.asm" +INCLUDE "engine/menus/main_menu.asm" +INCLUDE "engine/movie/oak_speech.asm" +INCLUDE "engine/overworld/special_warps.asm" +INCLUDE "engine/debug/debug_party.asm" +INCLUDE "engine/menus/naming_screen.asm" +INCLUDE "engine/movie/oak_speech2.asm" +INCLUDE "engine/items/subtract_paid_money.asm" +INCLUDE "engine/menus/swap_items.asm" +INCLUDE "engine/events/pokemart.asm" +INCLUDE "engine/pokemon/learn_move.asm" +INCLUDE "engine/events/pokecenter.asm" +INCLUDE "engine/events/set_blackout_map.asm" +INCLUDE "engine/menus/display_text_id_init.asm" +INCLUDE "engine/menus/draw_start_menu.asm" +INCLUDE "engine/link/cable_club_npc.asm" +INCLUDE "engine/menus/text_box.asm" +INCLUDE "engine/battle/move_effects/drain_hp.asm" +INCLUDE "engine/menus/players_pc.asm" +INCLUDE "engine/pokemon/remove_mon.asm" +INCLUDE "engine/events/display_pokedex.asm" SECTION "bank3", ROMX @@ -53,28 +53,28 @@ INCLUDE "data/map_songs.asm" INCLUDE "data/map_header_banks.asm" INCLUDE "engine/overworld/clear_variables.asm" INCLUDE "engine/overworld/player_state.asm" -INCLUDE "engine/overworld/poison.asm" -INCLUDE "engine/overworld/tileset_header.asm" +INCLUDE "engine/events/poison.asm" +INCLUDE "engine/overworld/tilesets.asm" INCLUDE "engine/overworld/daycare_exp.asm" INCLUDE "data/hide_show_data.asm" INCLUDE "engine/overworld/field_move_messages.asm" INCLUDE "engine/items/inventory.asm" INCLUDE "engine/overworld/wild_mons.asm" -INCLUDE "engine/items/items.asm" -INCLUDE "engine/menu/draw_badges.asm" +INCLUDE "engine/items/item_effects.asm" +INCLUDE "engine/menus/draw_badges.asm" INCLUDE "engine/overworld/update_map.asm" INCLUDE "engine/overworld/cut.asm" INCLUDE "engine/overworld/missable_objects.asm" INCLUDE "engine/overworld/push_boulder.asm" -INCLUDE "engine/add_mon.asm" +INCLUDE "engine/pokemon/add_mon.asm" INCLUDE "engine/flag_action.asm" -INCLUDE "engine/heal_party.asm" -INCLUDE "engine/bcd.asm" -INCLUDE "engine/init_player_data.asm" -INCLUDE "engine/get_bag_item_quantity.asm" -INCLUDE "engine/pathfinding.asm" -INCLUDE "engine/hp_bar.asm" -INCLUDE "engine/hidden_object_functions3.asm" +INCLUDE "engine/events/heal_party.asm" +INCLUDE "engine/math/bcd.asm" +INCLUDE "engine/movie/init_player_data.asm" +INCLUDE "engine/items/get_bag_item_quantity.asm" +INCLUDE "engine/overworld/pathfinding.asm" +INCLUDE "engine/gfx/hp_bar.asm" +INCLUDE "engine/events/hidden_object_functions3.asm" SECTION "Graphics (BANK 4)", ROMX @@ -106,33 +106,33 @@ PlayerCharacterTitleGraphicsEnd: SECTION "Battle (BANK 4)", ROMX INCLUDE "engine/overworld/is_player_just_outside_map.asm" -INCLUDE "engine/menu/status_screen.asm" -INCLUDE "engine/menu/party_menu.asm" +INCLUDE "engine/pokemon/status_screen.asm" +INCLUDE "engine/menus/party_menu.asm" RedPicFront:: INCBIN "gfx/player/red.pic" ShrinkPic1:: INCBIN "gfx/player/shrink1.pic" ShrinkPic2:: INCBIN "gfx/player/shrink2.pic" -INCLUDE "engine/turn_sprite.asm" -INCLUDE "engine/menu/start_sub_menus.asm" +INCLUDE "engine/overworld/turn_sprite.asm" +INCLUDE "engine/menus/start_sub_menus.asm" INCLUDE "engine/items/tms.asm" INCLUDE "engine/battle/end_of_battle.asm" INCLUDE "engine/battle/wild_encounters.asm" -INCLUDE "engine/battle/moveEffects/recoil_effect.asm" -INCLUDE "engine/battle/moveEffects/conversion_effect.asm" -INCLUDE "engine/battle/moveEffects/haze_effect.asm" +INCLUDE "engine/battle/move_effects/recoil.asm" +INCLUDE "engine/battle/move_effects/conversion.asm" +INCLUDE "engine/battle/move_effects/haze.asm" INCLUDE "engine/battle/get_trainer_name.asm" -INCLUDE "engine/random.asm" +INCLUDE "engine/math/random.asm" SECTION "Battle (BANK 5)", ROMX -INCLUDE "engine/load_pokedex_tiles.asm" +INCLUDE "engine/gfx/load_pokedex_tiles.asm" INCLUDE "engine/overworld/map_sprites.asm" INCLUDE "engine/overworld/emotion_bubbles.asm" -INCLUDE "engine/evolve_trade.asm" -INCLUDE "engine/battle/moveEffects/substitute_effect.asm" -INCLUDE "engine/menu/pc.asm" +INCLUDE "engine/events/evolve_trade.asm" +INCLUDE "engine/battle/move_effects/substitute.asm" +INCLUDE "engine/menus/pc.asm" SECTION "bank6_1", ROMX @@ -142,7 +142,7 @@ INCLUDE "engine/play_time.asm" SECTION "bank6_2", ROMX -INCLUDE "engine/overworld/npc_movement.asm" +INCLUDE "engine/overworld/auto_movement.asm" INCLUDE "engine/overworld/doors.asm" INCLUDE "engine/overworld/ledges.asm" @@ -150,26 +150,26 @@ INCLUDE "engine/overworld/ledges.asm" SECTION "bank7_1", ROMX INCLUDE "text/monster_names.asm" -INCLUDE "engine/clear_save.asm" -INCLUDE "engine/predefs7.asm" +INCLUDE "engine/movie/clear_save.asm" +INCLUDE "engine/events/elevator.asm" SECTION "bank7_2", ROMX -INCLUDE "engine/menu/oaks_pc.asm" -INCLUDE "engine/hidden_object_functions7.asm" +INCLUDE "engine/menus/oaks_pc.asm" +INCLUDE "engine/events/hidden_object_functions7.asm" SECTION "Battle (BANK 9)", ROMX INCLUDE "engine/battle/print_type.asm" INCLUDE "engine/battle/save_trainer_name.asm" -INCLUDE "engine/battle/moveEffects/focus_energy_effect.asm" +INCLUDE "engine/battle/move_effects/focus_energy.asm" SECTION "Battle (BANK A)", ROMX -INCLUDE "engine/battle/moveEffects/leech_seed_effect.asm" +INCLUDE "engine/battle/move_effects/leech_seed.asm" SECTION "Battle (BANK B)", ROMX @@ -184,24 +184,24 @@ BadgeNumbersTileGraphics: INCBIN "gfx/trainer_card/badge_numbers.2bpp" INCLUDE "engine/items/tmhm.asm" INCLUDE "engine/battle/scale_sprites.asm" -INCLUDE "engine/battle/moveEffects/pay_day_effect.asm" -INCLUDE "engine/game_corner_slots2.asm" +INCLUDE "engine/battle/move_effects/pay_day.asm" +INCLUDE "engine/slots/game_corner_slots2.asm" SECTION "Battle (BANK C)", ROMX -INCLUDE "engine/battle/moveEffects/mist_effect.asm" -INCLUDE "engine/battle/moveEffects/one_hit_ko_effect.asm" +INCLUDE "engine/battle/move_effects/mist.asm" +INCLUDE "engine/battle/move_effects/one_hit_ko.asm" SECTION "Battle (BANK D)", ROMX -INCLUDE "engine/titlescreen2.asm" +INCLUDE "engine/movie/titlescreen2.asm" INCLUDE "engine/battle/link_battle_versus_text.asm" -INCLUDE "engine/slot_machine.asm" -INCLUDE "engine/overworld/pewter_guys.asm" -INCLUDE "engine/multiply_divide.asm" -INCLUDE "engine/game_corner_slots.asm" +INCLUDE "engine/slots/slot_machine.asm" +INCLUDE "engine/events/pewter_guys.asm" +INCLUDE "engine/math/multiply_divide.asm" +INCLUDE "engine/slots/game_corner_slots.asm" SECTION "bankE", ROMX @@ -223,10 +223,10 @@ TradingAnimationGraphicsEnd: TradingAnimationGraphics2: INCBIN "gfx/trade/cable_ball.2bpp" TradingAnimationGraphics2End: -INCLUDE "engine/evos_moves.asm" -INCLUDE "engine/battle/moveEffects/heal_effect.asm" -INCLUDE "engine/battle/moveEffects/transform_effect.asm" -INCLUDE "engine/battle/moveEffects/reflect_light_screen_effect.asm" +INCLUDE "engine/pokemon/evos_moves.asm" +INCLUDE "engine/battle/move_effects/heal.asm" +INCLUDE "engine/battle/move_effects/transform.asm" +INCLUDE "engine/battle/move_effects/reflect_light_screen.asm" SECTION "bankF", ROMX @@ -237,15 +237,15 @@ INCLUDE "engine/battle/effects.asm" SECTION "bank10", ROMX -INCLUDE "engine/menu/pokedex.asm" -INCLUDE "engine/trade.asm" -INCLUDE "engine/intro.asm" -INCLUDE "engine/trade2.asm" +INCLUDE "engine/menus/pokedex.asm" +INCLUDE "engine/movie/trade.asm" +INCLUDE "engine/movie/intro.asm" +INCLUDE "engine/movie/trade2.asm" SECTION "bank11_1", ROMX -INCLUDE "engine/pokedex_rating.asm" +INCLUDE "engine/events/pokedex_rating.asm" SECTION "bank11_2", ROMX @@ -255,22 +255,22 @@ INCLUDE "engine/overworld/hidden_objects.asm" SECTION "bank12", ROMX -INCLUDE "engine/predefs12.asm" +INCLUDE "engine/gfx/screen_effects.asm" SECTION "bank13", ROMX -INCLUDE "engine/give_pokemon.asm" +INCLUDE "engine/events/give_pokemon.asm" INCLUDE "engine/predefs.asm" SECTION "bank14", ROMX INCLUDE "engine/battle/init_battle_variables.asm" -INCLUDE "engine/battle/moveEffects/paralyze_effect.asm" -INCLUDE "engine/overworld/card_key.asm" -INCLUDE "engine/menu/prize_menu.asm" -INCLUDE "engine/hidden_object_functions14.asm" +INCLUDE "engine/battle/move_effects/paralyze.asm" +INCLUDE "engine/events/card_key.asm" +INCLUDE "engine/events/prize_menu.asm" +INCLUDE "engine/events/hidden_object_functions14.asm" SECTION "bank15_1", ROMX @@ -280,41 +280,41 @@ INCLUDE "engine/battle/experience.asm" SECTION "bank15_2", ROMX -INCLUDE "engine/menu/diploma.asm" -INCLUDE "engine/overworld/trainers.asm" +INCLUDE "engine/events/diploma.asm" +INCLUDE "engine/overworld/trainer_sight.asm" SECTION "bank16_1", ROMX INCLUDE "engine/battle/common_text.asm" -INCLUDE "engine/experience.asm" -INCLUDE "engine/overworld/oaks_aide.asm" +INCLUDE "engine/pokemon/experience.asm" +INCLUDE "engine/events/oaks_aide.asm" SECTION "bank16_2", ROMX -INCLUDE "engine/overworld/saffron_guards.asm" +INCLUDE "engine/events/saffron_guards.asm" SECTION "bank17_1", ROMX -INCLUDE "engine/predefs17.asm" +INCLUDE "engine/events/starter_dex.asm" SECTION "bank17_2", ROMX -INCLUDE "engine/predefs17_2.asm" -INCLUDE "engine/hidden_object_functions17.asm" +INCLUDE "engine/pokemon/set_types.asm" +INCLUDE "engine/events/hidden_object_functions17.asm" SECTION "bank18_1", ROMX -INCLUDE "engine/overworld/cinnabar_lab.asm" +INCLUDE "engine/events/cinnabar_lab.asm" SECTION "bank18_2", ROMX -INCLUDE "engine/hidden_object_functions18.asm" +INCLUDE "engine/events/hidden_object_functions18.asm" SECTION "bank1A", ROMX @@ -333,42 +333,42 @@ Version_GFXEnd: SECTION "bank1C", ROMX -INCLUDE "engine/gamefreak.asm" -INCLUDE "engine/hall_of_fame.asm" +INCLUDE "engine/movie/gamefreak.asm" +INCLUDE "engine/movie/hall_of_fame.asm" INCLUDE "engine/overworld/healing_machine.asm" INCLUDE "engine/overworld/player_animations.asm" INCLUDE "engine/battle/ghost_marowak_anim.asm" INCLUDE "engine/battle/battle_transitions.asm" -INCLUDE "engine/town_map.asm" -INCLUDE "engine/mon_party_sprites.asm" -INCLUDE "engine/in_game_trades.asm" -INCLUDE "engine/palettes.asm" -INCLUDE "engine/save.asm" +INCLUDE "engine/items/town_map.asm" +INCLUDE "engine/gfx/mon_icons.asm" +INCLUDE "engine/events/in_game_trades.asm" +INCLUDE "engine/gfx/palettes.asm" +INCLUDE "engine/menus/save.asm" SECTION "bank1D_1", ROMX -INCLUDE "engine/HoF_room_pc.asm" -INCLUDE "engine/status_ailments.asm" +INCLUDE "engine/movie/credits.asm" +INCLUDE "engine/pokemon/status_ailments.asm" INCLUDE "engine/items/itemfinder.asm" SECTION "bank1D_2", ROMX -INCLUDE "engine/menu/vending_machine.asm" +INCLUDE "engine/events/vending_machine.asm" SECTION "bank1D_3", ROMX -INCLUDE "engine/menu/league_pc.asm" -INCLUDE "engine/overworld/hidden_items.asm" +INCLUDE "engine/menus/league_pc.asm" +INCLUDE "engine/events/hidden_items.asm" SECTION "bank1E", ROMX INCLUDE "engine/battle/animations.asm" INCLUDE "engine/overworld/cut2.asm" -INCLUDE "engine/overworld/ssanne.asm" +INCLUDE "engine/overworld/dust_smoke.asm" RedFishingTilesFront: INCBIN "gfx/overworld/red_fish_front.2bpp" RedFishingTilesBack: INCBIN "gfx/overworld/red_fish_back.2bpp" @@ -376,6 +376,6 @@ RedFishingTilesSide: INCBIN "gfx/overworld/red_fish_side.2bpp" RedFishingRodTiles: INCBIN "gfx/overworld/fishing_rod.2bpp" INCLUDE "data/animations.asm" -INCLUDE "engine/evolution.asm" +INCLUDE "engine/movie/evolution.asm" INCLUDE "engine/overworld/elevator.asm" INCLUDE "engine/items/tm_prices.asm" -- cgit v1.2.3 From 881e0059704b9134a80d30f203f54677a7c6fb89 Mon Sep 17 00:00:00 2001 From: Rangi Date: Fri, 3 Jul 2020 01:09:58 -0400 Subject: INCLUDE "engine/pokemon/bills_pc.asm" in main.asm, not audio.asm --- audio.asm | 7 +++++-- layout.link | 2 ++ main.asm | 5 +++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/audio.asm b/audio.asm index effcb6f7..94d63f25 100644 --- a/audio.asm +++ b/audio.asm @@ -359,10 +359,13 @@ INCLUDE "audio/engine_1.asm" INCLUDE "audio/alternate_tempo.asm" -SECTION "Audio Engine 2", ROMX +SECTION "Low Health Alarm (Audio Engine 2)", ROMX INCLUDE "audio/low_health_alarm.asm" -INCLUDE "engine/pokemon/bills_pc.asm" + + +SECTION "Audio Engine 2", ROMX + INCLUDE "audio/engine_2.asm" INCLUDE "audio/poke_flute.asm" diff --git a/layout.link b/layout.link index c9ad5839..6391c9d5 100644 --- a/layout.link +++ b/layout.link @@ -94,6 +94,8 @@ ROMX $8 "Sound Effect Headers 2" "Music Headers 2" "Sound Effects 2" + "Low Health Alarm (Audio Engine 2)" + "Bill's PC" "Audio Engine 2" "Music 2" diff --git a/main.asm b/main.asm index be29dfd7..50930bb4 100755 --- a/main.asm +++ b/main.asm @@ -160,6 +160,11 @@ INCLUDE "engine/menus/oaks_pc.asm" INCLUDE "engine/events/hidden_object_functions7.asm" +SECTION "Bill's PC", ROMX + +INCLUDE "engine/pokemon/bills_pc.asm" + + SECTION "Battle (BANK 9)", ROMX INCLUDE "engine/battle/print_type.asm" -- cgit v1.2.3 From 87ef75c173b5d5f227912860487600b6f53d1d1f Mon Sep 17 00:00:00 2001 From: Rangi Date: Fri, 3 Jul 2020 01:11:23 -0400 Subject: Add engine/movie/oak_speech/ subdirectory --- engine/movie/clear_save.asm | 23 --- engine/movie/init_player_data.asm | 55 ------- engine/movie/oak_speech.asm | 233 --------------------------- engine/movie/oak_speech/clear_save.asm | 23 +++ engine/movie/oak_speech/init_player_data.asm | 55 +++++++ engine/movie/oak_speech/oak_speech.asm | 233 +++++++++++++++++++++++++++ engine/movie/oak_speech/oak_speech2.asm | 219 +++++++++++++++++++++++++ engine/movie/oak_speech2.asm | 219 ------------------------- main.asm | 8 +- 9 files changed, 534 insertions(+), 534 deletions(-) delete mode 100755 engine/movie/clear_save.asm delete mode 100644 engine/movie/init_player_data.asm delete mode 100755 engine/movie/oak_speech.asm create mode 100755 engine/movie/oak_speech/clear_save.asm create mode 100644 engine/movie/oak_speech/init_player_data.asm create mode 100755 engine/movie/oak_speech/oak_speech.asm create mode 100755 engine/movie/oak_speech/oak_speech2.asm delete mode 100755 engine/movie/oak_speech2.asm diff --git a/engine/movie/clear_save.asm b/engine/movie/clear_save.asm deleted file mode 100755 index b47cd6c4..00000000 --- a/engine/movie/clear_save.asm +++ /dev/null @@ -1,23 +0,0 @@ -DoClearSaveDialogue: - call ClearScreen - call RunDefaultPaletteCommand - call LoadFontTilePatterns - call LoadTextBoxTilePatterns - ld hl, ClearSaveDataText - call PrintText - coord hl, 14, 7 - lb bc, 8, 15 - ld a, NO_YES_MENU - ld [wTwoOptionMenuID], a - ld a, TWO_OPTION_MENU - ld [wTextBoxID], a - call DisplayTextBoxID - ld a, [wCurrentMenuItem] - and a - jp z, Init - callba ClearSAV - jp Init - -ClearSaveDataText: - TX_FAR _ClearSaveDataText - db "@" diff --git a/engine/movie/init_player_data.asm b/engine/movie/init_player_data.asm deleted file mode 100644 index c576e65a..00000000 --- a/engine/movie/init_player_data.asm +++ /dev/null @@ -1,55 +0,0 @@ -InitPlayerData: -InitPlayerData2: - - call Random - ld a, [hRandomSub] - ld [wPlayerID], a - - call Random - ld a, [hRandomAdd] - ld [wPlayerID + 1], a - - ld a, $ff - ld [wUnusedD71B], a - - ld hl, wPartyCount - call InitializeEmptyList - ld hl, wNumInBox - call InitializeEmptyList - ld hl, wNumBagItems - call InitializeEmptyList - ld hl, wNumBoxItems - call InitializeEmptyList - -START_MONEY EQU $3000 - ld hl, wPlayerMoney + 1 - ld a, START_MONEY / $100 - ld [hld], a - xor a - ld [hli], a - inc hl - ld [hl], a - - ld [wMonDataLocation], a - - ld hl, wObtainedBadges - ld [hli], a - - ld [hl], a - - ld hl, wPlayerCoins - ld [hli], a - ld [hl], a - - ld hl, wGameProgressFlags - ld bc, wGameProgressFlagsEnd - wGameProgressFlags - call FillMemory ; clear all game progress flags - - jp InitializeMissableObjectsFlags - -InitializeEmptyList: - xor a ; count - ld [hli], a - dec a ; terminator - ld [hl], a - ret diff --git a/engine/movie/oak_speech.asm b/engine/movie/oak_speech.asm deleted file mode 100755 index b1acfb65..00000000 --- a/engine/movie/oak_speech.asm +++ /dev/null @@ -1,233 +0,0 @@ -SetDefaultNames: - ld a, [wLetterPrintingDelayFlags] - push af - ld a, [wOptions] - push af - ld a, [wd732] - push af - ld hl, wPlayerName - ld bc, wBoxDataEnd - wPlayerName - xor a - call FillMemory - ld hl, wSpriteStateData1 - ld bc, $200 - xor a - call FillMemory - pop af - ld [wd732], a - pop af - ld [wOptions], a - pop af - ld [wLetterPrintingDelayFlags], a - ld a, [wOptionsInitialized] - and a - call z, InitOptions - ld hl, NintenText - ld de, wPlayerName - ld bc, NAME_LENGTH - call CopyData - ld hl, SonyText - ld de, wRivalName - ld bc, NAME_LENGTH - jp CopyData - -OakSpeech: - ld a, $FF - call PlaySound ; stop music - ld a, BANK(Music_Routes2) - ld c, a - ld a, MUSIC_ROUTES2 - call PlayMusic - call ClearScreen - call LoadTextBoxTilePatterns - call SetDefaultNames - predef InitPlayerData2 - ld hl, wNumBoxItems - ld a, POTION - ld [wcf91], a - ld a, 1 - ld [wItemQuantity], a - call AddItemToInventory ; give one potion - ld a, [wDefaultMap] - ld [wDestinationMap], a - call SpecialWarpIn - xor a - ld [hTilesetType], a - ld a, [wd732] - bit 1, a ; possibly a debug mode bit - jp nz, .skipChoosingNames - ld de, ProfOakPic - lb bc, Bank(ProfOakPic), $00 - call IntroDisplayPicCenteredOrUpperRight - call FadeInIntroPic - ld hl, OakSpeechText1 - call PrintText - call GBFadeOutToWhite - call ClearScreen - ld a, NIDORINO - ld [wd0b5], a - ld [wcf91], a - call GetMonHeader - coord hl, 6, 4 - call LoadFlippedFrontSpriteByMonIndex - call MovePicLeft - ld hl, OakSpeechText2 - call PrintText - call GBFadeOutToWhite - call ClearScreen - ld de, RedPicFront - lb bc, Bank(RedPicFront), $00 - call IntroDisplayPicCenteredOrUpperRight - call MovePicLeft - ld hl, IntroducePlayerText - call PrintText - call ChoosePlayerName - call GBFadeOutToWhite - call ClearScreen - ld de, Rival1Pic - lb bc, Bank(Rival1Pic), $00 - call IntroDisplayPicCenteredOrUpperRight - call FadeInIntroPic - ld hl, IntroduceRivalText - call PrintText - call ChooseRivalName -.skipChoosingNames - call GBFadeOutToWhite - call ClearScreen - ld de, RedPicFront - lb bc, Bank(RedPicFront), $00 - call IntroDisplayPicCenteredOrUpperRight - call GBFadeInFromWhite - ld a, [wd72d] - and a - jr nz, .next - ld hl, OakSpeechText3 - call PrintText -.next - ld a, [H_LOADEDROMBANK] - push af - ld a, SFX_SHRINK - call PlaySound - pop af - ld [H_LOADEDROMBANK], a - ld [MBC1RomBank], a - ld c, 4 - call DelayFrames - ld de, RedSprite - ld hl, vSprites - lb bc, BANK(RedSprite), $0C - call CopyVideoData - ld de, ShrinkPic1 - lb bc, BANK(ShrinkPic1), $00 - call IntroDisplayPicCenteredOrUpperRight - ld c, 4 - call DelayFrames - ld de, ShrinkPic2 - lb bc, BANK(ShrinkPic2), $00 - call IntroDisplayPicCenteredOrUpperRight - call ResetPlayerSpriteData - ld a, [H_LOADEDROMBANK] - push af - ld a, BANK(Music_PalletTown) - ld [wAudioROMBank], a - ld [wAudioSavedROMBank], a - ld a, 10 - ld [wAudioFadeOutControl], a - ld a, $FF - ld [wNewSoundID], a - call PlaySound ; stop music - pop af - ld [H_LOADEDROMBANK], a - ld [MBC1RomBank], a - ld c, 20 - call DelayFrames - coord hl, 6, 5 - ld b, 7 - ld c, 7 - call ClearScreenArea - call LoadTextBoxTilePatterns - ld a, 1 - ld [wUpdateSpritesEnabled], a - ld c, 50 - call DelayFrames - call GBFadeOutToWhite - jp ClearScreen -OakSpeechText1: - TX_FAR _OakSpeechText1 - db "@" -OakSpeechText2: - TX_FAR _OakSpeechText2A - TX_CRY_NIDORINA - TX_FAR _OakSpeechText2B - db "@" -IntroducePlayerText: - TX_FAR _IntroducePlayerText - db "@" -IntroduceRivalText: - TX_FAR _IntroduceRivalText - db "@" -OakSpeechText3: - TX_FAR _OakSpeechText3 - db "@" - -FadeInIntroPic: - ld hl, IntroFadePalettes - ld b, 6 -.next - ld a, [hli] - ld [rBGP], a - ld c, 10 - call DelayFrames - dec b - jr nz, .next - ret - -IntroFadePalettes: - db %01010100 - db %10101000 - db %11111100 - db %11111000 - db %11110100 - db %11100100 - -MovePicLeft: - ld a, 119 - ld [rWX], a - call DelayFrame - - ld a, %11100100 - ld [rBGP], a -.next - call DelayFrame - ld a, [rWX] - sub 8 - cp $FF - ret z - ld [rWX], a - jr .next - -DisplayPicCenteredOrUpperRight: - call GetPredefRegisters -IntroDisplayPicCenteredOrUpperRight: -; b = bank -; de = address of compressed pic -; c: 0 = centred, non-zero = upper-right - push bc - ld a, b - call UncompressSpriteFromDE - ld hl, sSpriteBuffer1 - ld de, sSpriteBuffer0 - ld bc, $310 - call CopyData - ld de, vFrontPic - call InterlaceMergeSpriteBuffers - pop bc - ld a, c - and a - coord hl, 15, 1 - jr nz, .next - coord hl, 6, 4 -.next - xor a - ld [hStartTileID], a - predef_jump CopyUncompressedPicToTilemap diff --git a/engine/movie/oak_speech/clear_save.asm b/engine/movie/oak_speech/clear_save.asm new file mode 100755 index 00000000..b47cd6c4 --- /dev/null +++ b/engine/movie/oak_speech/clear_save.asm @@ -0,0 +1,23 @@ +DoClearSaveDialogue: + call ClearScreen + call RunDefaultPaletteCommand + call LoadFontTilePatterns + call LoadTextBoxTilePatterns + ld hl, ClearSaveDataText + call PrintText + coord hl, 14, 7 + lb bc, 8, 15 + ld a, NO_YES_MENU + ld [wTwoOptionMenuID], a + ld a, TWO_OPTION_MENU + ld [wTextBoxID], a + call DisplayTextBoxID + ld a, [wCurrentMenuItem] + and a + jp z, Init + callba ClearSAV + jp Init + +ClearSaveDataText: + TX_FAR _ClearSaveDataText + db "@" diff --git a/engine/movie/oak_speech/init_player_data.asm b/engine/movie/oak_speech/init_player_data.asm new file mode 100644 index 00000000..c576e65a --- /dev/null +++ b/engine/movie/oak_speech/init_player_data.asm @@ -0,0 +1,55 @@ +InitPlayerData: +InitPlayerData2: + + call Random + ld a, [hRandomSub] + ld [wPlayerID], a + + call Random + ld a, [hRandomAdd] + ld [wPlayerID + 1], a + + ld a, $ff + ld [wUnusedD71B], a + + ld hl, wPartyCount + call InitializeEmptyList + ld hl, wNumInBox + call InitializeEmptyList + ld hl, wNumBagItems + call InitializeEmptyList + ld hl, wNumBoxItems + call InitializeEmptyList + +START_MONEY EQU $3000 + ld hl, wPlayerMoney + 1 + ld a, START_MONEY / $100 + ld [hld], a + xor a + ld [hli], a + inc hl + ld [hl], a + + ld [wMonDataLocation], a + + ld hl, wObtainedBadges + ld [hli], a + + ld [hl], a + + ld hl, wPlayerCoins + ld [hli], a + ld [hl], a + + ld hl, wGameProgressFlags + ld bc, wGameProgressFlagsEnd - wGameProgressFlags + call FillMemory ; clear all game progress flags + + jp InitializeMissableObjectsFlags + +InitializeEmptyList: + xor a ; count + ld [hli], a + dec a ; terminator + ld [hl], a + ret diff --git a/engine/movie/oak_speech/oak_speech.asm b/engine/movie/oak_speech/oak_speech.asm new file mode 100755 index 00000000..b1acfb65 --- /dev/null +++ b/engine/movie/oak_speech/oak_speech.asm @@ -0,0 +1,233 @@ +SetDefaultNames: + ld a, [wLetterPrintingDelayFlags] + push af + ld a, [wOptions] + push af + ld a, [wd732] + push af + ld hl, wPlayerName + ld bc, wBoxDataEnd - wPlayerName + xor a + call FillMemory + ld hl, wSpriteStateData1 + ld bc, $200 + xor a + call FillMemory + pop af + ld [wd732], a + pop af + ld [wOptions], a + pop af + ld [wLetterPrintingDelayFlags], a + ld a, [wOptionsInitialized] + and a + call z, InitOptions + ld hl, NintenText + ld de, wPlayerName + ld bc, NAME_LENGTH + call CopyData + ld hl, SonyText + ld de, wRivalName + ld bc, NAME_LENGTH + jp CopyData + +OakSpeech: + ld a, $FF + call PlaySound ; stop music + ld a, BANK(Music_Routes2) + ld c, a + ld a, MUSIC_ROUTES2 + call PlayMusic + call ClearScreen + call LoadTextBoxTilePatterns + call SetDefaultNames + predef InitPlayerData2 + ld hl, wNumBoxItems + ld a, POTION + ld [wcf91], a + ld a, 1 + ld [wItemQuantity], a + call AddItemToInventory ; give one potion + ld a, [wDefaultMap] + ld [wDestinationMap], a + call SpecialWarpIn + xor a + ld [hTilesetType], a + ld a, [wd732] + bit 1, a ; possibly a debug mode bit + jp nz, .skipChoosingNames + ld de, ProfOakPic + lb bc, Bank(ProfOakPic), $00 + call IntroDisplayPicCenteredOrUpperRight + call FadeInIntroPic + ld hl, OakSpeechText1 + call PrintText + call GBFadeOutToWhite + call ClearScreen + ld a, NIDORINO + ld [wd0b5], a + ld [wcf91], a + call GetMonHeader + coord hl, 6, 4 + call LoadFlippedFrontSpriteByMonIndex + call MovePicLeft + ld hl, OakSpeechText2 + call PrintText + call GBFadeOutToWhite + call ClearScreen + ld de, RedPicFront + lb bc, Bank(RedPicFront), $00 + call IntroDisplayPicCenteredOrUpperRight + call MovePicLeft + ld hl, IntroducePlayerText + call PrintText + call ChoosePlayerName + call GBFadeOutToWhite + call ClearScreen + ld de, Rival1Pic + lb bc, Bank(Rival1Pic), $00 + call IntroDisplayPicCenteredOrUpperRight + call FadeInIntroPic + ld hl, IntroduceRivalText + call PrintText + call ChooseRivalName +.skipChoosingNames + call GBFadeOutToWhite + call ClearScreen + ld de, RedPicFront + lb bc, Bank(RedPicFront), $00 + call IntroDisplayPicCenteredOrUpperRight + call GBFadeInFromWhite + ld a, [wd72d] + and a + jr nz, .next + ld hl, OakSpeechText3 + call PrintText +.next + ld a, [H_LOADEDROMBANK] + push af + ld a, SFX_SHRINK + call PlaySound + pop af + ld [H_LOADEDROMBANK], a + ld [MBC1RomBank], a + ld c, 4 + call DelayFrames + ld de, RedSprite + ld hl, vSprites + lb bc, BANK(RedSprite), $0C + call CopyVideoData + ld de, ShrinkPic1 + lb bc, BANK(ShrinkPic1), $00 + call IntroDisplayPicCenteredOrUpperRight + ld c, 4 + call DelayFrames + ld de, ShrinkPic2 + lb bc, BANK(ShrinkPic2), $00 + call IntroDisplayPicCenteredOrUpperRight + call ResetPlayerSpriteData + ld a, [H_LOADEDROMBANK] + push af + ld a, BANK(Music_PalletTown) + ld [wAudioROMBank], a + ld [wAudioSavedROMBank], a + ld a, 10 + ld [wAudioFadeOutControl], a + ld a, $FF + ld [wNewSoundID], a + call PlaySound ; stop music + pop af + ld [H_LOADEDROMBANK], a + ld [MBC1RomBank], a + ld c, 20 + call DelayFrames + coord hl, 6, 5 + ld b, 7 + ld c, 7 + call ClearScreenArea + call LoadTextBoxTilePatterns + ld a, 1 + ld [wUpdateSpritesEnabled], a + ld c, 50 + call DelayFrames + call GBFadeOutToWhite + jp ClearScreen +OakSpeechText1: + TX_FAR _OakSpeechText1 + db "@" +OakSpeechText2: + TX_FAR _OakSpeechText2A + TX_CRY_NIDORINA + TX_FAR _OakSpeechText2B + db "@" +IntroducePlayerText: + TX_FAR _IntroducePlayerText + db "@" +IntroduceRivalText: + TX_FAR _IntroduceRivalText + db "@" +OakSpeechText3: + TX_FAR _OakSpeechText3 + db "@" + +FadeInIntroPic: + ld hl, IntroFadePalettes + ld b, 6 +.next + ld a, [hli] + ld [rBGP], a + ld c, 10 + call DelayFrames + dec b + jr nz, .next + ret + +IntroFadePalettes: + db %01010100 + db %10101000 + db %11111100 + db %11111000 + db %11110100 + db %11100100 + +MovePicLeft: + ld a, 119 + ld [rWX], a + call DelayFrame + + ld a, %11100100 + ld [rBGP], a +.next + call DelayFrame + ld a, [rWX] + sub 8 + cp $FF + ret z + ld [rWX], a + jr .next + +DisplayPicCenteredOrUpperRight: + call GetPredefRegisters +IntroDisplayPicCenteredOrUpperRight: +; b = bank +; de = address of compressed pic +; c: 0 = centred, non-zero = upper-right + push bc + ld a, b + call UncompressSpriteFromDE + ld hl, sSpriteBuffer1 + ld de, sSpriteBuffer0 + ld bc, $310 + call CopyData + ld de, vFrontPic + call InterlaceMergeSpriteBuffers + pop bc + ld a, c + and a + coord hl, 15, 1 + jr nz, .next + coord hl, 6, 4 +.next + xor a + ld [hStartTileID], a + predef_jump CopyUncompressedPicToTilemap diff --git a/engine/movie/oak_speech/oak_speech2.asm b/engine/movie/oak_speech/oak_speech2.asm new file mode 100755 index 00000000..fdc9ffa3 --- /dev/null +++ b/engine/movie/oak_speech/oak_speech2.asm @@ -0,0 +1,219 @@ +ChoosePlayerName: + call OakSpeechSlidePicRight + ld de, DefaultNamesPlayer + call DisplayIntroNameTextBox + ld a, [wCurrentMenuItem] + and a + jr z, .customName + ld hl, DefaultNamesPlayerList + call GetDefaultName + ld de, wPlayerName + call OakSpeechSlidePicLeft + jr .done +.customName + ld hl, wPlayerName + xor a ; NAME_PLAYER_SCREEN + ld [wNamingScreenType], a + call DisplayNamingScreen + ld a, [wcf4b] + cp "@" + jr z, .customName + call ClearScreen + call Delay3 + ld de, RedPicFront + ld b, BANK(RedPicFront) + call IntroDisplayPicCenteredOrUpperRight +.done + ld hl, YourNameIsText + jp PrintText + +YourNameIsText: + TX_FAR _YourNameIsText + db "@" + +ChooseRivalName: + call OakSpeechSlidePicRight + ld de, DefaultNamesRival + call DisplayIntroNameTextBox + ld a, [wCurrentMenuItem] + and a + jr z, .customName + ld hl, DefaultNamesRivalList + call GetDefaultName + ld de, wRivalName + call OakSpeechSlidePicLeft + jr .done +.customName + ld hl, wRivalName + ld a, NAME_RIVAL_SCREEN + ld [wNamingScreenType], a + call DisplayNamingScreen + ld a, [wcf4b] + cp "@" + jr z, .customName + call ClearScreen + call Delay3 + ld de, Rival1Pic + ld b, $13 + call IntroDisplayPicCenteredOrUpperRight +.done + ld hl, HisNameIsText + jp PrintText + +HisNameIsText: + TX_FAR _HisNameIsText + db "@" + +OakSpeechSlidePicLeft: + push de + coord hl, 0, 0 + lb bc, 12, 11 + call ClearScreenArea ; clear the name list text box + ld c, 10 + call DelayFrames + pop de + ld hl, wcd6d + ld bc, NAME_LENGTH + call CopyData + call Delay3 + coord hl, 12, 4 + lb de, 6, 6 * SCREEN_WIDTH + 5 + ld a, $ff + jr OakSpeechSlidePicCommon + +OakSpeechSlidePicRight: + coord hl, 5, 4 + lb de, 6, 6 * SCREEN_WIDTH + 5 + xor a + +OakSpeechSlidePicCommon: + push hl + push de + push bc + ld [hSlideDirection], a + ld a, d + ld [hSlideAmount], a + ld a, e + ld [hSlidingRegionSize], a + ld c, a + ld a, [hSlideDirection] + and a + jr nz, .next +; If sliding right, point hl to the end of the pic's tiles. + ld d, 0 + add hl, de +.next + ld d, h + ld e, l +.loop + xor a + ld [H_AUTOBGTRANSFERENABLED], a + ld a, [hSlideDirection] + and a + jr nz, .slideLeft +; sliding right + ld a, [hli] + ld [hld], a + dec hl + jr .next2 +.slideLeft + ld a, [hld] + ld [hli], a + inc hl +.next2 + dec c + jr nz, .loop + ld a, [hSlideDirection] + and a + jr z, .next3 +; 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 + ld [hl], a +.next3 + ld a, 1 + ld [H_AUTOBGTRANSFERENABLED], a + call Delay3 + ld a, [hSlidingRegionSize] + ld c, a + ld h, d + ld l, e + ld a, [hSlideDirection] + and a + jr nz, .slideLeft2 + inc hl + jr .next4 +.slideLeft2 + dec hl +.next4 + ld d, h + ld e, l + ld a, [hSlideAmount] + dec a + ld [hSlideAmount], a + jr nz, .loop + pop bc + pop de + pop hl + ret + +DisplayIntroNameTextBox: + push de + coord hl, 0, 0 + ld b, $a + ld c, $9 + call TextBoxBorder + coord hl, 3, 0 + ld de, .namestring + call PlaceString + pop de + coord hl, 2, 2 + call PlaceString + call UpdateSprites + xor a + ld [wCurrentMenuItem], a + ld [wLastMenuItem], a + inc a + ld [wTopMenuItemX], a + ld [wMenuWatchedKeys], a ; A_BUTTON + inc a + ld [wTopMenuItemY], a + inc a + ld [wMaxMenuItem], a + jp HandleMenuInput + +.namestring + db "NAME@" + +INCLUDE "text/player_names.asm" + +GetDefaultName: +; a = name index +; hl = name list + ld b, a + ld c, 0 +.loop + ld d, h + ld e, l +.innerLoop + ld a, [hli] + cp "@" + jr nz, .innerLoop + ld a, b + cp c + jr z, .foundName + inc c + jr .loop +.foundName + ld h, d + ld l, e + ld de, wcd6d + ld bc, $14 + jp CopyData + +INCLUDE "text/player_names_list.asm" + +TextTerminator_6b20: + db "@" diff --git a/engine/movie/oak_speech2.asm b/engine/movie/oak_speech2.asm deleted file mode 100755 index fdc9ffa3..00000000 --- a/engine/movie/oak_speech2.asm +++ /dev/null @@ -1,219 +0,0 @@ -ChoosePlayerName: - call OakSpeechSlidePicRight - ld de, DefaultNamesPlayer - call DisplayIntroNameTextBox - ld a, [wCurrentMenuItem] - and a - jr z, .customName - ld hl, DefaultNamesPlayerList - call GetDefaultName - ld de, wPlayerName - call OakSpeechSlidePicLeft - jr .done -.customName - ld hl, wPlayerName - xor a ; NAME_PLAYER_SCREEN - ld [wNamingScreenType], a - call DisplayNamingScreen - ld a, [wcf4b] - cp "@" - jr z, .customName - call ClearScreen - call Delay3 - ld de, RedPicFront - ld b, BANK(RedPicFront) - call IntroDisplayPicCenteredOrUpperRight -.done - ld hl, YourNameIsText - jp PrintText - -YourNameIsText: - TX_FAR _YourNameIsText - db "@" - -ChooseRivalName: - call OakSpeechSlidePicRight - ld de, DefaultNamesRival - call DisplayIntroNameTextBox - ld a, [wCurrentMenuItem] - and a - jr z, .customName - ld hl, DefaultNamesRivalList - call GetDefaultName - ld de, wRivalName - call OakSpeechSlidePicLeft - jr .done -.customName - ld hl, wRivalName - ld a, NAME_RIVAL_SCREEN - ld [wNamingScreenType], a - call DisplayNamingScreen - ld a, [wcf4b] - cp "@" - jr z, .customName - call ClearScreen - call Delay3 - ld de, Rival1Pic - ld b, $13 - call IntroDisplayPicCenteredOrUpperRight -.done - ld hl, HisNameIsText - jp PrintText - -HisNameIsText: - TX_FAR _HisNameIsText - db "@" - -OakSpeechSlidePicLeft: - push de - coord hl, 0, 0 - lb bc, 12, 11 - call ClearScreenArea ; clear the name list text box - ld c, 10 - call DelayFrames - pop de - ld hl, wcd6d - ld bc, NAME_LENGTH - call CopyData - call Delay3 - coord hl, 12, 4 - lb de, 6, 6 * SCREEN_WIDTH + 5 - ld a, $ff - jr OakSpeechSlidePicCommon - -OakSpeechSlidePicRight: - coord hl, 5, 4 - lb de, 6, 6 * SCREEN_WIDTH + 5 - xor a - -OakSpeechSlidePicCommon: - push hl - push de - push bc - ld [hSlideDirection], a - ld a, d - ld [hSlideAmount], a - ld a, e - ld [hSlidingRegionSize], a - ld c, a - ld a, [hSlideDirection] - and a - jr nz, .next -; If sliding right, point hl to the end of the pic's tiles. - ld d, 0 - add hl, de -.next - ld d, h - ld e, l -.loop - xor a - ld [H_AUTOBGTRANSFERENABLED], a - ld a, [hSlideDirection] - and a - jr nz, .slideLeft -; sliding right - ld a, [hli] - ld [hld], a - dec hl - jr .next2 -.slideLeft - ld a, [hld] - ld [hli], a - inc hl -.next2 - dec c - jr nz, .loop - ld a, [hSlideDirection] - and a - jr z, .next3 -; 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 - ld [hl], a -.next3 - ld a, 1 - ld [H_AUTOBGTRANSFERENABLED], a - call Delay3 - ld a, [hSlidingRegionSize] - ld c, a - ld h, d - ld l, e - ld a, [hSlideDirection] - and a - jr nz, .slideLeft2 - inc hl - jr .next4 -.slideLeft2 - dec hl -.next4 - ld d, h - ld e, l - ld a, [hSlideAmount] - dec a - ld [hSlideAmount], a - jr nz, .loop - pop bc - pop de - pop hl - ret - -DisplayIntroNameTextBox: - push de - coord hl, 0, 0 - ld b, $a - ld c, $9 - call TextBoxBorder - coord hl, 3, 0 - ld de, .namestring - call PlaceString - pop de - coord hl, 2, 2 - call PlaceString - call UpdateSprites - xor a - ld [wCurrentMenuItem], a - ld [wLastMenuItem], a - inc a - ld [wTopMenuItemX], a - ld [wMenuWatchedKeys], a ; A_BUTTON - inc a - ld [wTopMenuItemY], a - inc a - ld [wMaxMenuItem], a - jp HandleMenuInput - -.namestring - db "NAME@" - -INCLUDE "text/player_names.asm" - -GetDefaultName: -; a = name index -; hl = name list - ld b, a - ld c, 0 -.loop - ld d, h - ld e, l -.innerLoop - ld a, [hli] - cp "@" - jr nz, .innerLoop - ld a, b - cp c - jr z, .foundName - inc c - jr .loop -.foundName - ld h, d - ld l, e - ld de, wcd6d - ld bc, $14 - jp CopyData - -INCLUDE "text/player_names_list.asm" - -TextTerminator_6b20: - db "@" diff --git a/main.asm b/main.asm index 50930bb4..1c3b5800 100755 --- a/main.asm +++ b/main.asm @@ -25,11 +25,11 @@ INCLUDE "engine/events/pick_up_item.asm" INCLUDE "engine/overworld/movement.asm" INCLUDE "engine/link/cable_club.asm" INCLUDE "engine/menus/main_menu.asm" -INCLUDE "engine/movie/oak_speech.asm" +INCLUDE "engine/movie/oak_speech/oak_speech.asm" INCLUDE "engine/overworld/special_warps.asm" INCLUDE "engine/debug/debug_party.asm" INCLUDE "engine/menus/naming_screen.asm" -INCLUDE "engine/movie/oak_speech2.asm" +INCLUDE "engine/movie/oak_speech/oak_speech2.asm" INCLUDE "engine/items/subtract_paid_money.asm" INCLUDE "engine/menus/swap_items.asm" INCLUDE "engine/events/pokemart.asm" @@ -70,7 +70,7 @@ INCLUDE "engine/pokemon/add_mon.asm" INCLUDE "engine/flag_action.asm" INCLUDE "engine/events/heal_party.asm" INCLUDE "engine/math/bcd.asm" -INCLUDE "engine/movie/init_player_data.asm" +INCLUDE "engine/movie/oak_speech/init_player_data.asm" INCLUDE "engine/items/get_bag_item_quantity.asm" INCLUDE "engine/overworld/pathfinding.asm" INCLUDE "engine/gfx/hp_bar.asm" @@ -150,7 +150,7 @@ INCLUDE "engine/overworld/ledges.asm" SECTION "bank7_1", ROMX INCLUDE "text/monster_names.asm" -INCLUDE "engine/movie/clear_save.asm" +INCLUDE "engine/movie/oak_speech/clear_save.asm" INCLUDE "engine/events/elevator.asm" -- cgit v1.2.3