From 067c38d1555a8410e395d8c9ae4006fd0aa4c3cf Mon Sep 17 00:00:00 2001 From: Neka Date: Mon, 11 Nov 2024 00:48:04 +0100 Subject: [PATCH 1/2] Prevent catching modes from starting when no Pokeballs available --- modules/items.py | 4 ++++ modules/modes/bunny_hop.py | 20 +++++++++++++++++++- modules/modes/feebas.py | 10 ++++++++++ modules/modes/fishing.py | 9 +++++++++ modules/modes/kecleon.py | 4 ++++ modules/modes/roamer_reset.py | 4 ++++ modules/modes/rock_smash.py | 18 ++++++++++++++++++ modules/modes/spin.py | 9 +++++++++ modules/modes/static_run_away.py | 5 +++++ modules/modes/static_soft_resets.py | 5 +++++ modules/modes/sudowoodo.py | 6 ++++++ modules/modes/sweet_scent.py | 19 +++++++++++++++++++ 12 files changed, 112 insertions(+), 1 deletion(-) diff --git a/modules/items.py b/modules/items.py index 1055344a..f5d5c7fd 100644 --- a/modules/items.py +++ b/modules/items.py @@ -385,6 +385,10 @@ def first_slot_index_for(self, item: Item) -> int | None: def number_of_repels(self) -> int: return sum(slot.quantity for slot in self.items if slot.item.name in ("Repel", "Super Repel", "Max Repel")) + @property + def number_of_balls_except_master_ball(self) -> int: + return sum(slot.quantity for slot in self.poke_balls if slot.item.index != 1) + def to_dict(self) -> dict: return { "items": [s.to_dict() for s in self.items], diff --git a/modules/modes/bunny_hop.py b/modules/modes/bunny_hop.py index 6006980f..b3077abc 100644 --- a/modules/modes/bunny_hop.py +++ b/modules/modes/bunny_hop.py @@ -1,8 +1,11 @@ from typing import Generator from modules.context import context -from modules.items import get_item_by_name +from modules.items import get_item_by_name, get_item_bag from modules.player import AcroBikeState, TileTransitionState, get_player_avatar +from modules.battle_state import BattleOutcome +from modules.safari_strategy import get_safari_balls_left +from modules.map_data import is_safari_map from ._asserts import assert_item_exists_in_bag from ._interface import BotMode from .util import apply_white_flute_if_available, register_key_item @@ -20,7 +23,22 @@ def is_selectable() -> bool: else: return False + def on_battle_ended(self, outcome: "BattleOutcome") -> None: + if is_safari_map(): + balls_left = get_safari_balls_left() + if balls_left <= 15: + context.message = "You have less than 15 balls left, switching to manual mode..." + return context.set_manual_mode() + else: + if not outcome == BattleOutcome.Lost and get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() + def run(self) -> Generator: + if get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() + assert_item_exists_in_bag(("Acro Bike",), "You need to have the Acro Bike in order to use this mode.") yield from register_key_item(get_item_by_name("Acro Bike")) diff --git a/modules/modes/feebas.py b/modules/modes/feebas.py index 6ffae2fb..d435f256 100644 --- a/modules/modes/feebas.py +++ b/modules/modes/feebas.py @@ -7,6 +7,7 @@ from modules.map_data import MapRSE from modules.player import get_player, get_player_avatar, AvatarFlags from modules.pokemon import get_party +from modules.battle_state import BattleOutcome from . import BattleAction from ._interface import BotMode, BotModeError from .util import ( @@ -146,7 +147,16 @@ def on_battle_started(self, encounter: EncounterInfo | None) -> BattleAction | N return None + def on_battle_ended(self, outcome: "BattleOutcome") -> None: + if not outcome == BattleOutcome.Lost and get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() + def run(self) -> Generator: + if get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() + if not get_player_avatar().flags.Surfing: raise BotModeError("Player is not surfing, only start this mode while surfing in any water at Route 119.") diff --git a/modules/modes/fishing.py b/modules/modes/fishing.py index be24ae02..201a94aa 100644 --- a/modules/modes/fishing.py +++ b/modules/modes/fishing.py @@ -6,6 +6,7 @@ from modules.player import get_player, get_player_avatar from modules.runtime import get_sprites_path from modules.map_data import is_safari_map +from modules.battle_state import BattleOutcome from modules.safari_strategy import get_safari_balls_left from ._asserts import assert_item_exists_in_bag from ._interface import BotMode @@ -29,8 +30,16 @@ def on_battle_ended(self, outcome: "BattleOutcome") -> None: if balls_left <= 15: context.message = "You have less than 15 balls left, switching to manual mode..." return context.set_manual_mode() + else: + if not outcome == BattleOutcome.Lost and get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() def run(self) -> Generator: + if get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() + # Ask player to register a rod if they have one rod_names = ["Old Rod", "Good Rod", "Super Rod"] assert_item_exists_in_bag(rod_names, "You do not own any fishing rod, so you cannot fish.") diff --git a/modules/modes/kecleon.py b/modules/modes/kecleon.py index de6eef8d..a1bf8357 100644 --- a/modules/modes/kecleon.py +++ b/modules/modes/kecleon.py @@ -2,6 +2,7 @@ from modules.context import context from modules.encounter import handle_encounter, EncounterInfo +from modules.items import get_item_bag from modules.map_data import MapRSE from modules.memory import get_event_flag from modules.player import get_player_avatar @@ -43,6 +44,9 @@ def on_whiteout(self) -> bool: return True def run(self) -> Generator: + if get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() assert_has_pokemon_with_move("Selfdestruct", "This mode requires a Pokémon with the move Selfdestruct.") if not (get_event_flag("RECEIVED_DEVON_SCOPE")): raise BotModeError("This mode requires the Devon Scope.") diff --git a/modules/modes/roamer_reset.py b/modules/modes/roamer_reset.py index 286761fd..040818e5 100644 --- a/modules/modes/roamer_reset.py +++ b/modules/modes/roamer_reset.py @@ -115,6 +115,10 @@ def run(self) -> Generator: f"{highest_encounter_level + 1} in order for Repel to work." ) + if save_data.get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() + if save_data.get_item_bag().number_of_repels == 0: raise BotModeError("You do not have any repels in your item bag. Go and get some first!") diff --git a/modules/modes/rock_smash.py b/modules/modes/rock_smash.py index c6487284..3cbb8002 100644 --- a/modules/modes/rock_smash.py +++ b/modules/modes/rock_smash.py @@ -13,6 +13,9 @@ from modules.player import TileTransitionState, get_player, get_player_avatar, AvatarFlags, get_player_location from modules.pokemon import get_opponent from modules.runtime import get_sprites_path +from modules.battle_state import BattleOutcome +from modules.safari_strategy import get_safari_balls_left +from modules.map_data import is_safari_map from modules.save_data import get_save_data from modules.tasks import task_is_active, get_global_script_context from . import BattleAction @@ -81,6 +84,17 @@ def on_battle_started(self, encounter: EncounterInfo | None) -> BattleAction | N debug.debug_values["Nosepass per Hour"] = encounter_rate_at_1x return handle_encounter(encounter) + def on_battle_ended(self, outcome: "BattleOutcome") -> None: + if is_safari_map(): + balls_left = get_safari_balls_left() + if balls_left <= 15: + context.message = "You have less than 15 balls left, switching to manual mode..." + return context.set_manual_mode() + else: + if not outcome == BattleOutcome.Lost and get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() + def on_repel_effect_ended(self) -> None: if self._using_repel: try: @@ -113,6 +127,10 @@ def run(self) -> Generator: "In order to rock smash for Shuckle you should save in the entrance building to the Safari Zone.", ) + if get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() + if get_player_avatar().map_group_and_number == MapRSE.GRANITE_CAVE_B2F and get_item_bag().number_of_repels > 0: mode = ask_for_choice( [ diff --git a/modules/modes/spin.py b/modules/modes/spin.py index fef996b3..e043eb37 100644 --- a/modules/modes/spin.py +++ b/modules/modes/spin.py @@ -3,7 +3,9 @@ from modules.context import context from modules.player import get_player_avatar from modules.map_data import is_safari_map +from modules.items import get_item_bag from modules.safari_strategy import get_safari_balls_left +from modules.battle_state import BattleOutcome from ._interface import BotMode from .util import apply_white_flute_if_available, spin @@ -23,7 +25,14 @@ def on_battle_ended(self, outcome: "BattleOutcome") -> None: if balls_left <= 15: context.message = "You have less than 15 balls left, switching to manual mode..." return context.set_manual_mode() + else: + if not outcome == BattleOutcome.Lost and get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() def run(self) -> Generator: + if get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() yield from apply_white_flute_if_available() yield from spin() diff --git a/modules/modes/static_run_away.py b/modules/modes/static_run_away.py index e7535487..fed7af48 100644 --- a/modules/modes/static_run_away.py +++ b/modules/modes/static_run_away.py @@ -7,6 +7,7 @@ from modules.memory import get_event_flag from modules.player import get_player_avatar from modules.pokemon import get_opponent +from modules.items import get_item_bag from ._interface import BattleAction, BotMode, BotModeError from .util import ( follow_path, @@ -183,6 +184,10 @@ def path(): if get_event_flag(flag_to_check): raise BotModeError(f"{pokemon_name} has already been caught.") + if get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() + while True: yield from path() diff --git a/modules/modes/static_soft_resets.py b/modules/modes/static_soft_resets.py index 8238132e..7a903cd1 100644 --- a/modules/modes/static_soft_resets.py +++ b/modules/modes/static_soft_resets.py @@ -6,6 +6,7 @@ from modules.map_data import MapFRLG, MapRSE from modules.player import get_player_avatar from modules.save_data import get_save_data +from modules.items import get_item_bag from ._asserts import SavedMapLocation, assert_save_game_exists, assert_saved_on_map from ._interface import BattleAction, BotMode, BotModeError from .util import ( @@ -105,6 +106,10 @@ def run(self) -> Generator: if encounter.condition is not None and not encounter.condition(): raise BotModeError(f"This {encounter.name} has already been encountered.") + if get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() + while context.bot_mode != "Manual": yield from soft_reset(mash_random_keys=True) yield from wait_for_unique_rng_value() diff --git a/modules/modes/sudowoodo.py b/modules/modes/sudowoodo.py index c18735df..5031bf81 100644 --- a/modules/modes/sudowoodo.py +++ b/modules/modes/sudowoodo.py @@ -4,6 +4,7 @@ from modules.encounter import handle_encounter, log_encounter, EncounterInfo from modules.map_data import MapRSE from modules.player import get_player_avatar +from modules.items import get_item_bag from ._asserts import SavedMapLocation, assert_registered_item, assert_save_game_exists, assert_saved_on_map from ._interface import BattleAction, BotMode from .util import soft_reset, wait_for_task_to_start_and_finish, wait_for_unique_rng_value, wait_until_task_is_active @@ -33,12 +34,17 @@ def run(self) -> Generator: SavedMapLocation(MapRSE.BATTLE_FRONTIER_OUTSIDE_EAST, (54, 62), facing=True), "The game has not been saved on this tile.", ) + assert_registered_item( ["Wailmer Pail"], "You need to register the Wailmer Pail for the Select button.", check_in_saved_game=True, ) + if get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() + while context.bot_mode != "Manual": yield from soft_reset(mash_random_keys=True) yield from wait_for_unique_rng_value() diff --git a/modules/modes/sweet_scent.py b/modules/modes/sweet_scent.py index 0d2a283f..5ba1c4ab 100644 --- a/modules/modes/sweet_scent.py +++ b/modules/modes/sweet_scent.py @@ -6,6 +6,10 @@ from modules.menuing import PokemonPartyMenuNavigator, StartMenuNavigator from modules.modes._asserts import assert_has_pokemon_with_move from modules.player import get_player_avatar +from modules.items import get_item_bag +from modules.map_data import is_safari_map +from modules.battle_state import BattleOutcome +from modules.safari_strategy import get_safari_balls_left from modules.pokemon import get_move_by_name, get_party from ._interface import BotMode @@ -19,7 +23,22 @@ def name() -> str: def is_selectable() -> bool: return get_player_avatar().map_location.has_encounters + def on_battle_ended(self, outcome: "BattleOutcome") -> None: + if is_safari_map(): + balls_left = get_safari_balls_left() + if balls_left <= 15: + context.message = "You have less than 15 balls left, switching to manual mode..." + return context.set_manual_mode() + else: + if not outcome == BattleOutcome.Lost and get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() + def run(self) -> Generator: + if get_item_bag().number_of_balls_except_master_ball == 0: + context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." + return context.set_manual_mode() + assert_has_pokemon_with_move( "Sweet Scent", "None of your party Pokémon know the move Sweet Scent. Please teach it to someone." ) From ca821aa15bf2e35ec9d1738300784d8038984211 Mon Sep 17 00:00:00 2001 From: Neka Date: Mon, 11 Nov 2024 02:46:00 +0100 Subject: [PATCH 2/2] Add an assert to check for ball count before starting a catching mode --- modules/modes/_asserts.py | 17 ++++++++++++++++- modules/modes/bunny_hop.py | 22 +++++----------------- modules/modes/feebas.py | 10 ++++------ modules/modes/fishing.py | 19 ++++--------------- modules/modes/kecleon.py | 9 ++------- modules/modes/roamer_reset.py | 6 ++---- modules/modes/rock_smash.py | 25 ++++++++++--------------- modules/modes/spin.py | 19 ++++--------------- modules/modes/static_run_away.py | 6 ++---- modules/modes/static_soft_resets.py | 7 ++----- modules/modes/sudowoodo.py | 13 ++++++++----- modules/modes/sweet_scent.py | 19 ++++--------------- 12 files changed, 63 insertions(+), 109 deletions(-) diff --git a/modules/modes/_asserts.py b/modules/modes/_asserts.py index 1c5a0d6d..d74a863a 100644 --- a/modules/modes/_asserts.py +++ b/modules/modes/_asserts.py @@ -3,7 +3,9 @@ from modules.context import context from modules.items import get_item_bag, get_item_by_name from modules.map import ObjectEvent, calculate_targeted_coords -from modules.map_data import MapRSE, MapFRLG +from modules.map_data import MapRSE, MapFRLG, is_safari_map +from modules.safari_strategy import get_safari_balls_left +from modules.battle_state import BattleOutcome from modules.player import get_player from modules.pokemon import get_party from modules.save_data import get_save_data @@ -161,3 +163,16 @@ def assert_empty_slot_in_party(error_message: str, check_in_saved_game: bool = F if check_in_saved_game and len(get_party()) < 6: error_message += _error_message_addendum_if_assert_only_failed_in_saved_game raise BotModeError(error_message) + + +def assert_player_has_poke_balls() -> None: + """ + Raises an exception if the player doesn't have any Pokeballs when starting a catching mode + or if safari ball threshold is reached. + """ + if is_safari_map(): + if context.rom.is_frlg and get_safari_balls_left() <= 15: + raise BotModeError("You have less than 15 balls left, switching to manual mode...") + else: + if get_item_bag().number_of_balls_except_master_ball == 0: + raise BotModeError("Out of Pokéballs! Better grab more before the next shiny slips away...") diff --git a/modules/modes/bunny_hop.py b/modules/modes/bunny_hop.py index b3077abc..62d874ab 100644 --- a/modules/modes/bunny_hop.py +++ b/modules/modes/bunny_hop.py @@ -1,12 +1,10 @@ from typing import Generator from modules.context import context -from modules.items import get_item_by_name, get_item_bag +from modules.items import get_item_by_name from modules.player import AcroBikeState, TileTransitionState, get_player_avatar from modules.battle_state import BattleOutcome -from modules.safari_strategy import get_safari_balls_left -from modules.map_data import is_safari_map -from ._asserts import assert_item_exists_in_bag +from ._asserts import assert_item_exists_in_bag, assert_player_has_poke_balls from ._interface import BotMode from .util import apply_white_flute_if_available, register_key_item @@ -24,21 +22,11 @@ def is_selectable() -> bool: return False def on_battle_ended(self, outcome: "BattleOutcome") -> None: - if is_safari_map(): - balls_left = get_safari_balls_left() - if balls_left <= 15: - context.message = "You have less than 15 balls left, switching to manual mode..." - return context.set_manual_mode() - else: - if not outcome == BattleOutcome.Lost and get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() + if not outcome == BattleOutcome.Lost: + assert_player_has_poke_balls() def run(self) -> Generator: - if get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() - + assert_player_has_poke_balls() assert_item_exists_in_bag(("Acro Bike",), "You need to have the Acro Bike in order to use this mode.") yield from register_key_item(get_item_by_name("Acro Bike")) diff --git a/modules/modes/feebas.py b/modules/modes/feebas.py index d435f256..f1829c48 100644 --- a/modules/modes/feebas.py +++ b/modules/modes/feebas.py @@ -9,6 +9,7 @@ from modules.pokemon import get_party from modules.battle_state import BattleOutcome from . import BattleAction +from ._asserts import assert_player_has_poke_balls from ._interface import BotMode, BotModeError from .util import ( ensure_facing_direction, @@ -148,14 +149,11 @@ def on_battle_started(self, encounter: EncounterInfo | None) -> BattleAction | N return None def on_battle_ended(self, outcome: "BattleOutcome") -> None: - if not outcome == BattleOutcome.Lost and get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() + if not outcome == BattleOutcome.Lost: + assert_player_has_poke_balls() def run(self) -> Generator: - if get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() + assert_player_has_poke_balls() if not get_player_avatar().flags.Surfing: raise BotModeError("Player is not surfing, only start this mode while surfing in any water at Route 119.") diff --git a/modules/modes/fishing.py b/modules/modes/fishing.py index 201a94aa..9a8ac5da 100644 --- a/modules/modes/fishing.py +++ b/modules/modes/fishing.py @@ -5,10 +5,8 @@ from modules.items import get_item_bag, get_item_by_name from modules.player import get_player, get_player_avatar from modules.runtime import get_sprites_path -from modules.map_data import is_safari_map from modules.battle_state import BattleOutcome -from modules.safari_strategy import get_safari_balls_left -from ._asserts import assert_item_exists_in_bag +from ._asserts import assert_item_exists_in_bag, assert_player_has_poke_balls from ._interface import BotMode from .util import fish, register_key_item @@ -25,20 +23,11 @@ def is_selectable() -> bool: return targeted_tile is not None and targeted_tile.is_surfable def on_battle_ended(self, outcome: "BattleOutcome") -> None: - if is_safari_map(): - balls_left = get_safari_balls_left() - if balls_left <= 15: - context.message = "You have less than 15 balls left, switching to manual mode..." - return context.set_manual_mode() - else: - if not outcome == BattleOutcome.Lost and get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() + if not outcome == BattleOutcome.Lost: + assert_player_has_poke_balls() def run(self) -> Generator: - if get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() + assert_player_has_poke_balls() # Ask player to register a rod if they have one rod_names = ["Old Rod", "Good Rod", "Super Rod"] diff --git a/modules/modes/kecleon.py b/modules/modes/kecleon.py index a1bf8357..411bb044 100644 --- a/modules/modes/kecleon.py +++ b/modules/modes/kecleon.py @@ -2,16 +2,13 @@ from modules.context import context from modules.encounter import handle_encounter, EncounterInfo -from modules.items import get_item_bag from modules.map_data import MapRSE from modules.memory import get_event_flag from modules.player import get_player_avatar from modules.pokemon import get_party from modules.save_data import get_last_heal_location from . import BattleAction -from ._asserts import ( - assert_has_pokemon_with_move, -) +from ._asserts import assert_has_pokemon_with_move, assert_player_has_poke_balls from ._interface import BotMode, BotModeError from .util import ensure_facing_direction, navigate_to from ..battle_strategies import BattleStrategy @@ -44,9 +41,7 @@ def on_whiteout(self) -> bool: return True def run(self) -> Generator: - if get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() + assert_player_has_poke_balls() assert_has_pokemon_with_move("Selfdestruct", "This mode requires a Pokémon with the move Selfdestruct.") if not (get_event_flag("RECEIVED_DEVON_SCOPE")): raise BotModeError("This mode requires the Devon Scope.") diff --git a/modules/modes/roamer_reset.py b/modules/modes/roamer_reset.py index 040818e5..2827b476 100644 --- a/modules/modes/roamer_reset.py +++ b/modules/modes/roamer_reset.py @@ -14,7 +14,7 @@ from modules.runtime import get_sprites_path from modules.save_data import get_save_data from modules.tasks import get_global_script_context -from ._asserts import SavedMapLocation, assert_save_game_exists, assert_saved_on_map +from ._asserts import SavedMapLocation, assert_save_game_exists, assert_saved_on_map, assert_player_has_poke_balls from ._interface import BattleAction, BotMode, BotModeError from .util import ( RanOutOfRepels, @@ -115,9 +115,7 @@ def run(self) -> Generator: f"{highest_encounter_level + 1} in order for Repel to work." ) - if save_data.get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() + assert_player_has_poke_balls() if save_data.get_item_bag().number_of_repels == 0: raise BotModeError("You do not have any repels in your item bag. Go and get some first!") diff --git a/modules/modes/rock_smash.py b/modules/modes/rock_smash.py index 3cbb8002..0ad3e61b 100644 --- a/modules/modes/rock_smash.py +++ b/modules/modes/rock_smash.py @@ -14,12 +14,16 @@ from modules.pokemon import get_opponent from modules.runtime import get_sprites_path from modules.battle_state import BattleOutcome -from modules.safari_strategy import get_safari_balls_left -from modules.map_data import is_safari_map from modules.save_data import get_save_data from modules.tasks import task_is_active, get_global_script_context from . import BattleAction -from ._asserts import SavedMapLocation, assert_has_pokemon_with_move, assert_save_game_exists, assert_saved_on_map +from ._asserts import ( + SavedMapLocation, + assert_has_pokemon_with_move, + assert_save_game_exists, + assert_saved_on_map, + assert_player_has_poke_balls, +) from ._interface import BotMode, BotModeError from .util import ( navigate_to, @@ -85,15 +89,8 @@ def on_battle_started(self, encounter: EncounterInfo | None) -> BattleAction | N return handle_encounter(encounter) def on_battle_ended(self, outcome: "BattleOutcome") -> None: - if is_safari_map(): - balls_left = get_safari_balls_left() - if balls_left <= 15: - context.message = "You have less than 15 balls left, switching to manual mode..." - return context.set_manual_mode() - else: - if not outcome == BattleOutcome.Lost and get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() + if not outcome == BattleOutcome.Lost: + assert_player_has_poke_balls() def on_repel_effect_ended(self) -> None: if self._using_repel: @@ -127,9 +124,7 @@ def run(self) -> Generator: "In order to rock smash for Shuckle you should save in the entrance building to the Safari Zone.", ) - if get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() + assert_player_has_poke_balls() if get_player_avatar().map_group_and_number == MapRSE.GRANITE_CAVE_B2F and get_item_bag().number_of_repels > 0: mode = ask_for_choice( diff --git a/modules/modes/spin.py b/modules/modes/spin.py index e043eb37..3ad9fb12 100644 --- a/modules/modes/spin.py +++ b/modules/modes/spin.py @@ -2,11 +2,9 @@ from modules.context import context from modules.player import get_player_avatar -from modules.map_data import is_safari_map -from modules.items import get_item_bag -from modules.safari_strategy import get_safari_balls_left from modules.battle_state import BattleOutcome from ._interface import BotMode +from ._asserts import assert_player_has_poke_balls from .util import apply_white_flute_if_available, spin @@ -20,19 +18,10 @@ def is_selectable() -> bool: return get_player_avatar().map_location.has_encounters def on_battle_ended(self, outcome: "BattleOutcome") -> None: - if is_safari_map(): - balls_left = get_safari_balls_left() - if balls_left <= 15: - context.message = "You have less than 15 balls left, switching to manual mode..." - return context.set_manual_mode() - else: - if not outcome == BattleOutcome.Lost and get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() + if not outcome == BattleOutcome.Lost: + assert_player_has_poke_balls() def run(self) -> Generator: - if get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() + assert_player_has_poke_balls() yield from apply_white_flute_if_available() yield from spin() diff --git a/modules/modes/static_run_away.py b/modules/modes/static_run_away.py index fed7af48..d4a74bae 100644 --- a/modules/modes/static_run_away.py +++ b/modules/modes/static_run_away.py @@ -7,7 +7,7 @@ from modules.memory import get_event_flag from modules.player import get_player_avatar from modules.pokemon import get_opponent -from modules.items import get_item_bag +from ._asserts import assert_player_has_poke_balls from ._interface import BattleAction, BotMode, BotModeError from .util import ( follow_path, @@ -184,9 +184,7 @@ def path(): if get_event_flag(flag_to_check): raise BotModeError(f"{pokemon_name} has already been caught.") - if get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() + assert_player_has_poke_balls() while True: yield from path() diff --git a/modules/modes/static_soft_resets.py b/modules/modes/static_soft_resets.py index 7a903cd1..d0327114 100644 --- a/modules/modes/static_soft_resets.py +++ b/modules/modes/static_soft_resets.py @@ -6,8 +6,7 @@ from modules.map_data import MapFRLG, MapRSE from modules.player import get_player_avatar from modules.save_data import get_save_data -from modules.items import get_item_bag -from ._asserts import SavedMapLocation, assert_save_game_exists, assert_saved_on_map +from ._asserts import SavedMapLocation, assert_save_game_exists, assert_saved_on_map, assert_player_has_poke_balls from ._interface import BattleAction, BotMode, BotModeError from .util import ( soft_reset, @@ -106,9 +105,7 @@ def run(self) -> Generator: if encounter.condition is not None and not encounter.condition(): raise BotModeError(f"This {encounter.name} has already been encountered.") - if get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() + assert_player_has_poke_balls() while context.bot_mode != "Manual": yield from soft_reset(mash_random_keys=True) diff --git a/modules/modes/sudowoodo.py b/modules/modes/sudowoodo.py index 5031bf81..2fe62f52 100644 --- a/modules/modes/sudowoodo.py +++ b/modules/modes/sudowoodo.py @@ -4,8 +4,13 @@ from modules.encounter import handle_encounter, log_encounter, EncounterInfo from modules.map_data import MapRSE from modules.player import get_player_avatar -from modules.items import get_item_bag -from ._asserts import SavedMapLocation, assert_registered_item, assert_save_game_exists, assert_saved_on_map +from ._asserts import ( + SavedMapLocation, + assert_registered_item, + assert_save_game_exists, + assert_saved_on_map, + assert_player_has_poke_balls, +) from ._interface import BattleAction, BotMode from .util import soft_reset, wait_for_task_to_start_and_finish, wait_for_unique_rng_value, wait_until_task_is_active @@ -41,9 +46,7 @@ def run(self) -> Generator: check_in_saved_game=True, ) - if get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() + assert_player_has_poke_balls() while context.bot_mode != "Manual": yield from soft_reset(mash_random_keys=True) diff --git a/modules/modes/sweet_scent.py b/modules/modes/sweet_scent.py index 5ba1c4ab..61a7a069 100644 --- a/modules/modes/sweet_scent.py +++ b/modules/modes/sweet_scent.py @@ -6,11 +6,9 @@ from modules.menuing import PokemonPartyMenuNavigator, StartMenuNavigator from modules.modes._asserts import assert_has_pokemon_with_move from modules.player import get_player_avatar -from modules.items import get_item_bag -from modules.map_data import is_safari_map from modules.battle_state import BattleOutcome -from modules.safari_strategy import get_safari_balls_left from modules.pokemon import get_move_by_name, get_party +from ._asserts import assert_player_has_poke_balls from ._interface import BotMode @@ -24,20 +22,11 @@ def is_selectable() -> bool: return get_player_avatar().map_location.has_encounters def on_battle_ended(self, outcome: "BattleOutcome") -> None: - if is_safari_map(): - balls_left = get_safari_balls_left() - if balls_left <= 15: - context.message = "You have less than 15 balls left, switching to manual mode..." - return context.set_manual_mode() - else: - if not outcome == BattleOutcome.Lost and get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() + if not outcome == BattleOutcome.Lost: + assert_player_has_poke_balls() def run(self) -> Generator: - if get_item_bag().number_of_balls_except_master_ball == 0: - context.message = "Out of Poké Balls! Better grab more before the next shiny slips away..." - return context.set_manual_mode() + assert_player_has_poke_balls() assert_has_pokemon_with_move( "Sweet Scent", "None of your party Pokémon know the move Sweet Scent. Please teach it to someone."