diff --git a/modules/data/symbols/patches/language/pokeemerald.yml b/modules/data/symbols/patches/language/pokeemerald.yml index c2ea969e..4e2d1d9c 100644 --- a/modules/data/symbols/patches/language/pokeemerald.yml +++ b/modules/data/symbols/patches/language/pokeemerald.yml @@ -384,18 +384,6 @@ EventScript_DoTrainerBattle: I: 0x82710ab J: 0x82424ee S: 0x8275258 -EventScript_RockSmash: - D: 0x829ef03 - F: 0x8297028 - I: 0x829146e - J: 0x825667c - S: 0x8295638 -EventScript_SmashRock: - D: 0x829ef58 - F: 0x829707d - I: 0x82914c3 - J: 0x82566d1 - S: 0x829568d EventScript_EggHatch: D: 0x82a0780 F: 0x829887c @@ -611,12 +599,6 @@ LittlerootTown_ProfessorBirchsLab_EventScript_UpgradeToNationalDex: I: 0x81f9a6d J: 0x81f141b S: 0x81fa666 -SafariZone_EventScript_TimesUp: - D: 0x82b676d - F: 0x82ad154 - I: 0x82a6033 - J: 0x82623e9 - S: 0x82aae5a SouthernIsland_Interior_EventScript_Lati: D: 0x824b6cd F: 0x8247d7c @@ -815,4 +797,47 @@ EventScript_RepelWoreOff: S: 0x82aadeb gSpecialVar_0x8004: J: 0x2037280 -#----------------# \ No newline at end of file +#----------------# + +#-----------------# +# Rock Smash # +#-----------------# +EventScript_RockSmash: + D: 0x829ef03 + F: 0x8297028 + I: 0x829146e + J: 0x825667c + S: 0x8295638 +EventScript_SmashRock: + D: 0x829ef58 + F: 0x829707d + I: 0x82914c3 + J: 0x82566d1 + S: 0x829568d +sSafariZoneStepCounter: + J: 0x2039d1a +gNumSafariBalls: + J: 0x2039d18 +# 0xb +SafariZone_EventScript_TimesUp: + D: 0x82b676d + F: 0x82ad154 + I: 0x82a6033 + J: 0x82623e8 + S: 0x82aae5a +# 0xb +Route121_SafariZoneEntrance_EventScript_ExitSafariZone: + D: 0x8232697 + F: 0x822fb48 + I: 0x822b9b9 + J: 0x82129eb + S: 0x822de23 + +# We map it here to exit Safari otherwise the RepelScript is mapping at this address +MatchCall_PersonalizedText20: + F: 0x82ad142 +MatchCall_Text_MrStone10: + D: 0x82b675b +#----------------# + + diff --git a/modules/data/symbols/patches/language/pokefirered.yml b/modules/data/symbols/patches/language/pokefirered.yml index 51bc1822..cd9dd430 100644 --- a/modules/data/symbols/patches/language/pokefirered.yml +++ b/modules/data/symbols/patches/language/pokefirered.yml @@ -299,6 +299,8 @@ sTextPrinters: J: 0x2020030 gNumSafariBalls: J: 0x203990c +gSafariZoneStepCounter: + J: 0x203990e #--------------------# #----------------# diff --git a/modules/data/symbols/patches/language/pokeleafgreen.yml b/modules/data/symbols/patches/language/pokeleafgreen.yml index cec87811..df9f01f6 100644 --- a/modules/data/symbols/patches/language/pokeleafgreen.yml +++ b/modules/data/symbols/patches/language/pokeleafgreen.yml @@ -294,6 +294,8 @@ sTextPrinters: J: 0x2020030 gNumSafariBalls: J: 0x203990c +gSafariZoneStepCounter: + J: 0x203990e #--------------------# #----------------# diff --git a/modules/modes/_asserts.py b/modules/modes/_asserts.py index 70182127..eda9d62e 100644 --- a/modules/modes/_asserts.py +++ b/modules/modes/_asserts.py @@ -172,7 +172,8 @@ def assert_player_has_poke_balls() -> None: or if safari ball threshold is reached. """ if is_safari_map(): - if context.rom.is_frlg and get_safari_balls_left() <= 15: + # TODO : Remove rom check when RSE safari auto catch is implemented + 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: diff --git a/modules/modes/rock_smash.py b/modules/modes/rock_smash.py index 8eb02207..ec84b4df 100644 --- a/modules/modes/rock_smash.py +++ b/modules/modes/rock_smash.py @@ -8,7 +8,8 @@ from modules.encounter import handle_encounter, EncounterInfo from modules.gui.multi_select_window import Selection, ask_for_choice from modules.items import get_item_bag, get_item_by_name -from modules.map_data import MapRSE +from modules.map_data import MapRSE, is_safari_map +from modules.safari_strategy import get_safari_balls_left from modules.map_path import calculate_path from modules.memory import get_event_flag, get_event_var, read_symbol, unpack_uint16 from modules.player import TileTransitionState, get_player, get_player_avatar, AvatarFlags, get_player_location @@ -50,16 +51,23 @@ def name() -> str: @staticmethod def is_selectable() -> bool: - if not context.rom.is_rse: + if context.rom.is_frlg: return False - return get_player_avatar().map_group_and_number in ( + player_map = get_player_avatar().map_group_and_number + + if context.rom.is_rs: + return player_map == MapRSE.GRANITE_CAVE_B2F + + allowed_maps = { MapRSE.GRANITE_CAVE_B2F, MapRSE.ROUTE121_SAFARI_ZONE_ENTRANCE, MapRSE.SAFARI_ZONE_SOUTH, MapRSE.SAFARI_ZONE_NORTHEAST, MapRSE.SAFARI_ZONE_SOUTHEAST, - ) + } + + return player_map in allowed_maps def __init__(self): super().__init__() @@ -133,7 +141,10 @@ def run(self) -> Generator: check_in_saved_game=True, ) - assert_player_has_poke_balls() + # TODO: Remove and use the assert_player_has_poke_balls when RSE safari auto catch is implemented + # Shuckle catch rate is 35%. So 10 balls should be enough to catch it + if is_safari_map() and get_safari_balls_left() < 10: + raise BotModeError("Cannot rock smash with less than 10 safari 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/safari_debug.py b/modules/modes/safari_debug.py new file mode 100644 index 00000000..51c763d9 --- /dev/null +++ b/modules/modes/safari_debug.py @@ -0,0 +1,80 @@ +from typing import Generator + +from modules.context import context +from modules.player import get_player_avatar +from modules.battle_state import BattleOutcome +from modules.map_data import MapFRLG, is_safari_map +from modules.player import TileTransitionState, get_player, get_player_avatar +from modules.tasks import task_is_active +from modules.memory import get_game_state, GameState +from modules.modes.util.walking import wait_for_player_avatar_to_be_controllable +from ._interface import BotMode +from ._asserts import assert_player_has_poke_balls +from .util import spin, navigate_to, ensure_facing_direction, wait_for_script_to_start_and_finish, fish +from modules.console import console + + +class SafariMode(BotMode): + @staticmethod + def name() -> str: + return "Safari" + + @staticmethod + def is_selectable() -> bool: + return is_safari_map() + + def on_battle_ended(self, outcome: "BattleOutcome") -> None: + if not outcome == BattleOutcome.Lost: + assert_player_has_poke_balls() + + def run(self) -> Generator: + yield from self.enter_safari_zone() + + while True: + match get_player_avatar().map_group_and_number: + case MapFRLG.FUCHSIA_CITY_SAFARI_ZONE_ENTRANCE: + yield from self.enter_safari_zone() + case MapFRLG.SAFARI_ZONE_CENTER: + + def is_at_entrance_door(): + return ( + get_player_avatar().map_group_and_number == MapFRLG.SAFARI_ZONE_CENTER + and get_player_avatar().local_coordinates in (26, 30) + ) + + if is_at_entrance_door(): + yield from wait_for_player_avatar_to_be_standing_still() + # yield from navigate_to(MapFRLG.SAFARI_ZONE_CENTER, (32, 19)) + # while True: + # yield from fish() + yield from navigate_to(MapFRLG.SAFARI_ZONE_CENTER, (43, 16)) + case MapFRLG.SAFARI_ZONE_EAST: + yield from navigate_to(MapFRLG.SAFARI_ZONE_EAST, (8, 9)) + case MapFRLG.SAFARI_ZONE_NORTH: + yield from navigate_to(MapFRLG.SAFARI_ZONE_NORTH, (35, 30)) + yield from spin() + + def enter_safari_zone(self): + if get_player().money < 500: + raise BotModeError("You do not have enough cash to re-enter the Safari Zone.") + yield from navigate_to(MapFRLG.FUCHSIA_CITY_SAFARI_ZONE_ENTRANCE, (4, 4)) + yield from ensure_facing_direction("Up") + context.emulator.hold_button("Up") + for _ in range(10): + yield + context.emulator.release_button("Up") + yield + yield from wait_for_script_to_start_and_finish( + "FuchsiaCity_SafariZone_Entrance_EventScript_AskEnterSafariZone", "A" + ) + yield from wait_for_script_to_start_and_finish( + "FuchsiaCity_SafariZone_Entrance_EventScript_TryEnterSafariZone", "A" + ) + while ( + get_player_avatar().local_coordinates != (26, 30) + or task_is_active("Task_RunMapPreviewScreenForest") + or get_game_state() == GameState.CHANGE_MAP + ): + console.print("here") + yield + yield from wait_for_player_avatar_to_be_controllable()