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

Pokemon Emerald: Clean up dexsanity spoiler and hints #3832

Merged
merged 8 commits into from
Dec 3, 2024
2 changes: 2 additions & 0 deletions worlds/pokemon_emerald/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
- Added a Swedish translation of the setup guide.
- The client communicates map transitions to any trackers connected to the slot.
- Added the player's Normalize Encounter Rates option to slot data for trackers.
- Made pokemon locations in the spoiler and hints more readable (`MAP_SKY_PILLAR_3F_WATER` becomes
`Sky Pillar 3F (Water)`).

### Fixes

Expand Down
53 changes: 33 additions & 20 deletions worlds/pokemon_emerald/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,21 +618,34 @@ def write_spoiler(self, spoiler_handle: TextIO):

spoiler_handle.write(f"\n\nWild Pokemon ({self.player_name}):\n\n")

slot_to_rod_suffix = {
0: " (Old Rod)",
1: " (Old Rod)",
2: " (Good Rod)",
3: " (Good Rod)",
4: " (Good Rod)",
5: " (Super Rod)",
6: " (Super Rod)",
7: " (Super Rod)",
8: " (Super Rod)",
9: " (Super Rod)",
}

species_maps = defaultdict(set)
for map in self.modified_maps.values():
if map.land_encounters is not None:
for encounter in map.land_encounters.slots:
species_maps[encounter].add(map.name[4:])
species_maps[encounter].add(map.label + " (Land)")

if map.water_encounters is not None:
for encounter in map.water_encounters.slots:
species_maps[encounter].add(map.name[4:])
species_maps[encounter].add(map.label + " (Water)")

if map.fishing_encounters is not None:
for encounter in map.fishing_encounters.slots:
species_maps[encounter].add(map.name[4:])
for slot, encounter in enumerate(map.fishing_encounters.slots):
species_maps[encounter].add(map.label + slot_to_rod_suffix[slot])

lines = [f"{emerald_data.species[species].label}: {', '.join(maps)}\n"
lines = [f"{emerald_data.species[species].label}: {', '.join(sorted(maps))}\n"
for species, maps in species_maps.items()]
lines.sort()
for line in lines:
Expand All @@ -644,35 +657,35 @@ def extend_hint_information(self, hint_data):
if self.options.dexsanity:
from collections import defaultdict

slot_to_rod = {
0: "_OLD_ROD",
1: "_OLD_ROD",
2: "_GOOD_ROD",
3: "_GOOD_ROD",
4: "_GOOD_ROD",
5: "_SUPER_ROD",
6: "_SUPER_ROD",
7: "_SUPER_ROD",
8: "_SUPER_ROD",
9: "_SUPER_ROD",
slot_to_rod_suffix = {
0: " (Old Rod)",
1: " (Old Rod)",
2: " (Good Rod)",
3: " (Good Rod)",
4: " (Good Rod)",
5: " (Super Rod)",
6: " (Super Rod)",
7: " (Super Rod)",
8: " (Super Rod)",
9: " (Super Rod)",
}

species_maps = defaultdict(set)
for map in self.modified_maps.values():
if map.land_encounters is not None:
for encounter in map.land_encounters.slots:
species_maps[encounter].add(map.name[4:] + "_GRASS")
species_maps[encounter].add(map.label + " (Land)")

if map.water_encounters is not None:
for encounter in map.water_encounters.slots:
species_maps[encounter].add(map.name[4:] + "_WATER")
species_maps[encounter].add(map.label + " (Water)")

if map.fishing_encounters is not None:
for slot, encounter in enumerate(map.fishing_encounters.slots):
species_maps[encounter].add(map.name[4:] + slot_to_rod[slot])
species_maps[encounter].add(map.label + slot_to_rod_suffix[slot])

hint_data[self.player] = {
self.location_name_to_id[f"Pokedex - {emerald_data.species[species].label}"]: ", ".join(maps)
self.location_name_to_id[f"Pokedex - {emerald_data.species[species].label}"]: ", ".join(sorted(maps))
for species, maps in species_maps.items()
}

Expand Down
31 changes: 31 additions & 0 deletions worlds/pokemon_emerald/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ class EncounterTableData(NamedTuple):
@dataclass
class MapData:
name: str
label: str
header_address: int
land_encounters: Optional[EncounterTableData]
water_encounters: Optional[EncounterTableData]
Expand Down Expand Up @@ -341,6 +342,8 @@ def load_json_data(data_name: str) -> Union[List[Any], Dict[str, Any]]:


def _init() -> None:
import re

extracted_data: Dict[str, Any] = load_json_data("extracted_data.json")
data.constants = extracted_data["constants"]
data.ram_addresses = extracted_data["misc_ram_addresses"]
Expand All @@ -350,6 +353,7 @@ def _init() -> None:

# Create map data
for map_name, map_json in extracted_data["maps"].items():
assert isinstance(map_name, str)
if map_name in IGNORABLE_MAPS:
continue

Expand All @@ -373,8 +377,35 @@ def _init() -> None:
map_json["fishing_encounters"]["address"]
)

# Derive a user-facing label
label = []
for word in map_name[4:].split("_"):
# 1F, B1F, 2R, etc.
re_match = re.match("^B?\d+[FRP]$", word)
if re_match:
label.append(word)
continue

# Route 103, Hall 1, House 5, etc.
re_match = re.match("^([A-Z]+)(\d+)$", word)
if re_match:
label.append(re_match.group(1).capitalize())
label.append(re_match.group(2).lstrip("0"))
continue

if word == "OF":
label.append("of")
continue

if word == "SS":
label.append("S.S.")
continue

label.append(word.capitalize())

data.maps[map_name] = MapData(
map_name,
" ".join(label),
map_json["header_address"],
land_encounters,
water_encounters,
Expand Down
Loading