Skip to content

Commit c03927c

Browse files
authored
Merge pull request #797 from 40Cakes/roamer-reencounter
Add Roamer Re-Encounter mode
2 parents f430f13 + cbb726d commit c03927c

File tree

4 files changed

+230
-0
lines changed

4 files changed

+230
-0
lines changed

modules/modes/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def get_bot_modes() -> list[Type[BotMode]]:
2727
from .level_grind import LevelGrindMode
2828
from .nugget_bridge import NuggetBridgeMode
2929
from .puzzle_solver import PuzzleSolverMode
30+
from .roamer_reencounter import RoamerReencounterMode
3031
from .roamer_reset import RoamerResetMode
3132
from .rock_smash import RockSmashMode
3233
from .safari import SafariMode
@@ -51,6 +52,7 @@ def get_bot_modes() -> list[Type[BotMode]]:
5152
LevelGrindMode,
5253
NuggetBridgeMode,
5354
PuzzleSolverMode,
55+
RoamerReencounterMode,
5456
RoamerResetMode,
5557
RockSmashMode,
5658
SafariMode,
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
from typing import Generator, TYPE_CHECKING
2+
3+
from modules.context import context
4+
from modules.map_data import MapRSE, MapFRLG
5+
from modules.modes import BotMode, BattleAction, BotModeError
6+
from modules.player import get_player, get_player_avatar, get_player_location
7+
from modules.pokemon_party import get_party
8+
from modules.roamer import get_roamer
9+
from ._asserts import (
10+
assert_player_has_poke_balls,
11+
assert_boxes_or_party_can_fit_pokemon,
12+
)
13+
from .util import (
14+
walk_one_tile,
15+
navigate_to,
16+
register_key_item,
17+
mount_bicycle,
18+
unmount_bicycle,
19+
repel_is_active,
20+
apply_repel,
21+
ensure_facing_direction,
22+
RanOutOfRepels,
23+
)
24+
from ..battle_state import battle_is_active
25+
from ..items import get_item_bag, get_item_by_name
26+
from ..map import get_map_data_for_current_position
27+
28+
if TYPE_CHECKING:
29+
from modules.encounter import EncounterInfo
30+
31+
32+
class RoamerReencounterMode(BotMode):
33+
@staticmethod
34+
def name() -> str:
35+
return "Roamer (Re-Encounter)"
36+
37+
@staticmethod
38+
def is_selectable() -> bool:
39+
if context.rom.is_emerald:
40+
allowed_maps = (
41+
MapRSE.ROUTE110,
42+
MapRSE.SLATEPORT_CITY,
43+
MapRSE.SLATEPORT_CITY_BATTLE_TENT_LOBBY,
44+
)
45+
elif context.rom.is_rs:
46+
allowed_maps = (
47+
MapRSE.ROUTE110,
48+
MapRSE.SLATEPORT_CITY,
49+
# This is actually the Pokémon Centre, but R/S's map numbers are different here
50+
MapRSE.SLATEPORT_CITY_HOUSE,
51+
)
52+
else:
53+
allowed_maps = (
54+
MapFRLG.ROUTE1,
55+
MapFRLG.PALLET_TOWN,
56+
MapFRLG.PALLET_TOWN_RIVALS_HOUSE,
57+
)
58+
59+
return get_roamer() is not None and get_player_avatar().map_group_and_number in allowed_maps
60+
61+
def on_battle_started(self, encounter: "EncounterInfo | None") -> BattleAction:
62+
context.set_manual_mode()
63+
return BattleAction.CustomAction
64+
65+
def on_repel_effect_ended(self) -> Generator:
66+
try:
67+
yield from apply_repel()
68+
except RanOutOfRepels:
69+
context.message = "Player ran out of Repel."
70+
context.set_manual_mode()
71+
72+
def run(self) -> Generator:
73+
if get_roamer() is None:
74+
raise BotModeError("The Roamer is not currently roaming.")
75+
76+
min_level = 6 if context.rom.is_frlg else 14
77+
max_level = 50 if context.rom.is_frlg else 40
78+
first_pokemon = get_party().first_non_fainted
79+
print(max_level, first_pokemon.level, min_level)
80+
if first_pokemon.level > max_level or first_pokemon.level < min_level:
81+
raise BotModeError(
82+
f"The first non-fainted Pokémon in your party must have a level between {min_level} and {max_level}. Yours is {first_pokemon.level}."
83+
)
84+
85+
assert_player_has_poke_balls()
86+
assert_boxes_or_party_can_fit_pokemon()
87+
88+
if get_item_bag().number_of_repels == 0:
89+
raise BotModeError("You do not have any repels in your item bag. Go and get some first!")
90+
91+
mach_bike = get_item_by_name("Bicycle" if context.rom.is_frlg else "Mach Bike")
92+
if get_player().registered_item is not mach_bike and get_item_bag().quantity_of(mach_bike) > 0:
93+
yield from register_key_item(mach_bike)
94+
using_bike = get_player().registered_item is mach_bike
95+
96+
has_good_ability = get_party().non_eggs[0].ability.name in ("Illuminate", "Arena Trap")
97+
98+
if not repel_is_active():
99+
yield from apply_repel()
100+
101+
is_rse = context.rom.is_rse
102+
is_frlg = context.rom.is_frlg
103+
while not battle_is_active():
104+
player_map, player_coordinates = get_player_location()
105+
106+
if is_rse and player_map is MapRSE.SLATEPORT_CITY_BATTLE_TENT_LOBBY:
107+
if player_coordinates in ((6, 9), (7, 9)):
108+
yield from walk_one_tile("Down")
109+
else:
110+
yield from navigate_to(MapRSE.SLATEPORT_CITY_BATTLE_TENT_LOBBY, (6, 9))
111+
112+
elif is_rse and player_map is MapRSE.SLATEPORT_CITY_HOUSE:
113+
if player_coordinates in ((6, 8), (7, 8)):
114+
yield from walk_one_tile("Down")
115+
else:
116+
yield from navigate_to(MapRSE.SLATEPORT_CITY_HOUSE, (6, 8))
117+
118+
elif is_rse and player_map is MapRSE.SLATEPORT_CITY:
119+
if using_bike:
120+
yield from mount_bicycle()
121+
yield from navigate_to(MapRSE.ROUTE110, (13, 98), avoid_encounters=False)
122+
yield from unmount_bicycle()
123+
context.emulator.hold_button("B")
124+
yield from walk_one_tile("Up")
125+
context.emulator.release_button("B")
126+
else:
127+
yield from navigate_to(MapRSE.ROUTE110, (14, 97), run=True, avoid_encounters=False)
128+
129+
elif is_rse and player_map is MapRSE.ROUTE110:
130+
if not get_map_data_for_current_position().has_encounters:
131+
yield from navigate_to(MapRSE.ROUTE110, (14, 97), run=True, avoid_encounters=False)
132+
133+
directions = ["Down", "Right", "Up", "Left"]
134+
for index in range(42 if has_good_ability else 62):
135+
yield from ensure_facing_direction(directions[index % 4])
136+
137+
if using_bike:
138+
yield from mount_bicycle()
139+
140+
# In R/S, there is an NPC that wanders randomly and can get in the way of the
141+
# player's path. That's why in these games, we instead go into the Pokémon Center
142+
# to achieve the required map change.
143+
destination_coordinates = (10, 12) if context.rom.is_emerald else (19, 19)
144+
yield from navigate_to(MapRSE.SLATEPORT_CITY, destination_coordinates, avoid_encounters=False)
145+
146+
elif is_frlg and player_map is MapFRLG.PALLET_TOWN_RIVALS_HOUSE:
147+
if player_coordinates == (4, 8):
148+
yield from walk_one_tile("Down")
149+
else:
150+
yield from navigate_to(MapFRLG.PALLET_TOWN_RIVALS_HOUSE, (4, 8))
151+
152+
elif is_frlg and player_map is MapFRLG.PALLET_TOWN:
153+
if using_bike:
154+
yield from mount_bicycle()
155+
yield from navigate_to(MapFRLG.ROUTE1, (12, 39), avoid_encounters=False)
156+
yield from unmount_bicycle()
157+
158+
elif is_frlg and player_map is MapFRLG.ROUTE1:
159+
if not get_map_data_for_current_position().has_encounters:
160+
yield from navigate_to(MapFRLG.ROUTE1, (12, 39), run=True, avoid_encounters=False)
161+
162+
directions = ["Down", "Right", "Up", "Left"]
163+
for index in range(18 if has_good_ability else 38):
164+
yield from ensure_facing_direction(directions[index % 4])
165+
166+
if using_bike:
167+
yield from mount_bicycle()
168+
yield from navigate_to(MapFRLG.PALLET_TOWN, (15, 7), avoid_encounters=False)
169+
170+
else:
171+
raise BotModeError("Player is on an unexpected map.")
172+
173+
context.set_manual_mode()

