Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve cross-map pathing in Kanto Safari Zone #597

Merged
merged 1 commit into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 2 additions & 19 deletions modules/modes/safari.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,17 +205,8 @@ def is_at_entrance_door():

path = get_navigation_path(target_map, tile_location)

for map_group, coords, warp_direction in path:
while True:
if get_player_avatar().map_group_and_number == map_group:
if get_player_avatar().local_coordinates == coords:
if warp_direction:
yield from self._warp(warp_direction)
break
else:
yield from navigate_to(map_group, coords)
else:
yield from navigate_to(map_group, coords)
for map_group, coords in path:
yield from navigate_to(map_group, coords)

if mode in (SafariHuntingMode.SPIN, SafariHuntingMode.SURF):
if self._use_repel and not repel_is_active():
Expand Down Expand Up @@ -243,14 +234,6 @@ def _check_mode_requirement(self, mode: SafariHuntingMode, object: SafariHunting
case _:
return True

def _warp(self, direction: str) -> Generator:
yield from ensure_facing_direction(direction)
context.emulator.hold_button(direction)
for _ in range(50):
yield
context.emulator.release_button(direction)
yield from wait_for_player_avatar_to_be_controllable()

def _soft_reset(self) -> Generator:
"""Handles soft resetting if cash difference exceeds the limit."""
yield from soft_reset()
Expand Down
92 changes: 55 additions & 37 deletions modules/safari_strategy.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import yaml
from enum import Enum
from modules.roms import ROM
from dataclasses import dataclass
from enum import Enum
from typing import Union, Tuple, Optional, Callable, List
from modules.context import context

import yaml

from modules.battle_strategies import SafariTurnAction
from modules.pokemon import Pokemon, Species, get_species_by_name
from modules.runtime import get_data_path
from modules.memory import read_symbol
from modules.context import context
from modules.files import make_string_safe_for_file_name
from modules.map_data import MapFRLG, MapRSE
from modules.memory import read_symbol, get_event_flag
from modules.modes._interface import BotModeError
from modules.pokemon import Pokemon, Species, get_species_by_name
from modules.pokemon_party import get_party
from modules.roms import ROM
from modules.runtime import get_data_path


class SafariHuntingMode(Enum):
Expand Down Expand Up @@ -286,45 +289,60 @@ def get_safari_pokemon(name: str) -> Optional[SafariPokemon]:
return None


def get_navigation_path(
target_map: MapFRLG, tile_location: Tuple[int, int]
) -> List[Tuple[MapFRLG, Tuple[int, int], Optional[str]]]:
def get_navigation_path(target_map: MapFRLG, tile_location: tuple[int, int]) -> list[tuple[MapFRLG, tuple[int, int]]]:
"""
Returns the navigation path for a given target map.

Args:
target_map (MapFRLG): The target map for which the navigation path is required.
tile_location: Local coordinates on the destination map.

Returns:
List[Tuple[MapFRLG, Tuple[int, int], Optional[str]]]: A list of tuples, where each tuple represents a step
List[Tuple[MapFRLG, Tuple[int, int]]]: A list of tuples, where each tuple represents a step
in the navigation path. Each tuple contains:
- A MapFRLG enum value for the destination map.
- A tuple of (x, y) coordinates for the target location.
- An optional string for the direction to move.
"""
navigation_paths = {
MapFRLG.SAFARI_ZONE_CENTER: [
(MapFRLG.SAFARI_ZONE_CENTER, tile_location, None),
],
MapFRLG.SAFARI_ZONE_EAST: [
(MapFRLG.SAFARI_ZONE_CENTER, (42, 16), "Right"),
(MapFRLG.SAFARI_ZONE_EAST, tile_location, None),
],
MapFRLG.SAFARI_ZONE_NORTH: [
(MapFRLG.SAFARI_ZONE_CENTER, (42, 16), "Right"),
(MapFRLG.SAFARI_ZONE_EAST, (9, 9), "Left"),
(MapFRLG.SAFARI_ZONE_NORTH, tile_location, None),
],
MapFRLG.SAFARI_ZONE_WEST: [
(MapFRLG.SAFARI_ZONE_CENTER, (42, 16), "Right"),
(MapFRLG.SAFARI_ZONE_EAST, (9, 9), "Left"),
(MapFRLG.SAFARI_ZONE_NORTH, (21, 33), "Down"),
(MapFRLG.SAFARI_ZONE_WEST, tile_location, None),
],
}

path = navigation_paths.get(target_map)
if path is None:
raise BotModeError(f"Error: No navigation path defined for {target_map}.")

return path
def can_surf():
return get_event_flag("BADGE05_GET") and get_party().has_pokemon_with_move("Surf")

match target_map:
case MapFRLG.SAFARI_ZONE_CENTER:
return [(MapFRLG.SAFARI_ZONE_CENTER, tile_location)]

case MapFRLG.SAFARI_ZONE_EAST:
return [
(MapFRLG.SAFARI_ZONE_CENTER, (43, 16)),
(MapFRLG.SAFARI_ZONE_EAST, tile_location),
]

case MapFRLG.SAFARI_ZONE_NORTH:
if can_surf():
return [
(MapFRLG.SAFARI_ZONE_CENTER, (26, 5)),
(MapFRLG.SAFARI_ZONE_NORTH, tile_location),
]
else:
return [
(MapFRLG.SAFARI_ZONE_CENTER, (43, 16)),
(MapFRLG.SAFARI_ZONE_EAST, (8, 9)),
(MapFRLG.SAFARI_ZONE_NORTH, tile_location),
]

case MapFRLG.SAFARI_ZONE_WEST:
if can_surf():
return [
(MapFRLG.SAFARI_ZONE_CENTER, (8, 17)),
(MapFRLG.SAFARI_ZONE_WEST, tile_location),
]
else:
return [
(MapFRLG.SAFARI_ZONE_CENTER, (43, 16)),
(MapFRLG.SAFARI_ZONE_EAST, (8, 9)),
(MapFRLG.SAFARI_ZONE_NORTH, (21, 34)),
(MapFRLG.SAFARI_ZONE_WEST, tile_location),
]

case _:
raise BotModeError(f"Error: No navigation path defined for {target_map}.")
Loading