From e30e37ea43c9f223b711b9f05219fd3e665d5a0c Mon Sep 17 00:00:00 2001 From: Tino Date: Wed, 15 May 2024 08:51:38 +0200 Subject: [PATCH] Fix player running one additional tile before re-applying Repel The repel listener had an issue where it would close the notification message about repel expiring, but then yield control back to the bot mode for one extra frame before attempting to re-apply another repel. If that happened in or right next to tall grass, that would mean that the player moved inside the grass and might lead to an unexpected encounter. The bot would then hang because it would keep spamming `Start` to open the menu. --- modules/modes/_listeners.py | 10 ++++++++-- modules/modes/puzzle_solver.py | 3 +-- modules/modes/roamer_reset.py | 3 +-- modules/modes/rock_smash.py | 5 ++--- modules/modes/util/items.py | 19 ------------------- 5 files changed, 12 insertions(+), 28 deletions(-) diff --git a/modules/modes/_listeners.py b/modules/modes/_listeners.py index 218b705d7..68ddb19ce 100644 --- a/modules/modes/_listeners.py +++ b/modules/modes/_listeners.py @@ -1,4 +1,5 @@ -import signal +import inspect +from types import GeneratorType from modules.battle import BattleHandler, BattleOutcome, RotatePokemon, check_lead_can_battle, flee_battle from modules.context import context @@ -254,11 +255,16 @@ def handle_frame(self, bot_mode: BotMode, frame: FrameInfo): @isolate_inputs @debug.track def handle_repel_expiration_message(self, bot_mode: BotMode): + previous_inputs = context.emulator.reset_held_buttons() while self._script_name in get_global_script_context().stack: context.emulator.press_button("B") yield + context.emulator.restore_held_buttons(previous_inputs) self._message_active = False - bot_mode.on_repel_effect_ended() + + mode_callback_result = bot_mode.on_repel_effect_ended() + if isinstance(mode_callback_result, GeneratorType): + yield from mode_callback_result class PoisonListener(BotListener): diff --git a/modules/modes/puzzle_solver.py b/modules/modes/puzzle_solver.py index 5da13d310..a9123ec07 100644 --- a/modules/modes/puzzle_solver.py +++ b/modules/modes/puzzle_solver.py @@ -20,7 +20,6 @@ wait_for_task_to_start_and_finish, walk_one_tile, apply_repel, - replenish_repel, ) @@ -62,7 +61,7 @@ def is_selectable() -> bool: return False def on_repel_effect_ended(self) -> None: - replenish_repel() + yield from apply_repel() def run(self) -> Generator: assert_no_auto_battle("This mode should not be used with auto-battle.") diff --git a/modules/modes/roamer_reset.py b/modules/modes/roamer_reset.py index a5118342c..06c6da278 100644 --- a/modules/modes/roamer_reset.py +++ b/modules/modes/roamer_reset.py @@ -23,7 +23,6 @@ ensure_facing_direction, fly_to, navigate_to, - replenish_repel, soft_reset, wait_for_player_avatar_to_be_standing_still, wait_for_unique_rng_value, @@ -70,7 +69,7 @@ def __init__(self): def on_repel_effect_ended(self) -> None: try: - replenish_repel() + yield from apply_repel() except RanOutOfRepels: self._ran_out_of_repels = True diff --git a/modules/modes/rock_smash.py b/modules/modes/rock_smash.py index 4a7f7208f..45b132105 100644 --- a/modules/modes/rock_smash.py +++ b/modules/modes/rock_smash.py @@ -25,7 +25,6 @@ apply_white_flute_if_available, ensure_facing_direction, follow_path, - replenish_repel, soft_reset, wait_for_player_avatar_to_be_standing_still, wait_for_script_to_start_and_finish, @@ -69,9 +68,9 @@ def on_battle_started(self) -> BattleAction | None: def on_repel_effect_ended(self) -> None: if self._using_repel: try: - replenish_repel() + yield from apply_repel() except RanOutOfRepels: - context.controller_stack.insert(len(context.controller_stack) - 1, self.reset_and_wait()) + yield from self.reset_and_wait() def run(self) -> Generator: self._in_safari_zone = False diff --git a/modules/modes/util/items.py b/modules/modes/util/items.py index 77c4494d0..251cd6fef 100644 --- a/modules/modes/util/items.py +++ b/modules/modes/util/items.py @@ -136,25 +136,6 @@ def apply_repel() -> Generator: yield from use_item_from_bag(repel_item) -def replenish_repel() -> None: - """ - This can be used in a bot mode's `on_repel_effect_ended()` callback to re-enable the repel - effect as soon as it expires. - - It should not be used anywhere else. - """ - - if get_item_bag().number_of_repels == 0: - raise RanOutOfRepels("Player ran out of repels") - else: - - def apply_repel_and_reset_inputs(): - yield from apply_repel() - context.emulator.reset_held_buttons() - - context.controller_stack.insert(len(context.controller_stack) - 1, apply_repel_and_reset_inputs()) - - @debug.track def teach_hm_or_tm(hm_or_tm: Item, party_index: int, move_index_to_replace: int = 3) -> Generator: """