wiki/Readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ For quick help and support, reach out in Discord [#pokebot-gen3-support❔](http
3333
- 🟡 [Nugget Bridge](pages/Mode%20-%20Nugget%20Bridge.md)
3434
- 🧩 [Puzzle Solver](pages/Mode%20-%20Puzzle%20Solver.md)
3535
- 🏃 [Roamer Resets](pages/Mode%20-%20Roamer%20Resets.md)
36+
- 🏃 [Roamer Re-Encounter](pages/Mode%20-%20Roamer%20Re-Encounter.md)
3637
- 🪨 [Rock Smash](pages/Mode%20-%20Rock%20Smash.md)
3738
- 🏞️ [Safari](pages/Mode%20-%20Safari.md)
3839
- 🔄 [Spin](pages/Mode%20-%20Spin.md)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
🏠 [`pokebot-gen3` Wiki Home](../Readme.md)
2+
3+
# 🏃 Roamer Re-Encounter Mode
4+
This mode helps with encountering a Roaming Pokémon again after it has fled a battle.
5+
6+
It will run around the map (using Repel to avoid any other encounters) until it
7+
encounters the Roamer, in which case it switches back to manual mode.
8+
9+
## Requirements for Ruby/Sapphire/Emerald
10+
![](../../modules/web/static/sprites/pokemon/normal/Latias.png)
11+
![](../../modules/web/static/sprites/pokemon/normal/Latios.png)
12+
13+
1. The Roaming Pokémon must be active.
14+
2. The first non-fainted Pokémon in your party must be between level 14 and 40.
15+
3. You should have plenty of Max Repel in your inventory (though Super Repel and
16+
regular Repel will also work.)
17+
4. You must be on one of these maps:
18+
- Route 110
19+
- Slateport City
20+
- Slateport Battle Tent (R/S) / Slateport Contest Hall (Emerald)
21+
5. Optional, but it speeds things up: Have the Mach Bike in your inventory.
22+
23+
24+
## Requirements for FireRed/LeafGreen
25+
![](../../modules/web/static/sprites/pokemon/normal/Raikou.png)
26+
![](../../modules/web/static/sprites/pokemon/normal/Entei.png)
27+
![](../../modules/web/static/sprites/pokemon/normal/Suicune.png)
28+
29+
1. The Roaming Pokémon must be active.
30+
2. The first non-fainted Pokémon in your party must be between level 6 and 50.
31+
3. You should have plenty of Max Repel in your inventory (though Super Repel and
32+
regular Repel will also work.)
33+
4. You must be on one of these maps:
34+
- Route 1
35+
- Pallet Town
36+
- the Rival's house in Pallet Town
37+
5. Optional, but it speeds things up: Have the Bicycle in your inventory.
38+
39+
40+
## Game Support
41+
| | 🟥 Ruby | 🔷 Sapphire | 🟢 Emerald | 🔥 FireRed | 🌿 LeafGreen |
42+
|:---------|:-------:|:-----------:|:----------:|:----------:|:------------:|
43+
| English ||||||
44+
| Japanese ||||||
45+
| German ||||||
46+
| Spanish ||||||
47+
| French ||||||
48+
| Italian ||||||
49+
50+
✅ Tested, working
51+
52+
🟨 Untested, may not work
53+
54+
❌ Untested, not working

0 commit comments

Comments
 (0)