Skip to content

Commit

Permalink
Merge branch 'frlg-dev' into frlg-stable
Browse files Browse the repository at this point in the history
  • Loading branch information
vyneras committed Jan 25, 2025
2 parents 87f4b5e + 4dbd0d8 commit eb309bc
Show file tree
Hide file tree
Showing 24 changed files with 4,576 additions and 2,250 deletions.
255 changes: 184 additions & 71 deletions worlds/pokemon_frlg/__init__.py

Large diffs are not rendered by default.

79 changes: 73 additions & 6 deletions worlds/pokemon_frlg/client.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple
from NetUtils import ClientStatus
from Options import Toggle
import worlds._bizhawk as bizhawk
from worlds._bizhawk.client import BizHawkClient
from .data import data, FAMESANITY_OFFSET
from .data import data
from .items import reverse_offset_item_value
from .locations import offset_flag
from .options import Goal

if TYPE_CHECKING:
from worlds._bizhawk.context import BizHawkClientContext

DEXSANITY_OFFSET = 0x5000
FAMESANITY_OFFSET = 0x6000

BASE_ROM_NAME: Dict[str, str] = {
"firered": "pokemon red version",
"leafgreen": "pokemon green version",
Expand All @@ -31,7 +33,7 @@
"FLAG_DEFEATED_ROUTE22_EARLY_RIVAL",
"FLAG_GOT_SS_TICKET", # Saved Bill in the Route 25 Sea Cottage
"FLAG_RESCUED_MR_FUJI",
"FLAG_HIDE_SAFFRON_ROCKETS", # Liberated Silph Co.
"FLAG_HIDE_SILPH_GIOVANNI", # Liberated Silph Co.
"FLAG_DEFEATED_CHAMP",
"FLAG_RESCUED_LOSTELLE",
"FLAG_SEVII_DETOUR_FINISHED", # Gave Meteorite to Lostelle's Dad
Expand Down Expand Up @@ -70,6 +72,20 @@
]
FLY_UNLOCK_FLAG_MAP = {data.constants[flag_name]: flag_name for flag_name in TRACKER_FLY_UNLOCK_FLAGS}

HINT_FLAGS = {
"FLAG_HINT_ROUTE_2_OAKS_AIDE": "NPC_GIFT_GOT_HM05",
"FLAG_HINT_ROUTE_10_OAKS_AIDE": "NPC_GIFT_GOT_EVERSTONE_FROM_OAKS_AIDE",
"FLAG_HINT_ROUTE_11_OAKS_AIDE": "NPC_GIFT_GOT_ITEMFINDER",
"FLAG_HINT_ROUTE_16_OAKS_AIDE": "NPC_GIFT_GOT_AMULET_COIN_FROM_OAKS_AIDE",
"FLAG_HINT_ROUTE_15_OAKS_AIDE": "NPC_GIFT_GOT_EXP_SHARE_FROM_OAKS_AIDE",
"FLAG_HINT_BICYCLE_SHOP": "NPC_GIFT_GOT_BICYCLE",
"FLAG_HINT_SHOW_MAGIKARP": "NPC_GIFT_GOT_NET_BALL_FROM_ROUTE12_FISHING_HOUSE",
"FLAG_HINT_SHOW_HERACROSS": "NPC_GIFT_GOT_NEST_BALL_FROM_WATER_PATH_HOUSE_1",
"FLAG_HINT_SHOW_RESORT_GORGEOUS_MON": "NPC_GIFT_GOT_LUXURY_BALL_FROM_RESORT_GORGEOUS_HOUSE",
"FLAG_HINT_SHOW_TOGEPI": "FAME_CHECKER_DAISY_3"
}
HINT_FLAG_MAP = {data.constants[flag_name]: flag_name for flag_name in HINT_FLAGS.keys()}

