Skip to content

Commit

Permalink
Fix player running one additional tile before re-applying Repel
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
hanzi committed May 23, 2024
1 parent 8f86846 commit e30e37e
Show file tree
Hide file tree
Showing 5 changed files with 12 additions and 28 deletions.
10 changes: 8 additions & 2 deletions modules/modes/_listeners.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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):
Expand Down
3 changes: 1 addition & 2 deletions modules/modes/puzzle_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
wait_for_task_to_start_and_finish,
walk_one_tile,
apply_repel,
replenish_repel,
)


Expand Down Expand Up @@ -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.")
Expand Down
3 changes: 1 addition & 2 deletions modules/modes/roamer_reset.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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

Expand Down
5 changes: 2 additions & 3 deletions modules/modes/rock_smash.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
19 changes: 0 additions & 19 deletions modules/modes/util/items.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
"""
Expand Down

0 comments on commit e30e37e

Please sign in to comment.