Skip to content

Commit

Permalink
Improve cross-map pathing in Kanto Safari Zone
Browse files Browse the repository at this point in the history
This updates the Safari mode so that it will use the direct connections between the central and northern/western areas if the player is able to use Surf. This saves some time by not having to traverse through the East and North areals.

I've also removed the custom warp code. If `navigate_to()` is used with a destination that is an arrow warp (i.e. needs another 'step' to activate the warp), the function will automatically follow that warp already.
  • Loading branch information
hanzi committed Dec 27, 2024
1 parent 56761ba commit e834c8d
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 56 deletions.
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}.")

0 comments on commit e834c8d

Please sign in to comment.