MAP_SECTION_EDGES: Dict[str, List[Tuple[int, int]]] = {
"MAP_ROUTE2": [(23, 39)],
"MAP_ROUTE3": [(41, 19)],
Expand Down Expand Up @@ -125,6 +141,7 @@ def __init__(self) -> None:
self.local_checked_locations = set()
self.local_set_events = {}
self.local_set_fly_unlocks = {}
self.local_hints = []
self.caught_pokemon = 0
self.current_map = (0, 0)

Expand Down Expand Up @@ -229,7 +246,7 @@ async def game_watcher(self, ctx: "BizHawkClientContext") -> None:
# Read flags in 2 chunks
read_result = await bizhawk.guarded_read(
ctx.bizhawk_ctx,
[(sb1_address + 0x10E0, 0x90, "System Bus")], # Flags
[(sb1_address + 0x1130, 0x90, "System Bus")], # Flags
[guards["IN OVERWORLD"], guards["SAVE BLOCK 1"]]
)

Expand All @@ -240,13 +257,27 @@ async def game_watcher(self, ctx: "BizHawkClientContext") -> None:

read_result = await bizhawk.guarded_read(
ctx.bizhawk_ctx,
[(sb1_address + 0x1170, 0x90, "System Bus")], # Flags continued
[(sb1_address + 0x11C0, 0x90, "System Bus")], # Flags continued
[guards["IN OVERWORLD"], guards["SAVE BLOCK 1"]]
)

if read_result is not None:
flag_bytes += read_result[0]

# Read fame checker flags
fame_checker_bytes = bytes(0)
fame_checker_read_status = False
if ctx.slot_data["famesanity"]:
read_result = await bizhawk.guarded_read(
ctx.bizhawk_ctx,
[(sb1_address + 0x3B14, 0x40, "System Bus")], # Fame Checker
[guards["IN OVERWORLD"], guards["SAVE BLOCK 1"]]
)

if read_result is not None:
fame_checker_bytes = read_result[0]
fame_checker_read_status = True

# Read pokedex flags
pokemon_caught_bytes = bytes(0)
pokedex_read_status = False
Expand All @@ -263,6 +294,7 @@ async def game_watcher(self, ctx: "BizHawkClientContext") -> None:
game_clear = False
local_set_events = {flag_name: False for flag_name in TRACKER_EVENT_FLAGS}
local_set_fly_unlocks = {flag_name: False for flag_name in TRACKER_FLY_UNLOCK_FLAGS}
local_hints = {flag_name: False for flag_name in HINT_FLAGS.keys()}
local_checked_locations = set()
caught_pokemon = 0

Expand All @@ -285,11 +317,30 @@ async def game_watcher(self, ctx: "BizHawkClientContext") -> None:
if flag_id in FLY_UNLOCK_FLAG_MAP:
local_set_fly_unlocks[FLY_UNLOCK_FLAG_MAP[flag_id]] = True

if flag_id in HINT_FLAG_MAP:
local_hints[HINT_FLAG_MAP[flag_id]] = True

# Check set fame checker flags
if fame_checker_read_status:
fame_checker_index = 0
for byte_i, byte in enumerate(fame_checker_bytes):
if byte_i % 4 == 0: # The Fame Checker flags are every 4 bytes
for i in range(2, 8):
if byte & (1 << i) != 0:
location_id = offset_flag(FAMESANITY_OFFSET + fame_checker_index)
if location_id in ctx.server_locations:
local_checked_locations.add(location_id)
fame_checker_index += 1

# Get caught Pokémon count
if pokedex_read_status:
for byte_i, byte in enumerate(pokemon_caught_bytes):
for i in range(8):
if byte & (1 << i) != 0:
dex_number = byte_i * 8 + i
location_id = offset_flag(DEXSANITY_OFFSET + dex_number)
if location_id in ctx.server_locations:
local_checked_locations.add(location_id)
caught_pokemon += 1

# Send locations
Expand Down Expand Up @@ -354,6 +405,22 @@ async def game_watcher(self, ctx: "BizHawkClientContext") -> None:
}])
self.caught_pokemon = caught_pokemon

# Send AP Hints
if ctx.slot_data["provide_hints"]:
hints_locations = []
for flag_name, loc_name in HINT_FLAGS.items():
if local_hints[flag_name] and flag_name not in self.local_hints:
hints_locations.append(loc_name)
self.local_hints.append(flag_name)
hint_ids = [offset_flag(data.locations[loc].flag) for loc in hints_locations
if offset_flag(data.locations[loc].flag) in ctx.missing_locations]
if hint_ids:
await ctx.send_msgs([{
"cmd": "LocationScouts",
"locations": hint_ids,
"create_as_hint": 2
}])

except bizhawk.RequestFailedError:
# Exit handler and return to main loop to reconnect
pass
Expand All @@ -372,7 +439,7 @@ async def handle_received_items(self,
read_result = await bizhawk.guarded_read(
ctx.bizhawk_ctx,
[
(sb1_address + 0x3DD8, 2, "System Bus"),
(sb1_address + 0x3DE8, 2, "System Bus"),
(received_item_address + 4, 1, "System Bus")
],
[guards["IN OVERWORLD"], guards["SAVE BLOCK 1"]]
Expand Down
43 changes: 30 additions & 13 deletions worlds/pokemon_frlg/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from BaseClasses import ItemClassification

BASE_OFFSET = 6420000
FAMESANITY_OFFSET = 10000
NUM_REAL_SPECIES = 386


Expand Down Expand Up @@ -173,11 +172,6 @@ class EvolutionMethodEnum(IntEnum):
LEVEL_SHEDINJA = 7
ITEM = 8
FRIENDSHIP = 9
FRIENDSHIP_DAY = 10
FRIENDSHIP_NIGHT = 11
TRADE = 12
TRADE_ITEM = 13
BEAUTY = 14


EVOLUTION_METHOD_TYPE: Dict[str, EvolutionMethodEnum] = {
Expand All @@ -190,12 +184,7 @@ class EvolutionMethodEnum(IntEnum):
"LEVEL_NINJASK": EvolutionMethodEnum.LEVEL_NINJASK,
"LEVEL_SHEDINJA": EvolutionMethodEnum.LEVEL_SHEDINJA,
"ITEM": EvolutionMethodEnum.ITEM,
"FRIENDSHIP": EvolutionMethodEnum.FRIENDSHIP,
"FRIENDSHIP_DAY": EvolutionMethodEnum.FRIENDSHIP_DAY,
"FRIENDSHIP_NIGHT": EvolutionMethodEnum.FRIENDSHIP_NIGHT,
"TRADE": EvolutionMethodEnum.TRADE,
"TRADE_ITEM": EvolutionMethodEnum.TRADE_ITEM,
"BEAUTY": EvolutionMethodEnum.BEAUTY
"FRIENDSHIP": EvolutionMethodEnum.FRIENDSHIP
}


Expand Down Expand Up @@ -288,6 +277,7 @@ class PokemonFRLGData:
warps: Dict[str, Warp]
warp_map: Dict[str, Optional[str]]
species: Dict[int, SpeciesData]
evolutions: Dict[str, EvolutionData]
starters: Dict[str, StarterData]
legendary_pokemon: Dict[str, MiscPokemonData]
misc_pokemon: Dict[str, MiscPokemonData]
Expand All @@ -308,6 +298,7 @@ def __init__(self) -> None:
self.warps = {}
self.warp_map = {}
self.species = {}
self.evolutions = {}
self.starters = {}
self.legendary_pokemon = {}
self.misc_pokemon = {}
Expand Down Expand Up @@ -922,10 +913,18 @@ def _init() -> None:

# Create species data
max_species_id = 0
evo_item_map: Dict[int, int] = {
data.constants["ITEM_KINGS_ROCK_EVO"]: data.constants["ITEM_KINGS_ROCK"],
data.constants["ITEM_METAL_COAT_EVO"]: data.constants["ITEM_METAL_COAT"],
data.constants["ITEM_DEEP_SEA_SCALE_EVO"]: data.constants["ITEM_DEEP_SEA_SCALE"],
data.constants["ITEM_DEEP_SEA_TOOTH_EVO"]: data.constants["ITEM_DEEP_SEA_TOOTH"]
}
for species_id_name, species_name, species_dex_number in ALL_SPECIES:
species_id = data.constants[species_id_name]
max_species_id = max(species_id, max_species_id)
species_data = extracted_data["species"][species_id]
num_evolutions = len(species_data["evolutions"])
evolution_index = 1

learnset = [LearnsetMove(item["level"], item["move_id"]) for item in species_data["learnset"]["moves"]]

Expand All @@ -945,7 +944,8 @@ def _init() -> None:
(species_data["types"][0], species_data["types"][1]),
(species_data["abilities"][0], species_data["abilities"][1]),
[EvolutionData(
evolution_data["param"],
evo_item_map[evolution_data["param"]]
if evolution_data["param"] in evo_item_map else evolution_data["param"],
evolution_data["species"],
EVOLUTION_METHOD_TYPE[evolution_data["method"]]
) for evolution_data in species_data["evolutions"]],
Expand All @@ -958,6 +958,21 @@ def _init() -> None:
species_data["address"]
)

for evolution_data in data.species[species_id].evolutions:
if num_evolutions > 1:
data.evolutions[f"{species_name} {evolution_index}"] = EvolutionData(
evolution_data.param,
evolution_data.species_id,
evolution_data.method
)
evolution_index += 1
else:
data.evolutions[species_name] = EvolutionData(
evolution_data.param,
evolution_data.species_id,
evolution_data.method
)

for species in data.species.values():
for evolution in species.evolutions:
data.species[evolution.species_id].pre_evolution = species.species_id
Expand Down Expand Up @@ -1476,3 +1491,5 @@ def _init() -> None:
"SPECIES_JIRACHI",
"SPECIES_DEOXYS",
]])

NATIONAL_ID_TO_SPECIES_ID = {species.national_dex_number: i for i, species in data.species.items()}
Binary file modified worlds/pokemon_frlg/data/base_patch_firered.bsdiff4
Binary file not shown.
Binary file modified worlds/pokemon_frlg/data/base_patch_firered_rev1.bsdiff4
Binary file not shown.
Binary file modified worlds/pokemon_frlg/data/base_patch_leafgreen.bsdiff4
Binary file not shown.
Binary file modified worlds/pokemon_frlg/data/base_patch_leafgreen_rev1.bsdiff4
Binary file not shown.
Loading

0 comments on commit eb309bc

Please sign in to comment.