From db5d9fbf70d89643bf766566c6d944e064369f5a Mon Sep 17 00:00:00 2001 From: Alchav <59858495+Alchav@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:37:17 -0400 Subject: [PATCH] Pokemon R/B: Version 5 Update (#3566) * Quiz updates * Enable Partial Trainersanity * Losable Key Items Still Count * New options api * Type Chart Seed * Continue switching to new options API * Level Scaling and Quiz fixes * Level Scaling and Quiz fixes * Clarify that palettes are only for Super Gameboy * Type chart seed groups use one random players' options * remove goal option again * Text updates * Trainersanity Trainers ignore Blind Trainers setting * Re-order simple connecting interiors so that directions are preserved when possible * Dexsanity exact number * Year update * Dexsanity Doc update * revert accidental file deletion * Fixes * Add world parameter to logic calls * restore correct seeded random object * missing world.options changes * Trainersanity table bug fix * delete entrances as well as exits when restarting door shuffle * Do not collect route 25 item for level scaling if trainer is trainersanity * world.options in level_scaling.py * Update worlds/pokemon_rb/level_scaling.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update worlds/pokemon_rb/encounters.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Update worlds/pokemon_rb/encounters.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * world -> multiworld * Fix Cerulean Cave Hidden Item Center Rocks region * Fix Cerulean Cave Hidden Item Center Rocks region for real * Remove "self-locking" rules * Update worlds/pokemon_rb/regions.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> * Fossil events * Update worlds/pokemon_rb/level_scaling.py Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> --------- Co-authored-by: alchav Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com> --- worlds/pokemon_rb/__init__.py | 416 ++++++------ worlds/pokemon_rb/basepatch_blue.bsdiff4 | Bin 46356 -> 47245 bytes worlds/pokemon_rb/basepatch_red.bsdiff4 | Bin 46344 -> 47212 bytes .../docs/en_Pokemon Red and Blue.md | 9 +- worlds/pokemon_rb/encounters.py | 100 +-- worlds/pokemon_rb/items.py | 2 + worlds/pokemon_rb/level_scaling.py | 19 +- worlds/pokemon_rb/locations.py | 50 +- worlds/pokemon_rb/logic.py | 79 ++- worlds/pokemon_rb/options.py | 253 ++++---- worlds/pokemon_rb/pokemon.py | 215 ++++--- worlds/pokemon_rb/regions.py | 594 +++++++++--------- worlds/pokemon_rb/rom.py | 376 ++++++----- worlds/pokemon_rb/rom_addresses.py | 450 +++++++------ worlds/pokemon_rb/rules.py | 207 +++--- 15 files changed, 1435 insertions(+), 1335 deletions(-) diff --git a/worlds/pokemon_rb/__init__.py b/worlds/pokemon_rb/__init__.py index c1d84318..2065507e 100644 --- a/worlds/pokemon_rb/__init__.py +++ b/worlds/pokemon_rb/__init__.py @@ -3,6 +3,7 @@ import settings import typing import threading import base64 +import random from copy import deepcopy from typing import TextIO @@ -14,7 +15,7 @@ from worlds.generic.Rules import add_item_rule from .items import item_table, item_groups from .locations import location_data, PokemonRBLocation from .regions import create_regions -from .options import pokemon_rb_options +from .options import PokemonRBOptions from .rom_addresses import rom_addresses from .text import encode_text from .rom import generate_output, get_base_rom_bytes, get_base_rom_path, RedDeltaPatch, BlueDeltaPatch @@ -71,7 +72,10 @@ class PokemonRedBlueWorld(World): Elite Four to become the champion!""" # -MuffinJets#4559 game = "Pokemon Red and Blue" - option_definitions = pokemon_rb_options + + options_dataclass = PokemonRBOptions + options: PokemonRBOptions + settings: typing.ClassVar[PokemonSettings] required_client_version = (0, 4, 2) @@ -85,8 +89,8 @@ class PokemonRedBlueWorld(World): web = PokemonWebWorld() - def __init__(self, world: MultiWorld, player: int): - super().__init__(world, player) + def __init__(self, multiworld: MultiWorld, player: int): + super().__init__(multiworld, player) self.item_pool = [] self.total_key_items = None self.fly_map = None @@ -101,11 +105,11 @@ class PokemonRedBlueWorld(World): self.learnsets = None self.trainer_name = None self.rival_name = None - self.type_chart = None self.traps = None self.trade_mons = {} self.finished_level_scaling = threading.Event() self.dexsanity_table = [] + self.trainersanity_table = [] self.local_locs = [] @classmethod @@ -113,11 +117,109 @@ class PokemonRedBlueWorld(World): versions = set() for player in multiworld.player_ids: if multiworld.worlds[player].game == "Pokemon Red and Blue": - versions.add(multiworld.game_version[player].current_key) + versions.add(multiworld.worlds[player].options.game_version.current_key) for version in versions: if not os.path.exists(get_base_rom_path(version)): raise FileNotFoundError(get_base_rom_path(version)) + @classmethod + def stage_generate_early(cls, multiworld: MultiWorld): + + seed_groups = {} + pokemon_rb_worlds = multiworld.get_game_worlds("Pokemon Red and Blue") + + for world in pokemon_rb_worlds: + if not (world.options.type_chart_seed.value.isdigit() or world.options.type_chart_seed.value == "random"): + seed_groups[world.options.type_chart_seed.value] = seed_groups.get(world.options.type_chart_seed.value, + []) + [world] + + copy_chart_worlds = {} + + for worlds in seed_groups.values(): + chosen_world = multiworld.random.choice(worlds) + for world in worlds: + if world is not chosen_world: + copy_chart_worlds[world.player] = chosen_world + + for world in pokemon_rb_worlds: + if world.player in copy_chart_worlds: + continue + tc_random = world.random + if world.options.type_chart_seed.value.isdigit(): + tc_random = random.Random() + tc_random.seed(int(world.options.type_chart_seed.value)) + + if world.options.randomize_type_chart == "vanilla": + chart = deepcopy(poke_data.type_chart) + elif world.options.randomize_type_chart == "randomize": + types = poke_data.type_names.values() + matchups = [] + for type1 in types: + for type2 in types: + matchups.append([type1, type2]) + tc_random.shuffle(matchups) + immunities = world.options.immunity_matchups.value + super_effectives = world.options.super_effective_matchups.value + not_very_effectives = world.options.not_very_effective_matchups.value + normals = world.options.normal_matchups.value + while super_effectives + not_very_effectives + normals < 225 - immunities: + if super_effectives == not_very_effectives == normals == 0: + super_effectives = 225 + not_very_effectives = 225 + normals = 225 + else: + super_effectives += world.options.super_effective_matchups.value + not_very_effectives += world.options.not_very_effective_matchups.value + normals += world.options.normal_matchups.value + if super_effectives + not_very_effectives + normals > 225 - immunities: + total = super_effectives + not_very_effectives + normals + excess = total - (225 - immunities) + subtract_amounts = ( + int((excess / (super_effectives + not_very_effectives + normals)) * super_effectives), + int((excess / (super_effectives + not_very_effectives + normals)) * not_very_effectives), + int((excess / (super_effectives + not_very_effectives + normals)) * normals)) + super_effectives -= subtract_amounts[0] + not_very_effectives -= subtract_amounts[1] + normals -= subtract_amounts[2] + while super_effectives + not_very_effectives + normals > 225 - immunities: + r = tc_random.randint(0, 2) + if r == 0 and super_effectives: + super_effectives -= 1 + elif r == 1 and not_very_effectives: + not_very_effectives -= 1 + elif normals: + normals -= 1 + chart = [] + for matchup_list, matchup_value in zip([immunities, normals, super_effectives, not_very_effectives], + [0, 10, 20, 5]): + for _ in range(matchup_list): + matchup = matchups.pop() + matchup.append(matchup_value) + chart.append(matchup) + elif world.options.randomize_type_chart == "chaos": + types = poke_data.type_names.values() + matchups = [] + for type1 in types: + for type2 in types: + matchups.append([type1, type2]) + chart = [] + values = list(range(21)) + tc_random.shuffle(matchups) + tc_random.shuffle(values) + for matchup in matchups: + value = values.pop(0) + values.append(value) + matchup.append(value) + chart.append(matchup) + # sort so that super-effective matchups occur first, to prevent dual "not very effective" / "super effective" + # matchups from leading to damage being ultimately divided by 2 and then multiplied by 2, which can lead to + # damage being reduced by 1 which leads to a "not very effective" message appearing due to my changes + # to the way effectiveness messages are generated. + world.type_chart = sorted(chart, key=lambda matchup: -matchup[2]) + + for player in copy_chart_worlds: + multiworld.worlds[player].type_chart = copy_chart_worlds[player].type_chart + def generate_early(self): def encode_name(name, t): try: @@ -126,33 +228,33 @@ class PokemonRedBlueWorld(World): return encode_text(name, length=8, whitespace="@", safety=True) except KeyError as e: raise KeyError(f"Invalid character(s) in {t} name for player {self.multiworld.player_name[self.player]}") from e - if self.multiworld.trainer_name[self.player] == "choose_in_game": + if self.options.trainer_name == "choose_in_game": self.trainer_name = "choose_in_game" else: - self.trainer_name = encode_name(self.multiworld.trainer_name[self.player].value, "Player") - if self.multiworld.rival_name[self.player] == "choose_in_game": + self.trainer_name = encode_name(self.options.trainer_name.value, "Player") + if self.options.rival_name == "choose_in_game": self.rival_name = "choose_in_game" else: - self.rival_name = encode_name(self.multiworld.rival_name[self.player].value, "Rival") + self.rival_name = encode_name(self.options.rival_name.value, "Rival") - if not self.multiworld.badgesanity[self.player]: - self.multiworld.non_local_items[self.player].value -= self.item_name_groups["Badges"] + if not self.options.badgesanity: + self.options.non_local_items.value -= self.item_name_groups["Badges"] - if self.multiworld.key_items_only[self.player]: - self.multiworld.trainersanity[self.player] = self.multiworld.trainersanity[self.player].from_text("off") - self.multiworld.dexsanity[self.player].value = 0 - self.multiworld.randomize_hidden_items[self.player] = \ - self.multiworld.randomize_hidden_items[self.player].from_text("off") + if self.options.key_items_only: + self.options.trainersanity.value = 0 + self.options.dexsanity.value = 0 + self.options.randomize_hidden_items = \ + self.options.randomize_hidden_items.from_text("off") - if self.multiworld.badges_needed_for_hm_moves[self.player].value >= 2: + if self.options.badges_needed_for_hm_moves.value >= 2: badges_to_add = ["Marsh Badge", "Volcano Badge", "Earth Badge"] - if self.multiworld.badges_needed_for_hm_moves[self.player].value == 3: + if self.options.badges_needed_for_hm_moves.value == 3: badges = ["Boulder Badge", "Cascade Badge", "Thunder Badge", "Rainbow Badge", "Marsh Badge", "Soul Badge", "Volcano Badge", "Earth Badge"] - self.multiworld.random.shuffle(badges) + self.random.shuffle(badges) badges_to_add += [badges.pop(), badges.pop()] hm_moves = ["Cut", "Fly", "Surf", "Strength", "Flash"] - self.multiworld.random.shuffle(hm_moves) + self.random.shuffle(hm_moves) self.extra_badges = {} for badge in badges_to_add: self.extra_badges[hm_moves.pop()] = badge @@ -160,79 +262,17 @@ class PokemonRedBlueWorld(World): process_move_data(self) process_pokemon_data(self) - if self.multiworld.randomize_type_chart[self.player] == "vanilla": - chart = deepcopy(poke_data.type_chart) - elif self.multiworld.randomize_type_chart[self.player] == "randomize": - types = poke_data.type_names.values() - matchups = [] - for type1 in types: - for type2 in types: - matchups.append([type1, type2]) - self.multiworld.random.shuffle(matchups) - immunities = self.multiworld.immunity_matchups[self.player].value - super_effectives = self.multiworld.super_effective_matchups[self.player].value - not_very_effectives = self.multiworld.not_very_effective_matchups[self.player].value - normals = self.multiworld.normal_matchups[self.player].value - while super_effectives + not_very_effectives + normals < 225 - immunities: - if super_effectives == not_very_effectives == normals == 0: - super_effectives = 225 - not_very_effectives = 225 - normals = 225 - else: - super_effectives += self.multiworld.super_effective_matchups[self.player].value - not_very_effectives += self.multiworld.not_very_effective_matchups[self.player].value - normals += self.multiworld.normal_matchups[self.player].value - if super_effectives + not_very_effectives + normals > 225 - immunities: - total = super_effectives + not_very_effectives + normals - excess = total - (225 - immunities) - subtract_amounts = ( - int((excess / (super_effectives + not_very_effectives + normals)) * super_effectives), - int((excess / (super_effectives + not_very_effectives + normals)) * not_very_effectives), - int((excess / (super_effectives + not_very_effectives + normals)) * normals)) - super_effectives -= subtract_amounts[0] - not_very_effectives -= subtract_amounts[1] - normals -= subtract_amounts[2] - while super_effectives + not_very_effectives + normals > 225 - immunities: - r = self.multiworld.random.randint(0, 2) - if r == 0 and super_effectives: - super_effectives -= 1 - elif r == 1 and not_very_effectives: - not_very_effectives -= 1 - elif normals: - normals -= 1 - chart = [] - for matchup_list, matchup_value in zip([immunities, normals, super_effectives, not_very_effectives], - [0, 10, 20, 5]): - for _ in range(matchup_list): - matchup = matchups.pop() - matchup.append(matchup_value) - chart.append(matchup) - elif self.multiworld.randomize_type_chart[self.player] == "chaos": - types = poke_data.type_names.values() - matchups = [] - for type1 in types: - for type2 in types: - matchups.append([type1, type2]) - chart = [] - values = list(range(21)) - self.multiworld.random.shuffle(matchups) - self.multiworld.random.shuffle(values) - for matchup in matchups: - value = values.pop(0) - values.append(value) - matchup.append(value) - chart.append(matchup) - # sort so that super-effective matchups occur first, to prevent dual "not very effective" / "super effective" - # matchups from leading to damage being ultimately divided by 2 and then multiplied by 2, which can lead to - # damage being reduced by 1 which leads to a "not very effective" message appearing due to my changes - # to the way effectiveness messages are generated. - self.type_chart = sorted(chart, key=lambda matchup: -matchup[2]) - self.dexsanity_table = [ - *(True for _ in range(round(self.multiworld.dexsanity[self.player].value * 1.51))), - *(False for _ in range(151 - round(self.multiworld.dexsanity[self.player].value * 1.51))) + *(True for _ in range(round(self.options.dexsanity.value))), + *(False for _ in range(151 - round(self.options.dexsanity.value))) ] - self.multiworld.random.shuffle(self.dexsanity_table) + self.random.shuffle(self.dexsanity_table) + + self.trainersanity_table = [ + *(True for _ in range(self.options.trainersanity.value)), + *(False for _ in range(317 - self.options.trainersanity.value)) + ] + self.random.shuffle(self.trainersanity_table) def create_items(self): self.multiworld.itempool += self.item_pool @@ -275,9 +315,9 @@ class PokemonRedBlueWorld(World): filleritempool += [item for item in unplaced_items if (not item.advancement) and (not item.useful)] def fill_hook(self, progitempool, usefulitempool, filleritempool, fill_locations): - if not self.multiworld.badgesanity[self.player]: + if not self.options.badgesanity: # Door Shuffle options besides Simple place badges during door shuffling - if self.multiworld.door_shuffle[self.player] in ("off", "simple"): + if self.options.door_shuffle in ("off", "simple"): badges = [item for item in progitempool if "Badge" in item.name and item.player == self.player] for badge in badges: self.multiworld.itempool.remove(badge) @@ -297,8 +337,8 @@ class PokemonRedBlueWorld(World): for mon in poke_data.pokemon_data.keys(): state.collect(self.create_item(mon), True) state.sweep_for_advancements() - self.multiworld.random.shuffle(badges) - self.multiworld.random.shuffle(badgelocs) + self.random.shuffle(badges) + self.random.shuffle(badgelocs) badgelocs_copy = badgelocs.copy() # allow_partial so that unplaced badges aren't lost, for debugging purposes fill_restrictive(self.multiworld, state, badgelocs_copy, badges, True, True, allow_partial=True) @@ -318,7 +358,7 @@ class PokemonRedBlueWorld(World): raise FillError(f"Failed to place badges for player {self.player}") verify_hm_moves(self.multiworld, self, self.player) - if self.multiworld.key_items_only[self.player]: + if self.options.key_items_only: return tms = [item for item in usefulitempool + filleritempool if item.name.startswith("TM") and (item.player == @@ -340,7 +380,7 @@ class PokemonRedBlueWorld(World): int((int(tm.name[2:4]) - 1) / 8)] & 1 << ((int(tm.name[2:4]) - 1) % 8)] if not learnable_tms: learnable_tms = tms - tm = self.multiworld.random.choice(learnable_tms) + tm = self.random.choice(learnable_tms) loc.place_locked_item(tm) fill_locations.remove(loc) @@ -370,9 +410,9 @@ class PokemonRedBlueWorld(World): if not all_state.can_reach(location, player=self.player): evolutions_region.locations.remove(location) - if self.multiworld.old_man[self.player] == "early_parcel": + if self.options.old_man == "early_parcel": self.multiworld.local_early_items[self.player]["Oak's Parcel"] = 1 - if self.multiworld.dexsanity[self.player]: + if self.options.dexsanity: for i, mon in enumerate(poke_data.pokemon_data): if self.dexsanity_table[i]: location = self.multiworld.get_location(f"Pokedex - {mon}", self.player) @@ -384,13 +424,13 @@ class PokemonRedBlueWorld(World): locs = {self.multiworld.get_location("Fossil - Choice A", self.player), self.multiworld.get_location("Fossil - Choice B", self.player)} - if not self.multiworld.key_items_only[self.player]: + if not self.options.key_items_only: rule = None - if self.multiworld.fossil_check_item_types[self.player] == "key_items": + if self.options.fossil_check_item_types == "key_items": rule = lambda i: i.advancement - elif self.multiworld.fossil_check_item_types[self.player] == "unique_items": + elif self.options.fossil_check_item_types == "unique_items": rule = lambda i: i.name in item_groups["Unique"] - elif self.multiworld.fossil_check_item_types[self.player] == "no_key_items": + elif self.options.fossil_check_item_types == "no_key_items": rule = lambda i: not i.advancement if rule: for loc in locs: @@ -406,16 +446,16 @@ class PokemonRedBlueWorld(World): if loc.item is None: locs.add(loc) - if not self.multiworld.key_items_only[self.player]: + if not self.options.key_items_only: loc = self.multiworld.get_location("Player's House 2F - Player's PC", self.player) if loc.item is None: locs.add(loc) for loc in sorted(locs): - if loc.name in self.multiworld.priority_locations[self.player].value: + if loc.name in self.options.priority_locations.value: add_item_rule(loc, lambda i: i.advancement) add_item_rule(loc, lambda i: i.player == self.player) - if self.multiworld.old_man[self.player] == "early_parcel" and loc.name != "Player's House 2F - Player's PC": + if self.options.old_man == "early_parcel" and loc.name != "Player's House 2F - Player's PC": add_item_rule(loc, lambda i: i.name != "Oak's Parcel") self.local_locs = locs @@ -440,10 +480,10 @@ class PokemonRedBlueWorld(World): else: region_mons.add(location.item.name) - self.multiworld.elite_four_pokedex_condition[self.player].total = \ - int((len(reachable_mons) / 100) * self.multiworld.elite_four_pokedex_condition[self.player].value) + self.options.elite_four_pokedex_condition.total = \ + int((len(reachable_mons) / 100) * self.options.elite_four_pokedex_condition.value) - if self.multiworld.accessibility[self.player] == "full": + if self.options.accessibility == "full": balls = [self.create_item(ball) for ball in ["Poke Ball", "Great Ball", "Ultra Ball"]] traps = [self.create_item(trap) for trap in item_groups["Traps"]] locations = [location for location in self.multiworld.get_locations(self.player) if "Pokedex - " in @@ -469,7 +509,7 @@ class PokemonRedBlueWorld(World): else: break else: - self.multiworld.random.shuffle(traps) + self.random.shuffle(traps) for trap in traps: try: self.multiworld.itempool.remove(trap) @@ -497,22 +537,22 @@ class PokemonRedBlueWorld(World): found_mons.add(key) def create_regions(self): - if (self.multiworld.old_man[self.player] == "vanilla" or - self.multiworld.door_shuffle[self.player] in ("full", "insanity")): - fly_map_codes = self.multiworld.random.sample(range(2, 11), 2) - elif (self.multiworld.door_shuffle[self.player] == "simple" or - self.multiworld.route_3_condition[self.player] == "boulder_badge" or - (self.multiworld.route_3_condition[self.player] == "any_badge" and - self.multiworld.badgesanity[self.player])): - fly_map_codes = self.multiworld.random.sample(range(3, 11), 2) + if (self.options.old_man == "vanilla" or + self.options.door_shuffle in ("full", "insanity")): + fly_map_codes = self.random.sample(range(2, 11), 2) + elif (self.options.door_shuffle == "simple" or + self.options.route_3_condition == "boulder_badge" or + (self.options.route_3_condition == "any_badge" and + self.options.badgesanity)): + fly_map_codes = self.random.sample(range(3, 11), 2) else: - fly_map_codes = self.multiworld.random.sample([4, 6, 7, 8, 9, 10], 2) - if self.multiworld.free_fly_location[self.player]: + fly_map_codes = self.random.sample([4, 6, 7, 8, 9, 10], 2) + if self.options.free_fly_location: fly_map_code = fly_map_codes[0] else: fly_map_code = 0 - if self.multiworld.town_map_fly_location[self.player]: + if self.options.town_map_fly_location: town_map_fly_map_code = fly_map_codes[1] else: town_map_fly_map_code = 0 @@ -528,7 +568,7 @@ class PokemonRedBlueWorld(World): self.multiworld.completion_condition[self.player] = lambda state, player=self.player: state.has("Become Champion", player=player) def set_rules(self): - set_rules(self.multiworld, self.player) + set_rules(self.multiworld, self, self.player) def create_item(self, name: str) -> Item: return PokemonRBItem(name, self.player) @@ -548,19 +588,19 @@ class PokemonRedBlueWorld(World): multidata["connect_names"][new_name] = multidata["connect_names"][self.multiworld.player_name[self.player]] def write_spoiler_header(self, spoiler_handle: TextIO): - spoiler_handle.write(f"Cerulean Cave Total Key Items: {self.multiworld.cerulean_cave_key_items_condition[self.player].total}\n") - spoiler_handle.write(f"Elite Four Total Key Items: {self.multiworld.elite_four_key_items_condition[self.player].total}\n") - spoiler_handle.write(f"Elite Four Total Pokemon: {self.multiworld.elite_four_pokedex_condition[self.player].total}\n") - if self.multiworld.free_fly_location[self.player]: + spoiler_handle.write(f"Cerulean Cave Total Key Items: {self.options.cerulean_cave_key_items_condition.total}\n") + spoiler_handle.write(f"Elite Four Total Key Items: {self.options.elite_four_key_items_condition.total}\n") + spoiler_handle.write(f"Elite Four Total Pokemon: {self.options.elite_four_pokedex_condition.total}\n") + if self.options.free_fly_location: spoiler_handle.write(f"Free Fly Location: {self.fly_map}\n") - if self.multiworld.town_map_fly_location[self.player]: + if self.options.town_map_fly_location: spoiler_handle.write(f"Town Map Fly Location: {self.town_map_fly_map}\n") if self.extra_badges: for hm_move, badge in self.extra_badges.items(): spoiler_handle.write(hm_move + " enabled by: " + (" " * 20)[:20 - len(hm_move)] + badge + "\n") def write_spoiler(self, spoiler_handle): - if self.multiworld.randomize_type_chart[self.player].value: + if self.options.randomize_type_chart: spoiler_handle.write(f"\n\nType matchups ({self.multiworld.player_name[self.player]}):\n\n") for matchup in self.type_chart: spoiler_handle.write(f"{matchup[0]} deals {matchup[2] * 10}% damage to {matchup[1]}\n") @@ -571,39 +611,39 @@ class PokemonRedBlueWorld(World): spoiler_handle.write(location.name + ": " + location.item.name + "\n") def get_filler_item_name(self) -> str: - combined_traps = (self.multiworld.poison_trap_weight[self.player].value - + self.multiworld.fire_trap_weight[self.player].value - + self.multiworld.paralyze_trap_weight[self.player].value - + self.multiworld.ice_trap_weight[self.player].value - + self.multiworld.sleep_trap_weight[self.player].value) + combined_traps = (self.options.poison_trap_weight.value + + self.options.fire_trap_weight.value + + self.options.paralyze_trap_weight.value + + self.options.ice_trap_weight.value + + self.options.sleep_trap_weight.value) if (combined_traps > 0 and - self.multiworld.random.randint(1, 100) <= self.multiworld.trap_percentage[self.player].value): + self.random.randint(1, 100) <= self.options.trap_percentage.value): return self.select_trap() banned_items = item_groups["Unique"] - if (((not self.multiworld.tea[self.player]) or "Saffron City" not in [self.fly_map, self.town_map_fly_map]) - and (not self.multiworld.door_shuffle[self.player])): + if (((not self.options.tea) or "Saffron City" not in [self.fly_map, self.town_map_fly_map]) + and (not self.options.door_shuffle)): # under these conditions, you should never be able to reach the Copycat or Pokémon Tower without being # able to reach the Celadon Department Store, so Poké Dolls would not allow early access to anything banned_items.append("Poke Doll") - if not self.multiworld.tea[self.player]: + if not self.options.tea: banned_items += item_groups["Vending Machine Drinks"] - return self.multiworld.random.choice([item for item in item_table if item_table[item].id and item_table[ + return self.random.choice([item for item in item_table if item_table[item].id and item_table[ item].classification == ItemClassification.filler and item not in banned_items]) def select_trap(self): if self.traps is None: self.traps = [] - self.traps += ["Poison Trap"] * self.multiworld.poison_trap_weight[self.player].value - self.traps += ["Fire Trap"] * self.multiworld.fire_trap_weight[self.player].value - self.traps += ["Paralyze Trap"] * self.multiworld.paralyze_trap_weight[self.player].value - self.traps += ["Ice Trap"] * self.multiworld.ice_trap_weight[self.player].value - self.traps += ["Sleep Trap"] * self.multiworld.sleep_trap_weight[self.player].value - return self.multiworld.random.choice(self.traps) + self.traps += ["Poison Trap"] * self.options.poison_trap_weight.value + self.traps += ["Fire Trap"] * self.options.fire_trap_weight.value + self.traps += ["Paralyze Trap"] * self.options.paralyze_trap_weight.value + self.traps += ["Ice Trap"] * self.options.ice_trap_weight.value + self.traps += ["Sleep Trap"] * self.options.sleep_trap_weight.value + return self.random.choice(self.traps) def extend_hint_information(self, hint_data): - if self.multiworld.dexsanity[self.player] or self.multiworld.door_shuffle[self.player]: + if self.options.dexsanity or self.options.door_shuffle: hint_data[self.player] = {} - if self.multiworld.dexsanity[self.player]: + if self.options.dexsanity: mon_locations = {mon: set() for mon in poke_data.pokemon_data.keys()} for loc in location_data: if loc.type in ["Wild Encounter", "Static Pokemon", "Legendary Pokemon", "Missable Pokemon"]: @@ -616,57 +656,59 @@ class PokemonRedBlueWorld(World): hint_data[self.player][self.multiworld.get_location(f"Pokedex - {mon}", self.player).address] =\ ", ".join(mon_locations[mon]) - if self.multiworld.door_shuffle[self.player]: + if self.options.door_shuffle: for location in self.multiworld.get_locations(self.player): if location.parent_region.entrance_hint and location.address: hint_data[self.player][location.address] = location.parent_region.entrance_hint def fill_slot_data(self) -> dict: - return { - "second_fossil_check_condition": self.multiworld.second_fossil_check_condition[self.player].value, - "require_item_finder": self.multiworld.require_item_finder[self.player].value, - "randomize_hidden_items": self.multiworld.randomize_hidden_items[self.player].value, - "badges_needed_for_hm_moves": self.multiworld.badges_needed_for_hm_moves[self.player].value, - "oaks_aide_rt_2": self.multiworld.oaks_aide_rt_2[self.player].value, - "oaks_aide_rt_11": self.multiworld.oaks_aide_rt_11[self.player].value, - "oaks_aide_rt_15": self.multiworld.oaks_aide_rt_15[self.player].value, - "extra_key_items": self.multiworld.extra_key_items[self.player].value, - "extra_strength_boulders": self.multiworld.extra_strength_boulders[self.player].value, - "tea": self.multiworld.tea[self.player].value, - "old_man": self.multiworld.old_man[self.player].value, - "elite_four_badges_condition": self.multiworld.elite_four_badges_condition[self.player].value, - "elite_four_key_items_condition": self.multiworld.elite_four_key_items_condition[self.player].total, - "elite_four_pokedex_condition": self.multiworld.elite_four_pokedex_condition[self.player].total, - "victory_road_condition": self.multiworld.victory_road_condition[self.player].value, - "route_22_gate_condition": self.multiworld.route_22_gate_condition[self.player].value, - "route_3_condition": self.multiworld.route_3_condition[self.player].value, - "robbed_house_officer": self.multiworld.robbed_house_officer[self.player].value, - "viridian_gym_condition": self.multiworld.viridian_gym_condition[self.player].value, - "cerulean_cave_badges_condition": self.multiworld.cerulean_cave_badges_condition[self.player].value, - "cerulean_cave_key_items_condition": self.multiworld.cerulean_cave_key_items_condition[self.player].total, + ret = { + "second_fossil_check_condition": self.options.second_fossil_check_condition.value, + "require_item_finder": self.options.require_item_finder.value, + "randomize_hidden_items": self.options.randomize_hidden_items.value, + "badges_needed_for_hm_moves": self.options.badges_needed_for_hm_moves.value, + "oaks_aide_rt_2": self.options.oaks_aide_rt_2.value, + "oaks_aide_rt_11": self.options.oaks_aide_rt_11.value, + "oaks_aide_rt_15": self.options.oaks_aide_rt_15.value, + "extra_key_items": self.options.extra_key_items.value, + "extra_strength_boulders": self.options.extra_strength_boulders.value, + "tea": self.options.tea.value, + "old_man": self.options.old_man.value, + "elite_four_badges_condition": self.options.elite_four_badges_condition.value, + "elite_four_key_items_condition": self.options.elite_four_key_items_condition.total, + "elite_four_pokedex_condition": self.options.elite_four_pokedex_condition.total, + "victory_road_condition": self.options.victory_road_condition.value, + "route_22_gate_condition": self.options.route_22_gate_condition.value, + "route_3_condition": self.options.route_3_condition.value, + "robbed_house_officer": self.options.robbed_house_officer.value, + "viridian_gym_condition": self.options.viridian_gym_condition.value, + "cerulean_cave_badges_condition": self.options.cerulean_cave_badges_condition.value, + "cerulean_cave_key_items_condition": self.options.cerulean_cave_key_items_condition.total, "free_fly_map": self.fly_map_code, "town_map_fly_map": self.town_map_fly_map_code, "extra_badges": self.extra_badges, - "type_chart": self.type_chart, - "randomize_pokedex": self.multiworld.randomize_pokedex[self.player].value, - "trainersanity": self.multiworld.trainersanity[self.player].value, - "death_link": self.multiworld.death_link[self.player].value, - "prizesanity": self.multiworld.prizesanity[self.player].value, - "key_items_only": self.multiworld.key_items_only[self.player].value, - "poke_doll_skip": self.multiworld.poke_doll_skip[self.player].value, - "bicycle_gate_skips": self.multiworld.bicycle_gate_skips[self.player].value, - "stonesanity": self.multiworld.stonesanity[self.player].value, - "door_shuffle": self.multiworld.door_shuffle[self.player].value, - "warp_tile_shuffle": self.multiworld.warp_tile_shuffle[self.player].value, - "dark_rock_tunnel_logic": self.multiworld.dark_rock_tunnel_logic[self.player].value, - "split_card_key": self.multiworld.split_card_key[self.player].value, - "all_elevators_locked": self.multiworld.all_elevators_locked[self.player].value, - "require_pokedex": self.multiworld.require_pokedex[self.player].value, - "area_1_to_1_mapping": self.multiworld.area_1_to_1_mapping[self.player].value, - "blind_trainers": self.multiworld.blind_trainers[self.player].value, + "randomize_pokedex": self.options.randomize_pokedex.value, + "trainersanity": self.options.trainersanity.value, + "death_link": self.options.death_link.value, + "prizesanity": self.options.prizesanity.value, + "key_items_only": self.options.key_items_only.value, + "poke_doll_skip": self.options.poke_doll_skip.value, + "bicycle_gate_skips": self.options.bicycle_gate_skips.value, + "stonesanity": self.options.stonesanity.value, + "door_shuffle": self.options.door_shuffle.value, + "warp_tile_shuffle": self.options.warp_tile_shuffle.value, + "dark_rock_tunnel_logic": self.options.dark_rock_tunnel_logic.value, + "split_card_key": self.options.split_card_key.value, + "all_elevators_locked": self.options.all_elevators_locked.value, + "require_pokedex": self.options.require_pokedex.value, + "area_1_to_1_mapping": self.options.area_1_to_1_mapping.value, + "blind_trainers": self.options.blind_trainers.value, } + if self.options.type_chart_seed == "random" or self.options.type_chart_seed.value.isdigit(): + ret["type_chart"] = self.type_chart + return ret class PokemonRBItem(Item): game = "Pokemon Red and Blue" diff --git a/worlds/pokemon_rb/basepatch_blue.bsdiff4 b/worlds/pokemon_rb/basepatch_blue.bsdiff4 index 0f65564a737be4e77c18cf94336ac9ba859345a9..bcd94c632d2cf9e0d3c44e142f1635cf6e42ac0b 100644 GIT binary patch literal 47245 zcmaHyRZtx~)UG$~?i6<~?z)lUy75xn-JRmHad+2^ySux)7bq^py*=N5{)=;WGMVJf zWU?|@H!Jh31gIe;CnLknzJ>+(zvWux7lW>_hQ6YScC(UZ{N06(~1mHC9o3*0HhWrHEeRIq*WE6qgcQ|y+P7@OlYR2Z*_izmf2=(2puR5W~|%9DKJCzQ&HZ32=o;KV>5 zkh8>;M>IZ26!)Wuq)Zlus&z4Ow#FnU_d>IzBAyD+C@UM=i1BoM21*2WN$$udKS~5i zj3S~y1@y3_#F^z2zldX&t@_Bm0Lcnje&qDVk%=YDOFV;7sxZp($&d*u5Ro_|D*&Kz z!v|`Lz=$jH@Mb9zQx-X@T60<#%+D{JagWcV!B9&Siv!?8#Nh*>3W(4E+-UHD^8kR= zJokUTgHe$~ssR1Tiov~$S38oFiB}?m9k*`bwk}wD#Jr^}wlVR^toYB?LRokqu@yoE z3=hnrm54YuC#MznJQ`V~6*n3Ffcejz z|7olL+W*n;f&VEQ*<>Xp2}m;!d?vh7g%uhxz|1FHoZE!hiU>eN3?IvFH4jxlj79|b zuL1zp|DEuEOw3#D=tJ<>?LllSp;+LwjI3rzRD;&+S8ZUMlY!EOuTCu*X9_8!oM&?- znr5j9K5iyB9;z}{E3O^65wCQ-y}lz9TS=q>Ru6VTn`-XzjMT_k1`7ylep@lg*ZJyx9?d_%KU@GoRP_=tsv?l8i@zvyCy|lub6HUn`*@ z;?eu3>uLLfO&y6jgqY)|yD3*0bYZ>wf}nC%d+#=X+Pz|Ou>-Y$uRgL-%C_(ivtPBs zXVidO+$a*3Get@rH^zL5Aq27iFl&g1%eHJvqcs)(Yg40xXVnqavquQ*->80d_L0Vo z2_gEE4(uuKcLHUfjuh=We3ng7DKi$-2Cxdv?jC%}c4Q2lsBGFm;}mofX2Uws>^W`1 z25Iw?=g%WAVbH4JEbEVyyR7e~ZTh^wu0#{@O-kbQ_iW$C& z!E*)#WvMEo_B%+Q?pq>VW|>59dH4>WBXUr13JN8jj|zs0EJKeG|Gl`jRE zoKJ7hz)pQiCkdK6K5{wdbYqA?Y>jC*ii6&b4qAwrsc_H`4-vId$i=!g>;7{s<*z#%1gkRGa@1l z2d!hQ(xF-fRxfSv8*=oATw?EU$;0k+1`@ll@^_wo;BCsayMFoJUE`hd7Q+AwAfbRR z45`NiMM}7j#`dh%|MAXV%DrLoZ%3JLjPJ|Ts@5vf-+5w>Hv_VOp^4q@Wd~@yxVEM@Yf?T!ct?Dz*h{8KJCf9|-b1uUSk7v^2!Ur^L^lOV z42v#nh`h@R`vW$3(W_|ljE!uP#kNMqaHf+lVT!2Q%61mfs!eLx!LI7*nX-#aT)qqf zepGMc@O@hg3kdogeo3Y5ZFtS%X_W=_&Vsy}lONjy0un(3Uhyh07WTH$th{Y>m0To5 zC8BvnQ8ey>LtSi14y0iM{SQCo2uHTNx&-sw&9gfRxxzwV}?A@~&ey)Z*@ znYj`)eRwM(`AkAA1zOi4Qc8K!c|dEidT%-#SDH)ISo)l9FAcZYTk$%)R~*JUYymiV zY23@gDdS6(MP+$<4mJNG8P*3NpapxvKo@bGQSoV117ztzpyiB(PX=f&a=J0A6z7S~ zv5o_?@CqX?UPcIYOm@3fC4HBCV#I73JpMc9Uzc!|x4;pPMDIG*UB8O|HBfQV%}Mb7 z46TXAG>S%1@6mmhcEs%fet7!ZDR?w0p?1G_wzk;-KR+;+*=m@}+Sw~$;IB;R#WK;p zx|n+N1t{Lw2K~;#403QUw|_^jG8zV@XY577N3`SWjq*KZ1JhhTE9{D}GiFSheb%2W zJSZmi{V#14g$lFS&+a3!khYn}0OxR)#o9ZV90JkjxSl^+gyHXk_CJi0pO8OG_u0h; zW4%jii3)pgGJ}^Jx-vgQCO0+W$I|hrm5-Mly(GI{0g@0RHG6>lzPF& z=UJ?_S7-mw`bEbw+x~}Ts&((aT&f&@(4c;bp{>U6t!(v^nB>f$(&-FG4!JN-EW z&Fq5y=B}{pZgwq&%WxtOVr`aN0#p`GsL;*tSIha(4-JJSTsiH?Dvzs1 z94a$5AR8)}J?2N|2w=S(p2`FFYrP+0Wp=w8_7B| zn%*QE8o>@op3;s?C!?1(~~lJBdeN7*3_Tz02SgAfPPMF0A@lU5R(Fv2FYM}zrU%-2a~JEee}`e zaCraz&yRn&mfuK`VgjRMo>bFPaK>nv;Ax3Rm7kfH#Df~>7J+;@HxVl*4}`)Nj@s8Z znKhn7sl6N9cE(MvCw(J@#hde6j;h85W>7_<`e&x&R__cq5b?Iw6Ij>N8QI@Z0bv)&vhm*%s0fjtf5XP2&|M$&zb8p^zYeP zPdTm8JWQQ2=XAeLi!oZVFB_d_urgfb+ddW|OP9=#^%nNsI29%DK7C5L5QzQxYvb_h zuDQcIRXiAqZZ{zum;#eMgVT0;^d)W+r2%FO+MaH!XICiiBl*FxuDE? z0bf7fjoZ!CSh8+1_-KsXox`soCG!n5&|~p9RO$2!YJcx#;_BB1trH5qsdg%Tn-16K&dQjrOFIm z+O)ciI&%dj@n2Cz!$lx&sYuuxg=waQ&~FIVI!v5Uh#IVnQr~juydYG8E+&rBVL8b(#F2AW4eBFI05D~8P{A=WS zg99qwcvX~oH7yNWdCtL~9WB!E{&7wwL0$RDFRJsFB?sxcm4sk;!nl*!-7}8ABPVhb zu|&j6=z1N;YE-4)Z6c?u^k1p6`7;#>M<|lhsp(V$rMH!cKMt$80f89UzYa=5IqV%) z9QYM}(s$Zeur7IUIm1i9OPH`%DOMy?1t*2tM_54EsEWXj`nx>~CRC?00>WOUw0~n6 zQc)3=p|3HeBQu?WG!jTYf{dvt^j*I!8@pm)t0`bQ{&lE}e+$8XQEFt2enQU^sc67r zhRTNj!$xz&8>y znSD0AX{C{&)AvXvCGETiQZGcQb9lMrDa59DmK@On5l7cerK?7}U&-;fnieF2+{#QG zEKeAW`|8_;yaz$MRQD{(Cg$kJE9hxdkm2yM!PBGLPDEtG)xijjpfHc%$mF!qTS8mx zvh2{H70)$JVFOk|N*Ffarb)>f+hVp&PXy5u`(NV6&$4HZ==d|Mmh2dodM4ToCgf0x zSl+D%yNYJ9xO)_!+4!%cv)|D*hmJV2Yq+HcOoPFO!tT~=AzyPh)P)@xyHXll1s2-=e+s*9@4;*$D>6XP%O?Y@&|8o0&w}0cSHQWs|G}hli1d z86p)`L$?9EG~$?{hz=waKnhp@CL$D~$rmXe%zZ^fr)**p%+X-@T7LELMf?7607qH2 zogGdn-IjYMjWX<#eaBHJf_c`?cYK@hDbrzPBCXt9@;bNt59uz0gXIRQeTL7rK$}({ zA>jorH?u8T3+dL(gwykK=gsE}$1GnJzvInBR?6IrL)OkI{g9m~IZ}@kQEe-$XcixV zai^K#m;)JFV^{2~_p6cNrgw|tCwHxpkUGnTWkqRbOQxU+7aRrAWYh4$#3B2eq-X-W z(=Y4qw zdyzujIeGLh@m}LD6-Q*&9P?UB@gjeF(Uma+u8-E|m4WoI`~(n89(;E4n!;Q0+xN$! zv38ha)?s5sOj)p)9R6v3@AXq^x!6lr660WKuJDa(LnOCrCg1NcphqWVgJ0_r~|~eywNEGq2=p z<}^YZb-BZv_tr6Q+S0B~Z72rQPFL@94pUKBUHiN5vhUUg+J%!(mv5$RzK6evp>GPQ zdO7HspmTO+zMCVd75T)o@eel@QknQX0C7niDTsRsN0MS*206csE}7WOgnO{O(Izi5 zDZkQDV**2>C@(9oJiKgq;!H(jQ|?SSE04a?QSFp^MNBQ_&c;G!F)u4y<6FtYqtX|R zZz;qXffUeI|HWJ@*nTDMiGn2=uuu897gGS_+!yqz_NJnkD8l`yGOrp?@kQ!UM2VC8 zKZC_KW<&@TWM#`DlFN^10G|*Q)g_t0{|0DKZ>rq$KxhC`flRRVxsMWuipE6A4ELl> ze(0mx8}~yNeZh*D6{GO-GBH{4@*{@YxroYtj4UfpW0|)cQY^VZ#0`V9JWrNbEN%u^ zXkLVBAuCTA52$#A&62|urwfKpo)4FcIun7Np9ozM1Lj#R+IT6-HCjW?${~;}a}h2L zhKFno?&aZmD^wl~Re(jZidwNu77;g8v7|Tv4WR-)77)c`Rv9p&_GYfKBBJt$`yagf z57`A&_~ey^%M4<|=T};2n8eGSo0)9_GEwKVtPB1-mD(rLothc zp?I0t#JU*KiWmSZM`e`}Y_=pLNufx+Y?GI4U2~P=tTqzcaz;0BE0hQqYV}W!9 zcmHFK!k)rMCUBm6p#T7t03iMkdhx*6kQGZ5sua1IPOd2R4#hue8+}-_rhlr8^Ct>5 z1~1CK9Ddw7&8Nn1RyCIY>-jtIuL!PfvF}e>yNsiF+Z^^gUI6-B!+^$NK{Hrg8q!!j zAn%%=@u#KuX2R@@aFH*Jk(rn{pJqQI`!12zm~4!FtM6GCeR2xixy&+>Kw&5~@XZrf zMxcGK$d3KpxHss;7cO#tgO*`N-z0wK^>d9;;hk3OUm=;gZx3A0G+BHJ_+i!>J$bT0 z^03)I!kg28W4e9%6MGUb=Hn_=O|EZ2eDvu~YjnGP>Vg z9<`_-F#)4({nXcqy9=J=zZNfZBUDR%e>0B}^7HG2 z7AOdrWhrJy0W)ik_ba{ix{q9a=l*&0!gSCxv zx|gnnf56*9Z?OQ6X2aD_;Ry~oBTUjQ{_YQ|q`~jz^2BisoxL8@Z#=u%9_Hsp+&x~N z1X(4Su*T_M1h|9od`xM$N?7B}K`?yh)_`3ha44&zz(mIWO^co;p(u)E zjGWt8^NV-uj}}&`4b>OtYG{h!K#&B4(89t>IGWpNpx-z(2dRov@H8how4CJ!+8s6b z{R4uax)e=flw0#++l#|`f#bX@BV9Iq-BQGTS0){UR*;<=Y%u>?OJc7KK!mu<*U>t~ zHJrCqTbEyl1hq+bnZyX|GUz7WVqlC#Q&2(MTn>V6>P#|nm3=u$ta;}xPk%7w6eBTA zdxQW9-XrIQcCACEksp%_LOVjcev_c-^Co@s%K8QRQw_1*=rul)l7=LCu@HhnAYbC* zSZ9XXIEkiQozKN*aEiU!b=zAVcCWXZg&=4DdNa5&HZypLkX)4>plkpK^9EiOJmZT1 z@V7Gul%G;(mk)AHvwmexcbZfL@qUJ*rCbO93bIEmlW9^ImH!2F*~3c3SGByOkQpTR z>!pVQ+jUSdN0qyJcai$g&e%xtyPiSNt)Dnq2#fpxH>VS(W833(*AO3sRR>E z)nnGWyPEf;u)giW2681%AlZ0^q?$0WSIS3@^Jbe#CI#S`ehsxSfMFLU*?1GP-F({y zpL+FXr-d?>j#E>W!t-2Alg8{s7^+v&bR4IN?lVfug*gTs5V6~{(lODK_wa7It_bDj z-}0WW(Pz0#VHw5vpvcxk;8+`A+~~O)F8*C^#@S@n>nK0L8ROxL<~-mgP+}es{Q1~9 zK2D*&`TS|PCmM)1*}3o1Y-F-ZHcJ8_$C5=$`DV`hUk$+JPC1Bp;oPq4BA zViWboN8`tFsg&a5wHX(WY9J+Dz*K{F@^9J{~k|@QKnbm>GFs=@ zxJ@|AfZmIIUkCjF5~R#*F?N`^XD!aikFl@8)_CV!=>2mBc9yy!kXE@iICs>`ouU25+9TA&%4pOb!lC(c-oFQV?!yKa?EuznNyXMC`5v3v?xmbhL zg=getjXXa}ZC02E3lf@Yn!8%H(tRMVm~#W(p+lP`No{YR6rJaNc?lX ziIr6NX2DQwum<_P!OUSiZq%{b-6)JW$~ttb@xrba?9R9v2VTTijjtoZ=VqmPBC3PP z!Gjx7Z#%Uy^Yr33KW4gWIE(zY5^Ld~M}7(lsAWV>olm?EN_%j6TDz_o9?mf=!4S1P zBWs~1dvIc|mc@4N6U5wM?ruRo6`k}Q{FZst%HvRH$WhXxd?Ci-8=^f8j7rH{s7UE*$i}Bc) zT{cPD#=hD6CbyW2&#v=dBSeWU>GU= zW(W)H^2oV=2pxyzuS;F>rvYZZ1lr*xzR=2%lj*QO8OHkw2UaLh|^jaMA zW169cw8c@};o}tN`s}k7I?+09aUd+I*%3!lx=fsry{LYIw)ioMo1(n%fZtq{PVT#u zbpeklTvEK-RJJPmw7r9X{%NRv8yP>SW$AV*p7haaB z3nit8DG-81k@rbH*kzn}rGz;c1J9!WCAy=NEDX;YsYe+n;v3k2fscF-1_z^^K>&mI#Cg_f(#7{+wLHQy7 zwR>Mg)SMg}*`FM&8)iYcv_5QUkF+n zthG`EXWh3|*IXrMd?#3wGl-+!2O=@~N~C$B`2HW%z#|%1QD#wILm4{5Aa2uuLKPh` zt_1(22l5g90mflEW@{D){WEsoTJ>-pmLSF1?t<|Ve)xy)kj$v<@#)&PF}vRVQx2pm zU|iUAV|)H7_fYmSkI7K9Njld07F%-an`>)(?u@a{ByxR`dk?K4pwV*mjF~Vq6~-N* za{SOb#!JA~zPGqrVIybSI_e`dP_hbomr1CL_?15L3a6f5(eH$mr6Jvb@ojF7-t#>n*rZb-@0|I&xm4 zF}d8VX>H;pru_R0pfg5ObNUNS<}^D*K)<#>kqv?QZN(OuJbFBH=139j;d)-freXf**qJX`q59CX70N$Y}sle ziy2vB3g*nlvZFopcmTVwWz_~fTcpFvI^jQ$^d{tV@=ZnVxD7BS4|^e2@hAecW)TgGk?#WT=HuI= zDdj!&*zxSH_gFYz7_tsjVuR`fn^Pzv6qO`Uas_xfvpgBZmcCJ~DAn&Xp#}1CJ`lr^ zu&!iW+EEoQPzsOgaTkQbC)8j~l|9RriD7OJR{3w;>Y2HA@Ug~B6mXt6;@g-*Vu)l_*GxI2Ccowl8T}BAlHuxa@Wai_6>I$i*kJc~U}p zY43S4@xQ>1iLayJ`eFlsA26EE$o?`f(?|SP=uN-4Q*C?GKxRD#FJYzNxMNEsLd2#J zFGfkHYRkuSot|#WJ_-W9-I&Ef%}T`n=%BgqkKuInBWgNu=1QkcWi_i+708CXdX&|| zbR=~i9L)N7I4{{;FOTppp6!?M7sfMI+t%wRuygrUne&;NXGLpq(-lJt3XG3{Op6O-!^qD|Xa8T`zv-W#Vn@bC1TwOU6s%Q!Cp>JJ7+$6HdsxJWkWk zPN@G-&2P-G(P+@3)r_Jwh*Cm~F~#Vo9~XA0i;lTY8x=Hmg?O;`#$MWNvMGA|)nL0v z4E2x?&gGK3RODUC!n1<)$WME#*E>2NW}dDK3Iy_f zfjZ$#kDXVpB&n46GzcJLGD>S3wQH4zd^$3}w^KS?FDRtu_qryMH)A9`?kz)Vnfjfz zr=m9os$UM+#;V{BikTk=l%&c-&LN8EH;)PC#im?!%*63-!aa;xH->7_P|6B;1 z!6uJ$#O;rIfCdFYHRDRv5~06pe|Abg&kSywny`hbojnSe3<=Vbqx#KG(&|O1GFlxE#d!{Ijuw>+KJ)W6-Xot*0 z%x-#*o|xu0=irn=?{iHRP#=0Z-7Yvz-mW8TX2QJ2%wlk3x{O?g`R*|8mBjip-oUvP zef2L68%^k|6ZhG&etXLbNp^ojZ4q2rxtIF3aJb13hIBDJ` z&&tV$4UPw*;bZ>Z0R*Q~`5Nz;>6$gA3g@d&$U*$IYZo+Gc>g$IlGFTBu1s2f715#1 z{0KJ5TNZ!>^Tl?T*V4DG+JO-S5P}_418Kf2#TZfD3U$LpHF^DWtDA{{pIJZ51hGiqH)?Xru%zZCy5Gqtqd%zI5{O2>-RpT1e7d z5RfC?TR_JMMu8Bvx`;xF7S0XiB~OMRXkA7sFjuVZtq~EzPEV@)l{fj+x5*xRHGcg; z8|n0RRSwq&XZEs_t_EfzWt3E&QS$D0;?TySnuwK8*CEafjW~1y>oqf`MMd;DNOF9r zZfT3=TPbA!te%EfTv*>Rb25jw=gZxYGJ7$UKZ?YmjfBVf9#VPHCtg2RAU=4H?Czqv zV!U%6vmzN;o?_XSwyvdmZ(*xgZ%c;1zZi)ks<(ITyXSTW6)w9bawWW_Sw#a>G1vPk z=n_i~Lao^n5cB8^`Uix(cg{1`-@6Fs!f$je{|(TRahE75N>DD)t}LXu(oGBnBZD#e zxv15ihe7IhnWam1N>{!cqhd%hXA429E>{Ik3OfsVbjS`#r24uK+TmD6UhAZDCXZ@v z)P-0J(MgmPv@K_zw;IBHMtmcvdIgx9{lwsil0d#axosoFDcyLbiy6Pl3^5D4@H~q_e8HvOLi3RY5lPC_SFbF9jeN*6kV3 zbSp@y!5o!O&3>1{I`6=4uGXr-@7On_%m*f7DN-}1J1CCI;bDG_N@9WrN&S{F)~*kg zz-^=n(x8HdsDdzzaS7N6lY-@-!mzzBk*J&e#&aF$;ES&{RAb1%SlVp(`=#1H5s|O4 z5p5_H>~KUtB)z0#=Zs1QO=m8df;m&f17NTm{U!{Yk1>`aAR&S80ldfWf&~!NEmEf} zacw3`4K7YZX#m_~=O7l0i>qO7p8G1xlVCB@nBBuD0K(g3CUnTUbVjDn$b4rZI+WH&mSpesF6J2;U$EmGk$6nsP`4K({Pb>jw)6Y&$= z3>}h#O+1rCybuK=-l(Dn_F(~NIG>$NK^{N7J(2S3W;NLCDzZ2~o@y zO#L!1kHUk_2`2X~%0-8iB_^bz$s)zUcel||`zl^(`d?f`b6SWMh!q|^QCzmDj!Y;= zo8zQp&V9*JxmJ!<(%*J9Lb$UzNiP?nha{;uq;*ErnE4d?4~~{FEv9t}M#QL@FAHqxR-y2c6@8vJAZ#bj~shHv#ZJWw>PPvNyC}oz>vk^&qZJNU9 zeROB(WOog$yI)_KOhiejK6p(HO3hSwk6xNAnHzhpXIn^GxC++JIXdT(w0>7sdJ%QV zCAQeC-%-`*fd~}V4<&>y8g-^sIs?xq)Gdik@X-Fc7junl@WFxUGKujJWALRUBqWSR ztp2^W5>|(89>z0gmYJ0C=q>0(_7aqB1mDPqHEZIYV*XB1{YIWYR6i`&NP0y!dqiwo zetawxBMMmR%z4L+FW=$g&8R3`^!^v}@2NZy18byQfj+%c2b}2cki;UWo0$BBdZ)a~ zp#A7Ec0}39$YtZdRBNmW7f2=XRwcPbOVBu2G_3KI*E6i#7oAQUVU_Q9eC1JdbLXuI zt8?i8_+QeFeW6&Vk>$HDCUU5%n)55cdAK6K5c`p|P{${lB; zsS=ad5pirRwNwEUFYo&~$Ixg{5>#Qc=B3z=p|-M#R&^DJX$!9`ce)R|=ZS+)+N{AB z)%|hLKP>`|UxC)^FG41nFUuDOr?#~dAfp?}u)_F0c$2)EJXcf|gYv37pP}XV*w;Ue z?gizQa~P3DFRHJWUx2^5$)e)ml$r~DRqUGD^Q{d0 z4^4Q6g)3YIsoJ45c|Y^>Za{zBHPTo22)esFpV@5pG-Qikc$27@o_qoV$j-WBg7Bqb zH7t+`99`BKlGwpug!bL^iyB{SS0h;Z3*D*nzv#3Il<}#TvXQ*tz)YPA%EJMW^7)(6 zlzM>>mYSjlhFb4@$I^r0rL+Fa*{IiM%*V>rJtF>u9^HQpN1xvk5WNV2WQ-GxPktWDZhHes;taX>`D|3$CS4 zS(XhVBj0MqGNk#e0s$Sew#XU9T}W+c`QfMgP&~99QEO&+L#o>+q7qM~VfZ$ckvdO}&@ZU9SEB^l~gd|BKkLSz1XT z)pDZvc%JK1uC~4FY6-p3&`zO+0mZmYSU z1Ic|c`e%6*l1P9w2MundES^52*-_h z6bZV3TQ{-AsRpBplgfmg@z$tUb`tXkXHyJgpNKElg;Qa6$~CHJ^Od*5vAlJ|r-{gHhx_a_C9Is_gCX8E%XIjw)%J49eV=zl1djDd;ITuipUC4ntU)>MiA z$^;%Bo!-fDBMjy{8t+dHjkvb=yqgA=pQ-zJdBs-zzRAt>=WR(v!-Jj?pOv5tl8o5lyW<>NbqX~9sx)_MAW?FFio|FBXJblR z>*L&#)ilz32j4_lF_hQH6bT(6EhE7LvrO-D9-kU6P9R|nD@<>(i>qh<&w61K-(X}> zB)DwFrd#)$$)vPk0=EqL*3Gcz@-%vS*#-YxtOXZP<#2JF>CGBB;Yu0s*HL)2uxWc7 zgu3>1=k{S9$5qV8P>%1WE#2J9+6gD{)mt;EuOx&%6Il?B~Unx|52p%>>ua>2VXXO8JTUicx8- z;9~S!kx4&%`%}?ma9@aDRMa)uM9yrd>~>k&dBH(e2kcjtd$TGwoI9NjSl8drLB1M_l}X=>Ku`kGf?obEJI)t1N5*g zOQLk}h?JBjE_2j1k6b)>CxcivlJqCT)f{Et)hzh zeMX(eH|_%1_uygb1TfkpKFDYY(tESQ3}D2lA`;B7xy$f)-N-|mq7V0a<4_3d1^5M; zsJMhBIT`s$>x<_`A)Qnv!o^#W&&;NKDA$n!u2n|mudezq#H`qZQsIYC zf#joW9=NwI1%3E@{?z_mFS@BcKB#%C3Ca9@>^4DI7$qei-p%25R;VT^hkx0e+*122Mzs;EI>bI58;xl4hlrzi$sJr=5LLST`x zy56-|O7GSxLln&Bi^w#+Q9!w){I{in$Dx~SpC|N1$Ejq`qPR05os5EO|Lg?!6l&|O z{ggrJU(I$GH3%6l&sx}JBcc`q=F*SFK*NK4;b5HT;3J8$Qo4V`zm_}=`aMNds5l<| z<>87AX5k0--95AQyT98S1exrcLsfOWx4po?dkEmQcB&{(>By0;uj!%VKf4O2h*?vqY zm3rj%1}NAk`){^4$TF04c$oWJSKXtE#1&*fG+gVyhk3K_|7AxOcpmf%56HvZ`e>JO z<2Qc^TvbCICAlmf2d6UVIaUib`qFDLfMq9(zJEqTA3|FcF?o5KaHLZ&KQ-GNH*&Mu zY!#*Uw1fp%qI-c^tIM`+8Fb|&F?&*PPvJ>~oU*f+vyrkyQsq$XoK{r4hxD} zj!>X+r>ksy+m3dQ#~CxJ?LyU&BsM{+zkP!13&HdrPBvNft&jYgrEi*?yo zG`DfRStss`GdhMsGYLYfZ@78)8_xopF>kJUyswURwY`6SwV?}|v3mNEOPl^`^k*Wi zC?N}oLzy~!^@|GGaRe%hS z2$XdNX}6?=COqP}VF(2N)Vh@jo9Fd{BfbTpZgPeK2BN4)7Fnf`gT*;Y5->Dr@QLLx zV9-ris_X(SzAJIbRdMm`w8ADS<*I|#)ZuwHXpLzilvjXER52duRg|3$Gg*_Ay3KVV z7;=kBnSAEEwfZRgg))+sittSSy9VsXL*Y->*-n&ZMilz2(6W_QV*^;SN`&))PN>O0 zZRq$bNxw^D-&<5HF=$>t9~Ed!#Hdc;GD&<_rNk$bg;Er!DC}0yMMNeiPWiz|^Kmkm zD~VyKl->Jf3K32kI-$f^OpC`=C1U0y3yMx!;Uy+2hgkhobqnkH3j=-v0& z!?eRJNW)hG8@fN53SN#5#GuMTA-ai7lmLG!F30naEL6<ESU5j7${^Or`c=5x7~{(sWcz zOcPjux6P%~r9y$XcX$L+r*XW{qtwt>MmEPq z9T2Orm_x^6JFkc)B=W%vN21D@EUPuo^3i}>1Tz#>LU@yr!Ua;HD=Ukl4OUk)5lhW@ zx0PZD_?kQ@Ox?v-(VLB~uM91>HDoG&(S$gBfP(Vh^c+*Qe!378)Vu_Z4p~OK3YggK zj;c_fx^$bwnIp45W)5)K|Jk8HT5t#J!jN*3QE@WKQo@>4#PHsFJ*J}W?Avp;$sC;1 z@PuS+voFe`K$%pAn4{6?!h{u=-D{wh_C-hV`KxMx1GrGVxcr)UyM8BoD20Lvli;Xi zW3@n7YRYnaZZr#N*7$~E>>JP}DRR7ulN|IF$=IMX#L5lKMt~fPy!?i|rkUE87Fl_A z{sO{rXmAsD2^K!ZNcf^ZU(E{GCXH!|!Ur|K@zq0FQBWCNS)bnoEYanrV0@0m&u@O< zhHqD8LY^B+xpGGQtHc1QMpOuaqu|A?@5!5$d}1t@%7aNCMx*_dm(U(RKxp91CK!PaThXXqRfZ*;O;tDNCYCa?BwP;` z#ESmF!ES>Lon2pz>S{ymvQBT#5Iz@`Oax=hB+G6TQs2*OfeMzwqD+Cg`WNlY|EG{< zKLO??Mwo%vTRqJB_xU)ETrGapf6;3Uwvm-%9 z$-I9w8lR5!i!@%XaIu2ptVkU^ta7zi`!v!b9fq>cTrmY)%N=t7gSphTj2-9zh|2>hj9XCTr*xZ%~q_sG!1$j5+x9bH_5%0FzHQpm1)KmGN#y8 zx6W+F>?^(R4uo=6F+!cE7@R=E|n=2n-~0 z_n_ZW2qDlQ=4maStuizr?^nFNRmF;Lr*ck61%;$^RZC35*(kByV>5gZ$q{T2Gytx| z6j6O9u&E^yF8{wjZW*jmE%5_wH-}q~_*7au*NJQ5g^vbmm^&niPLDaJmJ&2ZN$*rpWY ze(l`Wu>6uD>6q?s5PYF#p+j-3B5AVvmxEG?@sv|X6u6%Fw};92s8%?_(0~5UI$-La z7$IzH>^TPO?5lyt(<)eXOcOh|cI#WBK9HbAw_kQ$Znr|MIBAz00jM!>!}#L(%j_iO3v(ZQ5j{ZkUfI4vZi4=)q~ekw@yG7}ebTTz7@X?okxFrYJ} zW0j0CPIy%EI>EP-)tlJL{fA4k2zoaz3aH9CGscjwQX4arQvY^NrZ9Tn1$txHoICz< z;K|GD6nzi$t~&#+WXux|CEFPW{H4V|ld?Bx9pfp$j0}H>LSNqQS~~VMNILAADO^=V zU&D4{UAZEx%Oa?x^8$~9;rl8|0neCHzokCW*^~qrB;_BaG3#1VHKc*t)f``2^@7K# zcMzAgRufwX{!YBT6t$8hwFr)fHf?eP$H#N6Wy8HHC5z0YRI_ziDq5?C#)YJRY}oVQ zg<&qg*K$h;o0>a^`Q$-jXLSD$0Czx$zqy5v5AJ%gxt?A}t<3qkKPQvY^*pVQx#95ke6IJa)%6+b)vH0-ZaEm<|NU-# zuS@#tdLHlZ`8=Wg22h_$=H}#Fi;-e1cf7x`ukvKS4n&C(BuJ6j|A*?|L76qFvvg`< zo!?!Y$O9vKF?1QKadvdNd+nrM7e~d3LF3bw6iE9;1!;&t*2UZPY`pH(-{yh`0)clu zd>zSwx-qset;JL4?tK3LH3Eo_Ru??|jP}m+We4q4x~>^}EMVYTfW7>S+xS^6cOwIL z_B%2b!MU-;;$WU!CS5zYjn+NASbh9Y5ZNLG^)nc~ou*?|^dL*@s3tz|25d-h^8vJv z!l6sPd+y(TNO8EUHerfbwNi9tZ*jv(7ohE){sYf_JLOFMTnsG8<3AXo!e*=HGxaGQ zpVGBg(W4%{?+Rm(ZXn`c41spM7VdO8xUp?4B*44O?IuOUeC`6OS;lh0#*G;b-DvGD zve+HlS-mS1Ct-SpTo}(grn8MzldFM&2h`-sYz2tZawi`ITgsn4e3p10YZ*$BMXo)u zi*h`h+uS~~C*yG-n_{%CyoeQ?0lJC=O1XzcS}!YuS~1w;@x$_@q)wp^DL!#r#UZvZ^(aD3`7!%-91^z^R^ zbZGQK5Q?gK;+LSqxy46pGuHVZOKsDhhd#(Xj9_*(e>|@0B4>blp9{1-CC83W*+kWWi$E*& zVy5$~&vaS-`|oeI(+J7r7hMbHRvmFldWbg)XWA11d1ECS`obm$+VF~&d%=O^I z=3EbcH%Dn4UmGH@M3WW%Mi z1IE9O!@J-fy(6ae+)jo(TnrSeOi`x z>&~F=B5K>0Wa}!A;Hw(Mz1YknIk(`Bqs_8xeWzk~ zyzG0g-tFV=}qbiwHYj>e9>=D)Kpwh>Cf0 z%4E;SKpJKdnq$NUp$o0Odt^&_B*8zJbSzhg6W|0n2C`)gqj^Cs8CGFhCu(b)^B;@o5g+Lx~k+p-w!6 z;<1BtiF6jg7{eSvVgZ0eLZ(J{klPlO2OUbzrg}OTrour6<6;WFC$zHKfUm^Y-0c{l zr~8O53*sOfA!1fuC1?GguYdi0kGp8^0s|Bt3X4bm1uPJmloQw}&IEM6zlzP%UBfNX zD>yaR@(DYB)koI$e@(vAUmJl&EyVXf_WvpvT7f^3t4?l}MTb{H7bH|X9d7pZ+o5IR+9kB?Q`Y#V;(-PegO-UA>6 zD+C1QL~1A!3fk%cJ+vty5fK&K$4JzQLCiUt8LcU84dO9L3q7*6Q~ufcN&;Dto#~(m zczkLk5Fg(lD7VFY^)`KWW|6WiWsT0`S??r~ft5M-z)Vd%O)#c_Pkg$f?${Af@P zN&sg*T`DQs%>)Y|e)yNK&|^pRSX2rGK!fI#tn#hyu;@v7xZ_MG@!two*p3`&0@jqVu2!I)4A&M{bM9U5QT;3IRmu=Y%&0S}# zWW3eTEaeglk?!mrzlL;@XFrifyB95L5lU$&_>2gjcW#ZCcHF^XdZ@BOq^vz;K0C~H z%F2)=;EKGs{+n(accJR4AK#~+-)8)&}TQpG&?cKoXyS=Nf<26=M>A~|DB}D*(-I2yA z;E)z~G9xOWx;nL5a5F%~z|X$BKCKIO#Uc^{t@-h2T!Nr~VEN%di}({5KN}Z^2Er(vxb%kyk%7(C~20NdZ6JA_koPs3*3GZCZNhW7jCx ztX3LC7J!nPh~X|k@pr1eD8r{aN<5ib0;(=@)u@jz zsb$p)iV1sug9agNU7v+w%#Pu{nT#<2TWMFo*U^C{44!W3OMANdTxc3MB9)MV z26Bm>5-2%g!j3O>Kt0Sr_HcO^=+u%;YAag28&}@xZ!E7O3O;rQC<0}HrIvv%h>|@l zg!n8xTYU#-v9~1h`yQ@oCwHe$;rssCkz&DOtW{BpEMf}81?b9NxF!{e?a%b-$B>R}F_74bW>sSif>ZJ@UJef2g( zMg4V@+8(R<(D;anYz5fBYCg(lL*K*0MJ$Tp@Vwo|_&!`!$pud$CusrKhZ-uE$A!3B z#dg$K@fQ~Yr~-CK0W>xCIK#ox;C`J{t9JPm>wC$w^E#}+lX``xl4r#LDZ|NDDd7>z zsn6gufzcr%)kQKsjwQNXwQCqe&lme(CZ5*EeXHlSa4+BPSm0^WuB0|+3I|_2NRP6E zuz0j<&Ln;0M)>e^(g$UAtTCE6>3jHrM7%u&H`Z5!4ZDgv*fk57A-8JFo>S~PNe%6v zW#Xhikdt)lN$W8DbOQwD&taZeY{YvxmTklM;<;k!N9p1t-o-WdG<^leY}}r8-xcU| zcs{R$Z}8zqdmVUb!1UT(wSe|88}}*PfEylkq0B){h_2c=VCd(G!PeYU#al||ZdXr5 zVUlA?&T423)x-WlAa{kf=J7 zS%^^Gn`(9GLm+@U#m^5HXV*$RfYVYg@6$Mt;7_TEBzs!NXcsE9mB0k5B`;$*+0h@{C8 z>D@9bS77H^cYXEVZlE^l7DvkJw6Y`(F45*btL;ob{~+3_BAj@BYdJ( zdza~C9AjgLLQ#f(7iSPy1D%~DR_Y$C6KDRu|Rf@kl7JMGSz}$WniEW0x&ryF$}WDHev?`G9iE@nIYgfiEZ^2 zw^bDA`pVhk*GrADxpkwGW~z{8TUheoRBpbD5&yWA6Pwjg*u_mjkUY;0Qe87wLcvG6 zy-0hW%j9&!>-&AIH$&9nd5kMxCa!AN&wnWoYU)f`>ZOR4*3*V+PGsJ1N@7o43W(@O z+QSJ61EGNkUwz%0P2L|_PhV=Yc1@Sm_&85d?O#VerWxjkPK}7_z}|2<-pcI1wM&Et zdp$Muw`Qg9ZlH&thY!oM_b%J{GjzTi$q!oHJqe4KcE@^H9d)XY9m5boL#X|?>y;e_ z?;`76KS7rHstC15IORA}K+y0>!9EA{^!beWs89M+i@`kI*_CaWhq`3Mc=r6AP4>Kc zcfbP#(iYa)$qVkO&BW|?cW;91$pepdIzC%jva?@JK&~;3`lNm^WWd@Yt12os7Z;y$Q2?{;^0EoNF*;LjxP1z&sss@?P=qg< z%0ptC2^4$RF`3}GWe^wxw7*QTewv`2EX)LQu`2>OUs_B>VrUW-Ms)5Pj zGm?j-LR;n)rB`p5!D_;DeGJU7#(znDW_U5e++IsX)|kst`8%cXA?mW}^-y2ObqmGi zmfhG!*N8=oHkQ7IxIw9HBOOtcq=>3q3d1c*B3yP3ZXzWZYTU7(i`q({bZK=o0D`y|&*0#1;p)gA+>H`(Q7D&~rA2Y)>x$bp{k0chS(+%4q$6{_qoBFB zXF?9|59+LBz^a-sJcwiW6o-QhAqaJG$E10#W#3TlYOCT>xo=9vV4+rJ3#ydZQ3fff zQd}tRzYnoqP5z#{>Pq?ir(3aP_#Ya(tCgAybdOKHadvftB?og}K)_Z?9E;@$)JF5;O(!=AS@tHb0xm#sLC@A55YTIo7_KGhc@TwO6V`0qhStiyqU#X`$zBK%O7NradiSr&2bgdfg76MymAK0l)w<5@%*&UCl4llhT+ND4{W7*1&MOgyGn!l!qsxT)Ho{9a{}U^QD~ARJ1l;H5+l z4oaR0+%zM1zf^rIn#!Aq;|8)XzwYMmZ?0k2JH$x!d0bx__Hm=uW3ZY3V+El=FAI5$g3F^M*hYW-6J2MrBnX8m3^V!vx z@MudDfy28e6xkE+8A!x8Pc!H;FiLbvi-;rzJS9pYlQK0A5A$EWaJ*>9+;0Dv*64x( z>kt6QfPsK_8ISZQKpeC(c2x%^x>{bzu{_0yC@KaR^iKl`r9 z(YDtSu|6-~(bH|!*)A591tW)ufNSxm(zX$z#;W6%a9L?~PiAaw`d4D&;@H8{!;Y)` zt1nSoZK$`=4om#y^U0d!mqs^<&HS$+wmPEx=x6q9n>JU>EB7^h_l1$QGZnum&t;QZ z7-;F-z-@=0<|f}$yG+oZ9*7X4jpjQ(PUV=ICUmYbdAQVDE%|m;*0DS3suQRLwV>4T z1l0o(la^#%BGMg6HSTX1hB&MU77=)daAI6&PuSF@JF23r7GhYosuXEX3ZjJh=or6M z_2NLHkmOK-F^uVeJcJ%PzB7v)rmpR+f%COK|~!C7lxp zWuf>`Fuf#q7=jFiw2LET*MeTPA=}IFIxP7+aN|Km6gl_O9`Wo}euqB}PCn22+&m9y zi1zT)h-*VrnZDzki@@M{$WZHb6crB3VuUq`6fq6Z@MY$Z>*%^kySjW#D*@t#M9lOP z>S5s9w9%Ot=CVR^Tw8^RW+ItZGEvxMyVJ{KD@CElTFfez~ke&0(v{x~dR%}4Ez?Yjt@N_Z(;_%Dg60oV*#Q%SR*I(Uc zM3>I6`%Pz+c3RY>9-*E{*xNH)yH%Y_mJgIk!NhX5DeRRDJxhBO%?q3?atb!B*DO+^ zROM)5xj~Fvj%x`1UOPzgt`*?A{id&v0$N>x5)VQ6IAd)60ua_SzZFhHS`V=Y2Ci=Q zB!#+_jAc9nshAz>V9P67U%{~3U6rO5I7eEz+$O;C3aDrl7FJapw)uab_a5i{f1v&6 z%JOuazz@nwJ@#JDMutA>>)pC?!l3@c?`VN`A6vP9&{}|0bq!A}sCAIzn?gpuK6LEt z%zPT$&!<}gvK2ilEe3c#3R3c= z5AO(3n(e0TX82ef<2C3iAw=`1d4iobW8u{&FQQB$E#Iri$rBY31cBL9`X|rGs63-1NG^`1D_G*s&eTI+vI>Xx?vERYR$;77(mFCwNj5cIEj{31) z`W}W@x1fGYl(>*^K@50V71cl;9kf2K23!vhWn_tt1c|1?8_FsN;!)(s-Q1cm6V;x= zq*L#?(j5s89kt*grbv3NNU-Zeu|D}G=zf`pcMI>Ba7m3x?fwNicf6DLx}x=S_&>Gb zvGY)_;Svb5V9wyW$pUe-CSk%+k|HF~tfK+51WcG3O(r6sY@Lq%7NX60Gtk>;Y{QOh zVLErKr;87j*?)Y6clK-#Mbp8b=XkD3B*DUkI%gy(YXh;qCZL76**nfP!9n0!RCR~z&c)*NqTRh!w^~2!(@=` z=R+SsJyWuusrQyoGtumMvc8k%Vbq<;3{9AKpa!i{x_T68>uT!o@2gVCD(90H6)e`p zdd}lEYq4^y=y2uujvrC4L$31exgEg~Q(P*ad&@sFeay94Iq=p`J?j%k{;4)(KATVv z(z0TqHeuDhoZrE@pY}hWPW%XYo^YLX?{S=MX+duc z;9>bW>14l4PUoZE{|5~|N4snM*Ot1o6%+Wa|2y<~hx_j&?nCxSWB#w?{eeaY?tkpy zIUl!Q_WH_5v)yUR;Eyb-co-~UjHEh>sHdKwsp_+aQ`8!%G>7UF;yp|_ZU~J~;PWr) zC{lu}R7%BeZ-nn$`JZz8&-QKL5XSCnVRQ;n1)g`A+o?SyKgoC?E}G7FmU~EiOtb0U z^Q`gm&PU4nzYiVWmZyWuPR4xap*+kFXFlJvTrECR(5M}(>*K-6rtDW^zR8LqICTYN zaDA0oSatACkuE-O?3U6jDUND{lNsUR%O`3N!?5tP&QC!OY=$$Xh6$uOn?c))yO%`D zeQH^4keUcdlogm&u%!z^#yK(#embPcH$@#VlnoUDC(uJUt&Xg|qciCuvINe0?4>_3 zqE9$nb`jJ@p`I?1iC|hux<&%XM9g<1*GBnDG9j!OSmfHV>b(^)8;W8w^OZfh0+%9> z*|2JAX2$korQ|a4Eh=G|3WnjSOd(lp6u%wlq{p16t%3wSf!#2K1_M|jJfez4o7@s{ zb&7xpn!yzqeGu+pR5>7tk?B^ZN+q3G&wqu6VmS|{LD1K8ah+J{Ulo$@*R~c>n)qt2 zD9-tC)UYX;N)Vwar=5z@WP~X0LBRGF$0)%Q$2@7)hZY?v<4MpjD>it#av?f>#UaCk zK~6N^KUd0{^;u3H3Uf^%&@Hg&ap(41YfCx2kUgIlw$8?Fv+45E?4BkZ(0+>6Ag@DT zdGAR03Mnqxs=3&7NLAu*)U);4Mhq4I37i$wG7Oye}8et#an;r|GM=%$B&+oJ$nb4JToq0g+I zAWq8$1<`>7z>W?aB*rjTdHs)qun06@x~GUC%1iZOsG@_JS$p8)1aKlbwdl_+I>^0r1oENHf(8*d5J!Ck z5#5L?DtUy+e`A0c0eBn0zZyO^KJF3_&ZR^trc&jkbC9&rn%P)T3|(t6)-gs5ejm*u zSIx1Jc}_KXR?5OKM2mLjzk^=;Pk(cBm!Bw#9TgP#SW%e(5)zQk9L8`$0T-1mNJ}Ci z?4Q8eR5#`zsB4&j38A=#qAsuTQ+M}mvNQkN0nrG`%*2`p_0OdE`yb0^1*lzZ6fR_K zbdLzguAmiZejAWT5xy))qX+-ud?4)69LQl-+N=r6o_MC?jKIDF!R4SOhz<6W$27ti zefIpboSp-&f&vMhr_R8}@mUO>xdsx3?m}>m`d$XEs^l$JR=`z z19jfy76yXD=zOaC5y|`a#~HeZ7uFJX+K9J+~D`FbF8Hli!;n(Qpc6jX`KJSy^N^sA?lP0{%PrZ@~=FMZb=fmAJR?2-ZHeY4)kz9Otd3%$DpTFjvhh&qs? ziFe&Qo5s}|plR^aAj_I!d5pn?-`*${Y}^nVc~lO+nB0rw$?m5o9t^u|v5uwEU{~C~8Fl1O^vJb6^k)V>X`c*}HAIx)Y ze2`Bj-oZjyx?p1qb75uL1Osk;B2F4+U&IH^uqWddA^=+m^d=U+!e-fNiG?DuunzO1 zSOt1w3`lLH5EW#ysqrBOxhcQ^j1+^hw@oZ<9rd_Qus?m4an)z>|^F^Q`(Do(}e$#U1LmKXbJ3!7e0w=4k+3&-WMs zKtzN%4-YPI>S@%Nn^KE4@-M}EhHUQ7Yj4`;?)RV!&EDKk(>Ci$Pgl9g=fZ?HgH|tx zn;XseV|IBz$H&h=kKk7#07+s!v+PbX6D-bwoe+Q!I!I7laNxP~PG&_Y1P+=L#xj9{ z4UunV-ma={Pj5|^L+yOsd!D0?9%q82@#e-Q&Gg=c2NMR3gg!lLF9Zxy=dzRpiI5>} z)cORh%A}zo0+e#_Py_+Ly1qPKHfq_JV=I2a^11rQ>hj3YgvI~ycO+AV2?R20^*};e zXgM)KSte6i^Q4i700G^9|NsC0|NsC0|NsC0|NsC0|NsC0|NsC0|NsC0|NsC0|KL7< zdlSA8*5@cb?eV;=eg&z+ZlQp*k$it_tXVY0B!d0 zZoSax8{NU^0000014=EkZ8N^`?|bM+dEaHtjawa^SVPQ_oolyFF4Y!mb=}>&RR>b_ zzHc}^S83C|d_Mc{9b@cfbpz>Xy`JZG?k+Z&Zr=NP>(x>9G|cA*ryMXwxQB22B|TMv3UaBNQ5h2msJb zjRqq|L6bnpnWI1kfKO4Q011hvn5LKpfS!rzJw_z-6KRyh*o>#6Nb*z7Dd9a&RN6Gf z9!atzG{T!|nWoeprkYH8p%8)q4Gk~=2xyp?lL?b1jGCBC6Dj2Mm?KX~F{X_fPY4s* zg!Cq!DYBV}YHd$VO+72@u0U0u<>8a{?r=d?|m`0;)sqItL^*?D*>FKI@Pt`q4n@vp*)iI>?2c+_k zQ)wQMdTI|*rh%hC@_-Gf42?7cQ^+C_GG#SAO)@;B^HkcNrZk%&HX#Ovf$9wyjT&e) z(9=L3rhsXnGzNe)&;V!v0077Vrh`U+8UO$Q4F;M-0s>$YA)qD%WW+Qy&}dB3dT0}A zq`^G|o|OC~+8R^wG{_TaqE9L0n+TeDJyX*|BSd*krkWaRX_}g5BxKV})Y=J&iJ3-& zO{ry!>nlOVe;-ciN%5G7k&1n!AqXf!0#QDz6b29oTu7j9!6_rWNgAUyNtjT&kmw0xE}kl?l(k&hrn6~lOWGmJRDmv;o*6WE>oFDphq1Flv7Ya9 z!4w_4RS4PcJ@L0=Ov2#?_mN2!eG9s+u-Gxgidc2vmqD^9EWl1kq zXsupNYGxjx=|*RH640eEs3I!QDzMF3v8tJ@hVFa(#fXDI>@SotGj?` z_+{3_(i z2FkL8;Npw`SVkQHPG75(^1gMQYS(Rqm^-HOvh=g8Ru8Wyc zt5gyyf{}jy>swb6I0M{Oe9je+&%V~sf{+caLG@=3hQ(aVSy8KPeXT!$qkt$$jtB*F z2JikFg>Q>KQ491LaX?Z9%EHGrb@~f{zbL-rd0Ex9>xDsfO2Pa749>BVX|f8|*BN6a zq&RDNNDLRe3*^w>DI3~r*HVRZ8Op|Yr@FJad}i`gByy4SkmxC_pSBcqJb2Gw1zN}SXJkNpz;7CPNC0*1Aqar)Y@qm8%Mh9pqU)k0HIZr876!G zxMI2ptwDqV^5cBZ&@wHNDhnd0hzbQzf|=BmYjsu(*=nOfSt>H-+NFF^Km|Tm18~P= zK@?L~?Xf0s7#8e-9E{m+gb%)`6HC-vaHXYS7(=8PMFbnoO8S3x!n$>A6zpPR(xjUr zkO`8uR@fLTmIoNGzztcby8#d|fz)2;?JeDg<~zH#I2mOsi$E4F5Cka1cz}-3Q2=4v z68+LfExa%USO$Llg;C&Rl!=w?5be=XRk=L)Ld?))1KTXgpdb^I@h%}0aM2Vg=X)He;_WRWGE!zT=2*=YhK5($G61s&=1*6z*+lS;Au4X`joo*6!uG&bZR z_KfCY!YfeCYh;Sz>6yo#zSqCCdchSHw|jCOF2yD)05}p$OTmX&p#jW?uNBnxI{7f7 z$2B8^-J`C9Ypp30MwE`c34_2AYH0V!R3TeSH8yb7r5*LUm#702M708Cm1P~@F|S8h za>D>s#Wdu^J)GR#rOl=!?0kjI$neu9BkF_QZfOYP-V2VIpZ|i6^u4(8v+}b!oe_En z6Inf~b$EdoQ_Hxq2c9ql05-aPM9~05DTVk%EhOv^m^bB?GQ(Z~@Vh%9q_j+HOfnW) z=r7coQaW4%3*2f(!anD|4vWSwC4Qlsh8K+!c~Qnj4Tu0^CVOinu8ygSgDm2A_PBZm zy|GwE%-31rUx2f#ujlWes0&dwY^y@UCAP;I@endW0VJiIx1prZeWszAQHpux#m9xsMx_96EQE9spUnRirXz2sS90CYjumOCM~z{AakIm zXGG~N_z!3mq|k&Oz@Jgf87C-%zl5TRQwqyc7d9m9&LUf9?>>v=0g2H9INtfFT9Au! zi?FEa^_iws)iV-w4|O~Y6IEp86otTwyj*w z!JGH#HCL5~Ag@&g^t1skSz3sfA_S1qL5R}@fm40)MZ>5HR@-LvWJA3>%K!ySI$65x z{`N`>QyijP^Ue9c>uo9QmdNDG2=d9aydnb>!gCPa>YEK*z}b8AGf&Rxb=ak8auu!8 z4S|rr40R5MuDIP5|XY|Ka^2qR#edz+b9n} zsM1J6QlXYuLVThxsYhZXg$Y3*pm9}*NHPdeQ3)iSu~aBZ4k-voeSvHU3Q0jAg@Hnp z1cE{mfS5IL*o`3QiYpIHcFj~I2?Z3U*o&4ZB#@lbNtLWiVvgeg1cFIINfpJUu~3i* zD27eD5rqV^F_7mm}!r1R|eX9=J&w=5Vu zWS)3$?J?Ki_OH1&361jgyl#tRe21*qTvUwmKhJfMQP@~Hd(^YnjoECk-;6EF(}O9H zIMcAK#B*H0E&&Bk*ClF_7M4jIEi`QvD$lMbQALL(9{FL4JoUzZJw}YG$7hhFr0k^voEb3{oKu-a}t3 zk;RfX6DAoIjKsx;5rrO5-fu3rD!LVBY|PLbPsm=OCLB%}Rb#Sg-9JMnW_=up8o7A} zBmm6|805m{tcIFFAQf%YjHXW6*$w+NpDSf5B|-)6bzr6n*+_HFLvRGqNB|U6#vgqR ziW1hmbh`GJib1vrIS|e0J6wR)KQgYQbNZYeq(o(;HmN)560gDBv0{cElob^RX*1HS zVNJKiz}(P3rJ=5pJX%Z#@C4|yJ`Lw<%?FZ96vTpwR77o+8!E=$x^)FQbY&a;;PfJQ zxJ}Aa0FsCS0F*|AoBON1MQE*mxZ$HO*=ydZa-y3R4))ZZ~}W zlAX3E>E%5eyrZ??h$^ZzLw0pmc(S_Q$6=Q6cxy4wKWf?8Qk_43G?}6#DIg&N_*6`Ap($(SM}WYy46lQiFy2X|v|q-R#4v(Sqla4hjKaq{ zCT54hW0wX~-YbK=w9?X}C0&wuYNYS6Z)?yGhlnxt^Z*f~#+ikAaD48gvat`zmSp(f z4(nzDM-dbrkUIbn!RfjK*5wS5&OgDtZQ}f{$GMjnKJbbfFEZK|INfkcwBBvEE;~RJ zecu5F94-@Y;Ps;elgSV-r45jNr}Xzny^h( z%8^KECP9#*`K0s4WW(;b*CawR4!OM;=F%Y{ z1MezV34!a+aL(E&I8l>i>(hP+rOQRR(hd2fX%NioF(`PQaYcp0X4`pVSDf@e=1{dH zD!BF@+$*Sb0(#~b)+SWA$v@-nc4_eDuovI}_HDr6)|KCC_~PfUvE-euwVBoH8B3?} za++b>@Uym5dr!M9_~kCM#WbGQ2v&~Mncw;(N z)-Jr&ReGS{k<}@9uGKf`FcgxDE2o*W=<1n7Ab{S85s)ECHb{_A$ontHJn_w(*?GpI zc77002Z`Zna_gLcpqcp>QK_9lulGxyjR?(*9KS=Trn&l#cDsD8Ik@KsgmY2$ik94a z>&1F6y3-ok*Wny-IK1*x6HghKF)#r2G#E{umKWLDew95DnD|Ha8=cZ6uQ~b8HsoiU zXg4|g#x0D~Sa2xpu1vc%Yh2~~-5_XasG&xYxi6ySEADNcw}M%i7=PPQl@;m}vNAw3ksz$!;f5Gn8=>?|o4 z;v7Q8b9-k*{|(h0G^x%Poh`Rtk9LI39!mDrRyzgEDQIbEV1j{fHYeg7Iw}%3)GrX@ zq1-SrSo~`}ULMagd7?PT>rQ>e6?%3YQ$#S7u$6!%N zD?a^MyL+o%I&t$UV7TO(y}WB{^|yRTc1x7TFdV$vmx8S+a=XLZ zoWaBA+T`QwGn&mDPg?5+vtHz=5(XIcv*MGoD(z>k_*#{2cN|Tk$(0yJ!-~Kcq;nq7Ti>K4JnEMF$n|y5 zKjSzttwi0ZpGQnK{6wFC|0mcO)d)Qc5TaPJan$tuRLR=0gMsLkJy-q`!|;h%+6&IZ zV_@X^{C*zpIF}p=WXohxDtGcwLqk%~@xdyM`GU zF3u;Jr1|$bp~p@tiwY_s5pY=)n3Qx1wfU+Dk#Eu`Kb8PiO zO%woBD3VdmQ-lVU@UQCWp1#tGvFx$KuAPF2_TS3B!nb_NCc7)5&$F+NhF{k5=rL7#u@%~ zsHl}(K#q`*pj_^wX3oE9LueDru%faTcSL{f2Mh4q$UNig~ z)%(inr3)Fn%O;%_0V$Xnw7R`qmw!l^uk93`1r|JW-M0T8bc^`Hhg=v#*y8Mb>~Dv* z%5OdXTrbs#N+1DSYUJ6>~I!Rx7y$g>$yq$SPm zHC!HBv~?jo%K1{TN6`5gxyTS8s}e%2<`3IR%QvVY?Fbzn6C(HO0uAv*7V8TDifwe~ zE^2H%KZr!J5vyJlB)O}G+k;|4AZipsfTB23u?QL1I>Zfi^4;fB!Yt5u)ag;y_)=*U zZWl{%qx~PJuN9=zWxujta<>d*TD)21;~~vRjRZEtCTFHV3uN(c7}%Zw5^_7yluIgoE&Q+<8lbFzy^YoUml90fWo}|P0VhAn?mC*=-B`Zb z>bh5Ac1JoPBLCx}uU@3oweBuFUOr%Vp07`6Hq_PICeUW~eG1p_I36v>$%xs>Qa1_N z*%Xi5rMx2zHnpQg_=YPu2yc)xL>bMU5NUS1JiE|)DaViGtV)`!zCah}uDl_wbFkHA zguBD+`;wW8-!l&?v8?e~i#^eGZob=E-D=f$2ar5}3N4GIkqA17l$nM{6W06P<{wIK z|9^{#(9lOl&^X5ODa-2Vz|Ai^)}aW*8XJ|gGY#Q8p=h(SZN>cz|G?f-0e&}u$bhIS zZ~m`-NB-0fHwP=4?4)qfZd5mC5@Ha5AqExfx{5qQAyTo5s-(&SV&ut`&zh!>!&9pS zFlwI64{6CKHbIC3TU*W{gp|aJfU^hWqLmrt9ly=7dM|E~pzdj$Mp1sFf}0W;Y`8H4 z@)Q9Fia>gcT2O?B3=B8S3YcR?j2^6w8T@T2%56J;M0?7&Q(LI*u8>1mm`JY*@Fqne zEQ5+(2v8R)VExWx=(@8W&|lj+nu!$3z~><;EWxe<5$_y}p|FH7;8|H++&PgUZI@}~ z*HzaYe47D(17Zd;kFlVuVRRaK4*%Tg`An2Y!U78SPJCx6rYE|+zGg5zG3F6px1&VUP z$gox3s{+2uQDap+qapP_HKj_pD|zJWvr6F4%h8q`*QQ=;Ux$> zAs+<6*YsXh`0raQx7(^w?{0C&zb^l~-dwccZ7LW1w||wkHN<*Ov~mzIw}qJ+Bt}X8X0( zI)T-lZ%-wfv6J@h3$*|wB#%N${sD=&DkYucEvCY{HD(XffZ-Oslkm9r7P4Mp+^50~ zW4>i3he1B6{sG9R+~y*7#G8K@`HA`LESv4#HZx{3%QYn|vmWzR&L0xvpNsbJu45qn zHQN7dUHl(^=i_w^SC(kU(B(Cgc5eUj{Y|yMAcg2E24;;PUO93Cli$pw48a@vtIfIynZXoxRaa5RU80x9O$i zd#+)74WDi1UW@nVpNz-C6Np$ptY2xr_S`} zmXf3#jwE1{WZ=qo*R(<8XLU&(?$t3rv;c$xq%7j#QLklSLVFM%h%yBFchfkNs?@1H z)cW$jV{g52KD=8qjVVZ)N(Ci11XqkBthyk> zSiT(qj#-W*xVn>95ldh>(^0=c*p^7V2pmBMzV^i4ErQe+P;!BC9LOJ zqGF8&xe#h1CmG_q^ZFeJ3T}j3DIE5-j~yr0G;=7o<^rsj=Ow+}gcy=>i`*)0JL>6Yv2K;5*Rr`i=bc|G*_UJndD77@-AbU--}q zu1A*kz71eNo@M>-{AA3hJ!N9l|wu>>j8m1L`yM`>#bua8*5%EaHeeehc7*=!=4h3&!qECg*j=^DO zY9o6lV$80pWKpA{f-6a2;&Dz4_^v_=SR!RIbYjyY}gT0RpJRBdmwoMDa007viIl1m@7aOc^@OLz!9)~FyMmMp!zL|tNf!Xw# zfic=MqV&C29eVJB2*E1Me-kKs7}_^*EWow-$*K~RL5!L<;T0l?a=;g!KLWVPRh_B^ zhaW}MlN&PZl&>xW$aT)xUs}PdTa52J(=l|2wr)$F=fBq9)_-kYqjSY?Jx?cxN94P3 z+3xqW-theU&nY!qWX1ZPYFWWb+`!@j7+Yb*Hyf@2>W z`aOy$w?#(K6Oxqzvsb|lEjhpE>rT9>DOry9wB6eP+YRC;-Sf7`m-PD*JCZ+Kkr$shwL_vWHx97JsYn6JU2h1@g2!iUP%jMvEN)jSYa} z{B8q;_Q3fWye`jaZ*xsmp3hiFer)=6>kCLj3YQ#Yhs?0* zFBl#Sq}TbG*-wEsVQRnJeO;k8WK?c?%@bPxzncpfz_T^Md9|dFlb%~#TQ->CrVo4> zRsLdNmju`c4dm?0F!B{)K%kpxH8qYzw zs$}i4H?c~y63oRh){QK>Rc>tsy>Od+Y%4;}A%31A1B8SD#$t;nN^v)xC)5~+&|I3{cH||-}$coY&)cNk6L}J8;Mu+K% zWX_$azV?rrQ#-DjVP}|>6b!ioEMl)4KZ7_~7rP$LC&NW?jk@OK!e{r>EJexH@~ zRSyp^o;T_Pi80qhvIQcW@Jrp!=rlIGFR}Znrk7RfqC8=>uaP_6eBgf-((351)Lg&M z4>qsgmcW4wZ}EYlacAbUS9#*~wD97Muwy2t;~k5g9QA)mT-26phBZu!Uk56(nx(1H z*9xq*0O<+O_9sZ=gVxAr`FQZAYrJ?Nk9f&xROP2(1Ln2v6K`dg(ig`t5O&d2Y6O7XCONQ93@LWjIoCkCz-li5fefsbRy)Bqxp96W&G!-o$X zI0jc8(|(di)v=#Pt2GV+7dPceUNjrrn7fT801bvdsafS`IBKew(Un#}EH$&g#~)uV z@exQwKszD;MBK1Mz?+{Se0B8i&_A9E~Ph+f_Pu)lPkibT!rYT?O(8 zG$LdzB4ZL!{Mm~}LK-~R-kkzGlz7PS9LUwW8)#@_wv)Ii9u_Gsfc0!2n)g+i9@e87 zP6caK!+E;yt%F!?B)5f7-M;Js3)lJfzVn`j_n0Z<+e3hgh{_4rm(g>>(x7s)DK6IYbPDHO^ez5!dfJmOZ_|ee>RWrKyrqAaM-|oC+vrb zl9tkTl#fLB62{he*JpUo- zV+Vt5mPtwMkMcqa11ai@^=RvzzNgEPjVH@!>trmt@#J6FUHdog(@rWe!{%;%zPvx3 zK45_;@6{Qw+?s;UfxJyDSha1t8QB5EX5IC1NYG3>@6F-u36YZ=s7N5BK9GMR&p1Ya zR#*9{9q*Ntqh0$F&HYJ8{V=1or=&f8Gxi^Sl&9rgEk-4l_v!FFXr!!bLXQ#bx?*%0PP~H2rl! zFY=bBd+z-n9-mts{f{c(1uFlDUoD)}WS_6>-N!qg`$>@L`t7Kt2o*x^!;`UL{k5fL z>uSH!Ghd(6;=CJs`0mL6e+Q@2J0B>KxOF-1^BAVQA(fAV_A$a54}ASQ6NBLBP^qNpU&E0V9YXuRdwH`c#GPE#NSq5JS7LP z1xV&tkG6p0tj+ORc>}Wf5g-7EhuJ+*-7lAF z=GpE|>DS}6IcISxZF=S2s5;!Q=;Z!SzBxdd!bz*Y(=|iY*fb>dJDsQZtmIc1+oY^L zaKctu*P7P-NMEcqKt598-$ujLWtjQ@c3_|M|K1;_&)PrIO%!fC)Wm3jVIl}B&tf{M z?DXck&l;{mxW$Hap?G&l(rX?;h24AlcTCvrv{u`{u|X`wU+b+ob$@Gyx9Mtm>ufuZ z&I<^gW`&>{#hPt$hQ+$#F`c@~;<;)4P|7}T??V&O->%v4T&*}AQb_G}C2wCiz@L@| zz)eEA#V{MKofJg_*8sX@>^9J07SN+npwG7ZCA+-TFh&weq^VxFT6#_UyuWFAT~)Ca z74&8wBfj6RTf zrzSXj2|RahT%wMzAZOYs&=qzry_YLT(62x13PkeQM zxXlaFLoP^VNVZ#G&72CG1 zX(8~I?$Lj3*zr(2OORiUn-g1a#66b&%_c9_K$va4kP%kzmfvyqNkl=o=6NjD{TD(B z4kkML{*#Y9b4KG>e_G%P62LCg&mabvbrvkV9p@q9l z4ip;7D!eZ*rk{-TYciq$naCfWoM&ERH+!w$-BaxD_usHOhY-Tvi2%S%?@P!RxsqZ= z&icA^`#MpHshg9|Q33T+@zIQ~B&8JmfCZ`OEgomC4U=x^1YiSPPce}k#*KZdbBe+K zR}tfv;t~)d&7B*Zg`~{-PRnWa5Nz)yy;u6qpQ_{uxbHdE9Ix}P1X`z@aS5PO6RDlt zwXN#9J(4%aOKek6%QIRMKMV=7V~ot$yRPxReXsU)0?2Xu?)-S*xq!c)J)zKm5rzN| zvM@UX033h6N#qv^R6yJi2pvI2m~k}*mfEDeZHbI*)C1XnM4*m`gBXHhTok1!ydHh~ zt~bn3JkQ}H>}@_i9Q&H0LYeFz6IrsI*1QTh->jD3yFcx0dmLxari0SW5Ts~7ZPU7u zN(3T9NqKGL3`sW;j}o06v=PO#;Qprh7KDfuSoM_R4=5E zlg|su8bEIdDx24Gw5mI;r)C1-2x;&&JsQkk9dESL$DSVs#|t$#4}trrA9ebjXuvK=OO;;Bl0^j4*)e3<{_y5`zGmpg9ZTWGK?>`2B)jjs zZgMdJW;=)_fYCqLtA3*jnx&s>Ya4qsG@Vxqd+Jllv|Yl(8a)E?#HnO-@l{@V)B%6V z)~u}&-uINI>~+-uFrs!u^M-Y@lQlLoh}Sbk#gms#1&+a1G?_~?B}Nkj`R%LTqh10$csV# ziBv@LLIAUGZ!c0rKpQL`GY8Q+8&ZS{q5BJe5QI#3lj2NyEOIwUeOUBAa}`!ZdWGov zvwkXNMElX}p+P*ytGO>)C#(IvH~T1)5LJC;8T0(1pQg~*Ii-#EUl5J|VnUNFx`mDL zkbfOmGaEJk0{nj;B9bB?{^1BBd6fXRwpIJ3uk_`c-nH}wo`9AhIQ1ddaqq3B6A1+f z?VUUTf)KX*PKcrwM^zBFo+L)Lb|Sqj8fOZqkWAzpcPABbYpH}!krN#dgy^3EiBrFr zlTnhaE7*Wf8F9OU3TnL@v4)yRC8ho4dvPLEoUSUgCX?YsEVjwm+Hp|EoJFP<8Y*PP z$P2+5(j!956b#x|<=<^P^JC?qUM-f}JtQktn$%}^S=iGH?$NqNJFm+aF?nI4vgDa@ zBs3;)w3{X;qd`D8It3PN8-Tq@LC!|2o@-{u0adrmg4mMxi@7Wf%z*SgOl$t&jeS#_ll}XkofUM(U zdI7*yq*O|!BdwFHD=c#Oy!?ge0u+Sy#wkgAA>-ljs-5t1?y&l31!!<#NI{Sdng_q1 z$~-yeE>x)>zs~z#XUpAU<4y%xU1-NE6YV1yTqpcWYwpF3n^K{jjBRvI#wT}y7EV@5 z0Z+{}EC9q5;*;rz%PK-S!1twt;!Z|u9JG?6$~n#k4lD92b3~PFg<1hXK*xE;P>JP4 zWRR7tCAmJ?&TL3p7?&3MPOtE&^m_tL#fJ4bap=NynVIp!#2qa@_b7NH5XoE;g=l^ZW6 z&fnIG%Q=&4sL;&InJ@$ORtBfSjR}n8O}RQlq>eTR#30}#Wtgx5p$C$N8nHtKI4saQ z8Jcx)mYy1NeYRT42=jB;GBR+xG&Be#J)ve62G;>(Fv|h@flKQzt({OWPzltN1jbBY z0?RQoBZRw~!t)v0KJVN-LJ%NFxOmA!o_*IV#V)~{7;IzV=tn51f}p4nA19Iyfd(?e zI;y+n%IAxW1*jz=#n6YLr|O0Pa121cWi0h23;rxEj$Q2vE)EM?WYLUG7-gHF;&kn6 z4`Lp+7(QRjMs-RzRph*Nt5GsJx zq$O|AE7wqxk7QvaxJ9d`cT)CxhDEApv~p&M78)ldAX+N(w8|J{1h6i6$V@Qx_5>=D z_o;>%l^&izs3MUm0s!!`kxw*bVw4a=H4VhW( zd9K>sJ(|rObnVMjaIl*OWy_X&*rADkf^_LxgNcEFQw!6utN^%k;~`Lhsi%x2UrSa< zUTiOt$%E6cMw0!Ri347NuF|9^^%!{K$uT0+prh<2FiftGKrn{t^;y64fUf9N;3vy$0#7%2@y z*~q`TwcI+JbjDOAN+S=z1bDsZCCyqHc1*@D>mzC7@RZ;0i5+5Rl~(LV?~v)&4ck@mKD@npXoX z2s#KAkTASGV+cBSRtF+J9`k{du-Tn{znfBc0FaXkSo|tWavPxp2Z&Q(@Ff7QV0gV& z!L1QBMBFL*;EGzU#0L{V(lUV#xzs3qTruIgQtcP zDgsrdghI5-%GYPu%zgrMUStKN%dI{AhFu54ql4IEcc`oDJx^3^k>cjh-OPzENpBJx zE=4hFU;LaXk18IeUm{8e2Kythm`PKl`zh05)>+_(HPsy#L+k`lwW$LgCo+`wp<2`i z35z0ZHo=8>*^Y)+a`~=dkYu9=ot|t4WPX z)YR+_>!;Q{)Tt(6(E=D1){Ll})5rijUp%i za4`PsoV!&Il(I$vaH<%9GV-&C!i3Bsy96jj8znu8t%E^bU0f-h3Rtma6yoL6x>5r` z3ISUWDnJ%x09k}lIN*ruE6W|dOB7a{7mzTeS6arHcb`w!|FQc3xJ}EP@k_|&wd6xN zU)i7L$UQYE7_XTqa2}p?uQXapUnjqUn4+bJBLGU3KDb;xq_xF4;LDwxZ+5zez{S(| zV@Sr@T7nt7H=g-X(Tim93Ru86(@LATNTU%!Q%XB6s<;lqr;!s^C$%*}q&r^hL`D?F zZG3jAOptpBNT7)%0t;Doij0`~AZW&rhC%&bA#>)Le2ft$8ZS2#^}IT}>X4=Jg_)|i zPpDFe7!*VfT^=pZrns3z9-S+ihGOGz0>c9_WFeWnJW`2PXSzTRT5=C|;#3Xjeq}0# z8WBQXAt`mcBa4tbDLLFuBDMSo)8vxmtc*q?8%$IL6nLYtxuN+|S_L$e#;a)%usCRS z8f$IlO7ZmBJrdEekR?j8zLS7nfK)C`vUb(i zo=9z(%d;I{b4q54JYX{j_85vSDQO?d>-_#JWmnO`DfEY~+L|m5QFRoIdxJd&Fsw{5K5-!CvF>EUtMA`hFWaMIsi;OOm z!iCum+5(IOgRmb`(^*}9>WMd&o<3dO_7)ah{)Rm(YWYDW1i)1mqc<*coG<>supKSYg!zF z3%VN!^1ud>&}rs6k;tpX$r31tqn*J6a_Rv$p)5gcWH2CDh8HbcA%>!*sX=`WiU!w& z5RxcD5nzmhq#CobAyc!u>w_|i*465{vC8g}#w7vMouzc(viLW*Hsr4d~hi zG(5+)Pw1RYC4h@+rdA|&BTQ^U0D;c&z62DvC}`sRB4Bt74hYQOAn(J`3oCNA98{rT zIOYp4bO=EDo5j|+RV&xBr|r8?>WJ?;49m!i=<>rZ17b?Z%v@>XXPngDf=puABt|C~ zh>!`ZO^z^J*yji2eO%wEJVnavm3IrVeU z7;9E+@ZaGU;sx3!TQF{N{H_DA=QmJRzXeK>k|sMgeYeZ@?jaDQTL!TLv@`-ndize} zdm*hXt++@x4A8;*-PXWy9iVmh^Oca1`gVt-l5&^>HhT$Vn*Mer=FJO?7Oyh%e0j+ILxIp8OoWepG(Xfqe zN#EY;mD}1cPd2vVxr|T?gzR?h6DX|{K&6C;1InTz`2_n=IXZjYtEUyC?2%fG=%F{8WFFqB__ z>j||i6kI#NrT0?WLd2pwOhFmo;C#he4JpnL61;+1RN52_Ba~WR#)3)Ef##M&l9Gc) z)X)q=4{2m{di2rAYu3`$Ck%R48B`bGpwvj8lJi(dH(E$p0d!h|Dmi$Ogfe980LUro zX57Lx>$1pQp}M_zC$0La&!ayGQqv_ESZ^Ov?VZ>~QXsM}g5XfgHCO6LvxK^VEK*Z} zj+rb7)*$_(SD{eIfk5fHA(MQOS)&Ucwq1`fT-jrly05RYj@1DQsSY4Ulx&wA66@W7 zbN1>t=p@VPVP-Ei#$96T9v2d3kTD2Od0;4x1O#1THKJDMB5-PfO3{sNwQ_AM<5xyi z8Cbq`xDD{{@_i> z$9_IlJC?@PYpkE)R)bdbCGvw)m0HY;HBh-DB3>Qg#4DLPY9}2F1~~YLJ}?wL?Ih(t zG1*tz<^cpz7|0ucBHsfrccM=pE9SgP3dez>)>ZcCUvuelbdoAc9J5Q}joK)vgR`Ah zg$cbyUSa0$KLf-Aww@Qa?}6X-ekxb?PArbdI@GehmoO}0Ct_95018M#`7!*f#Xy+> zHHlI5)MB}vFgBMRJy@!`FfEP4=WdYH3mgaN!jLIop{nox6IIK!_RiA!<2y4cTb$M1 zBNFCsVR;L@LTN9}E9CsDnTs&a9Z{vgc+h(gWN8$C9#IK1xX!pqJ>Pqa!I5In_J?E9 zWgoejoca^)-9Z;FYK8)d+BpjyE)Yr;qNt^vA>5vYz{tT~l?gZQQyNtw4Kbui2>^iv zl0;w1wHd)EqHvANWoLj3xoT!J(kEQDHw1v04SCAS2&o1WkrI*lCnadNu#=!EDTQ_a z>bJbh4x7qJeoh`IK0_bgMcuC`}MS*?lT zY|1@4-+}Myy(YhfjVVeoC0XTRro=ucm{MO8d9?Ajq#@zjr>r*|>}+K8@FZX5ORxY) zJU9HRbsoz9^Zcu0$@Yn72LHJEOW81Saf)PHyZJD7E7GAyW_sA&l`1Eyt*D|Gi~<0 z>lICl&0}R`&rUzqM&@BnjlMTJ?g_WJ%9oZt!TOW=wW$=|lERhm)%gsPTwF{?dYmnWBRP5CBsmK+T9yT-KuVP>X80(b@@VKON8?1Tl-J?1lP#?WGd{-BL*VKE2$R&7|>E73R z9Gl+Qro<~X&nu1ULbv0Vz6SE@?jiCC`!Z%r`KM=HoXT%|BOGJ);Gr@=M2}zjI@aZn zecgYFjJ9wR&#jv?!nUXt?CHu~j+}j^ zfPzCy2_OiMQ?L{C^VUF?{lbl=o1#H?}mNk@qnz*&qW@TGWx{wNJjnL);DhC zU6f;evtpM)POC}0Mt9{jeaD}oQEABq)Wl;!XqUi3(~F{7v_q0ck5&ulO*T7tMMV&P zNzOziAvo|2sW20zG4awUQqv!J%jy~t{JA;Mg+QqZrH^IWC zcr+LKqp#3Z+xNA~0perfhq$J%bGq>Nyz63*2Pb`7g0&>eFP0)+wV{IW20OdEv5~C$ z+iniLJ*-T-SPjD6E^CYn#?@&UKJ=b;rYIU_CzezMmPF{5lU3P-~YU1wvM|dKGf1|;(QNo7~ z3^UWBqy?s$KA$PB<40}wHPM;$urMWBGP6CNJC7B{wt7b-e-(QnV(twJtua0JIGkt# zvP{7-Mh?;}wgKoW<+<7r0iC+Ey`-k`vCXwx=rd$<{{lod@saPnT$$Vz7Jn$|l-#GY zLxAnLnLus>pH=Oz_*LNi2gjC-i>Ee?K}NWy#NBD;D`WMcM+BlrJN;HZI<`r zbA5@A!J#f=4XWc09YdMwvhQS^^|+C~9RN1_eAr#+uvSvKRK{q%NuM%rB8hy2BN3eo z6{XkdJm5XiOu?8ZSWxT>2UA!os2>`E%?&=-2hW z6`Dz?7b@ap%*9Q?GG%Dbz)ZzZOEm~r{;o*+vAM1L#@V!rYe~i9K?q!C`RA{qWg6~z z3`k-bu!;xMjon`#+au!;dIXP+frB3_D*>lf13vLI4D9)H&Gvk+3!xdD5obm}vZ&!s z>EH^nacBaFn2kH?-DVo);&ylxg()bXvzs9^I){U{d7p=*fIxo9E_#K1coQ_Rw)2UU zAH3g7YwjQ^t4+!k+g>j~IdY#KRMlS)beJ;zO00bzxmH^QQhVi&?Zc^7+*)1RH7WuD z1QIgifI0mjr#ESWEwlFf_@4MLYo6>P2-=U3KPeo3BfN^%!ilgdFyV>_Qa@0JPpgM! zeWuMIOMew&1M0}g&iWElHjzyVSp`;#zMAUWnPw+6?gIc9H;6$$okv5hizTvXBA&hw z?_mnwu&-6pF`)B49dEo&H=6l*5=QH_Dwl~pi>si$+WUJAkD%2&R{a{V;h{c5G3TCg zG-l96L+Gf(38tdBcia!#`-n|$8#kVjHB;4oIIFup*Cr0O3QLI&rQOJ7p?jF-Kg@X` zWM;Z|@|6ivjD3z08Y&tjvJs*Z8FV9rB)AfkQ6$q#zCkqJZab++4a$&zl~ zb-xj&-gU;Dakm_0cN}&KPr+ujI+iP0vBsrV5scGm*IlPhohKfe^Y71j=hj8$9eLN9 zb-NYo*0W}xtKKeK>^k$yuER|>+f206Ot8ufGPPz|X6~zSRiy?W3t#_#*WU8^Jyuth ziG%Ll$^7vo_0nW+@U@lZhBbl!HZY_sJ}p(ccR@;W&)CUZxrjU*D@+?ahte#M5Q3wmG#VM#Vp5dcTb)>pPsiL8kc`Z^`-6@_W<@-DVpgC>k zuP=qB=6Kn92YjBVW6eolHA1b6IJ|D_wj%eeQd8*?N(Gl3sA$xxsU=AVkVwA}h32G; zBud<37G|rMX;0R#2c`))47s@vgwe9ZC|h9uj_uk32C!fPrUMfJ<}LO*Hvbt2dkLBkk=zW@KiZfaP*G?BZz~ zk*#Qd-VgP~}H69+Bc^GmV!{PEKT5txC5Riv3eaay^1Z;!o;0|rwt^ci% z4P3$O*m`68#{lksL5J`<{6W8d$MgM9xAL$9ULx#(JzXLLOmY3iT}}`uCx102P&>}a z>K(k<#hjW{GS0SrY>E2v3cq-UKSj?xrfm-1Tr2c>yq{6Hb7+NTja~OY?!_)l@Cr( z2>W(P_ML*D6VUrRacPK&w@BV)y5iyC`yV?ySdQ=87;a%Q>%SrgpU^u)L8HLa%)`uUYQHVZ}byQeqE63x1Y)XzgiKe1FkF zvknbdBY-xY=E~gt2ue6> z%bNa@3eR`R;xbo*RTCHUZ{&A49PY$~9#KfeIK+8*)d8-$hy3(rrY%P2N`{XxZd0O2)_wp9;b18y|9(FE>*_{JKO)WqG{F_VXzqWS-0pSZKfhi ztvEWk#3db2srgnQ*7G+VdQH$NZ%%?7v~Ydg;Z%I~?4*M2VU>&fI z-#fwkTF)E?5xy!=a+MT<93w1_S*m~z!u7suf$}lRpRTGwKtE#MRrF&Ghkm2Jsw;rW zD^PGI#TDN_4|}gyv12`7{3WW{@F(FFT`@?XP+YYK$_=TvQXvutDqbn~eynVN_`8xR K!i0yNB#b!4-%|wu literal 46356 zcmaf(RZtvE(5@F)eDTHI7Y*)&#ob+lyK5joa9Jd1aCdi?;KAK3xVr~Pa=!mR7w7W4 zH$BqTT{TlRHT_geXiCY;$nbCo-~j$t^Vzb76MTW%+Y_-?ScbOEWDr7yUB1_=0&X=L!-?0HbyVMNl5Q zC^$`OF1sjz3`2VQ;yRuZQzpDBD9kQ-HWoPU%d==fE1$3~Tl|QWAu4`GA_{%v6veZQ zL;9xnFji5PvK|EB;o(^iLJ9)V;3=b?@h|{~l$1+DHI;eh@=4W3c>qXp7#ILsP>}5- z0Pvre?f*R#jQ=qRs`9AC@)e<4qO^9zSWHEWV;QQNvzg||6$NLOYf!$j;)Qu6Wef}+ zxR(DC&vGk6A9-d!XGTEhN;Ch9wE*P-AeV!JM8zv!E2xXtWg^Qh|0gb7{wxv{0GPET zu?5V+<^Q+D16Y9mmzxJb^1o9AszfQx*@{z`FIR3^F=eGFWBGt}k$73TT|wzQ23*vv zxgV5g?vw|x4h4`PmoF^NB8lf?h)O~clra#*^GSF(%K>xwkEB)AmFYrbK4$PE-&1+* zGzo?c1$vCpw)(yJYn=6JF}PC5ndI%CQpGEqtEKC!tMJR0WDNvs;oWu8X!ZsU3x|Y- z)3BkN-s(x<_#eGtR;N0;4rn{-k)RVLyu0*$cXRoA5eIikX7E`Q%joZmr!xQjSFH=i zzxEPkeLEtaK*^17VE?QSnNvi*(grp+viz>u)G&A?Eu3idTNJ)eYLS?14d^^ZR@({< zE&C(%`SbBCiYmlM6?JL*^#d;$4mFG_P-b|f;rUW*pgJu(dRHNGs)(xu^@;4;?k{Y= zt(<+@@wZi1!%lWdOgyE70yDa& zgOzJn8IoEg{69%h1|o~h5X%=y=nlt>`967Rz>d$H^-Jb7ywW65@ftZhe|mXmu&4_! zCyhX@kYyM(AV^ntn1u?vj4tA)(c)W9`=7%(@B%J0uKs3v+PRUTj2KmZ5BbC4LzpM* zaR@&lCIL-)Gz8LT%Gr+t*#o3+vB;4fG-XuYnv{R;Xpo{;g8v+K{wI6Wn%0BFz*@K@OVQ2y7D|BUnJ$NMZ0so;6IYsDYeB;n!vX&uE^Y@*@Igx7*$JDS z)<}W7sa=%ZK!?UouU4ax16&_yEm0$T&CWf0KdAmSyno)R40JvhJ>C5f&Tl=B z%92jARQ*LNsoz=xfJhW5%g{G#Z&;9Ft7sd-giU|_i?}P8<1KKQGG3Y=E34LQH_WUC z9cUO3LUeBZMr{UiF3$^aF5# z03DeV-Tegas3^aA6Hra0@PJi-$H-U;HPYd!4l6n^<`le7bs=Hj4NQ^DoWlLit%jjR zJ#vYl0A{rK5L9H%r6{0$;A1x#FM|tro~o16l~&@yM$M^RZLY_!4aCP87?rO6b*W}z zI;jv!+twQ1;t+VARr$c}6Lk54L-yK(qp4g@;rM%mZF@lf4nZ0)5Fe)BU3{l4MYdy)DBj2CI62Pc>0-3v+Y31B`oqZHyNCN( z^!pXIcXy>PPowvM$8k7wr^FOi+ADmoq*AVFQz$y@H_>bx)0y#EE#L3v2R2ugxi~Wv zd-}Jo1)8d^+F~`7f2kkeC)%EyohbI!lq51PRhxLYep_wJo2R3aPw1Q#)*}tVRZsX= zj#w#;pQiaWa&+f888~5T3^p?7uO(GO&(9*F4zj>`DmocfC&qB8~p0=9#t&&dMP^75ezI?|oqX3>&F7gH}3< zg0;ZKAx)>iLgE%BtH`I`Bz`WxK)Ek|U@4^2C^TEGc!iL8H853a_@~Zvn)8-X)^4kJ z63!U`ezk`zls7RDgB>0>NUFtXWLve!SrOBWmVlD{46IDleuS!1TVK7u-qv_&0lh1R zz%2R@@w%eogVDYeZ&<9(<)5R)h<6& zve$8x`Nc?z?fgjd_ME}mjz4D*KOEf^SP0pZGnX)&r3)Eb(QaT{8*rIAovA)?a>W;D z`l(u5*V|x4LU(2@KJvm%InKPkWScu3%C%JpW8QaPN?831-gpFi%40=y?AqZh(2h-U zRN9x(TXb~<4IZ16R7W#2yM_~*2K|K0!rQ#BhMp=}Iv0k(Z!2czr1(3bgTt&V3DK=` z1a{6GXDt(7V_r0dGc2?6Gh>B*Z?`D&b7j5;$Y6vC7&2LIXjl;~C&}O$@eX6rVeH5I zHU@wlwTh-dSsz2bbEnpnIc;kv^JZHN0D9L*Z3hfln0jZFiWiFO7>p>u`bXOKd&w*K&MAN|(1AkG4z%BJFNQ32C0ooc;&xra^_Jg4vbQ z!|dbweCG5%0077tMmjo>r;~=0ohMLsnv>iv4#bZR?5kR!%7MGdbKF7yZ0u#9AS!Y9 z`RQwJjba`ytGo|$Ge)@jiO8ammVK;fBV#)fn%e}iT+#26e5Ethj;_0a{&60p4m@14 zAB~mfIg7|c^;QoP%k-S_@T1pc@u$>drM%S#4fI-=FUhfo<8nY!BYdNOZ|T39mzurV zHSWtKaOLSbKUl-dL2Wz?qE|({7dA~{F-9R{MOVr@6iFluSQR6oBka+M*nF)L!~V9k5{(>!Z#OX?V?Zbr59Nd+M=0sSUJeR*ES>uFdg>|R(cIa2eDvByi zPZdR`_i_cY2eO#RGZ9{%zU& zv*poUd_#J}WRto|ce`C+`R;Y+ zzYmaQAQA;!f5|sZ$I_QQ;|4L4A#!sZL2MKxzz`jPni>#B1*MY1jj$_)pFyn;&LUC* zejt>^$}fL=|EPCS43r`H_VnjPVz;q={q@1r{qc6i02?F3iAqLn{_YDK{Zg)M?@iVA z!{E4l8bnQl(dJf&iCc$svV=NU~#T!S`UI? zp^gb`0G{*xw_N%)6biIBt;YPw04?0;eX-xU)u zbe2}<$qR-u)50Y>hglJWaRqwqMuNnPEAHy$QBa!cvecu|_{k~w$AW=8oX~=JITbnJ zO(`B)p#*K0fsT0*6?Qn+e2SDu@j^Qk;I9H(WM}W2~lSF z40zRsCr}?TYioWKN2}3*8_WOCZ{aOHjiqR%swG-xVxc4!btaJvmTJ#!yBj?>G;TV= zddA6Al$Z>G(jw!kT_EfISF#*r3(rdsb!2s|4H)iuc7sYR4(xJWs>y{JR}hEmo}L?2PBE+pjk7p zJ4R?XZ(%HIJ`{^TG)%81L;TLKTw(rSK>Pft-Q`V7w&>Y!UPaAS_0xjt7PdXas`0lBpHL777mO-MS zV&S(}*!QPcZ^%}mm|m9=SM&Qp<1~@A646tDYSult*)$B)o_e^z)wrR3A^dM{FxF^) z5CO-bGt-`5zyLy@$pkivW0YKW_cUPdyhoQ!%`lwEizU7~ErWcYpNVpA?C&5lYUdEj zba2#)As+aLgSsY^UOo8j(7>Rx33-E5W7Fkrq>K=!NG7JvVV_{zGFe%E2lzXpkqg|4 z{y3RXEYHWlz=&N)%_)KB3fS#K1w`x)08xMd8aMzoNYXZJwc&9{+1tbzQ3(Db?2@Jj1hP4zKzaqNE2^)$C(bxVh60j{j-XiI;J z?sT4Z;;nKeXg`8Js5_;!w}2>dHCpXc)}ivndCyHZa7d$eeu?1M;8fi7!1^njjeIg2 zfoMzt&exD7J9(q{(}Bb0T4o6jJ5$!kwe|ZZ(>m=h%b|;|+&>cK*tvKl;pAQ%rb+Lk zX-k_Y>82yOv(hUoZH)u<1!RrLQQGX>Onm3-RID?1nRUZ+`e|g;tIwU#<`~Zc>Pl`Y z;g<=1ut!)la*m%tNszI!C`9s()Aa?i+&VLz8g^en&dfN(b*Ngnt8X7^b4wiK^4bd( zCn(T`MOoA{Z}AZmq#1loI)2IR?Zvc&<*Sie;D%h?(+%#wX8bwCG$wbspIn_McCP8k z?bP;|0tVu;b$tmCEfss|N@5xai(E5W1pGg4B39o_5BTo(|Dh)TZSNRnG?7fDYE{OC zw^^sCo#vwzmcv28fP4Tz_>-fyONn~r0^olX*6G_fo^mpiB|aZqgO-1Jq;ke*bs_~6 ze?W=@0C=JQ!<_oOK97I7 zwbka)?a}G8?YB@1)||_+AKCJ_JRofQ<)W$RD{?>mu=gC3=86d!kiM)kZ8GL9l8c;w z>LuOnao4qNIe6>piiirLm6U`s;K@V;%>wY?F&M14e3jrdXVff_X0S;*jT784Jxjzvd@*z&|_K9yFy6yH;qmYvy&6xkD(%bpQS zEO73;r1eeretQn$tN#jAmu`36N`P7GEyEzl^!Kk<@1vjXyAZD04gOV zJWb67MAfn8(y|tg+}MiN^f*{%qdJMI*!ZK9x%(xc`_TD!DAV_Xcxo- z;DJZLQ^K=F4dV-17cQR5k)9Gb`_->U&Qm5#OT&V z73?mVUJ*%|{>z!GT*-r_Df3O!3WH}X|39MjA5-GNQUe765TGP}L8G=jwzdcoVkci& zkB1X0vN(P}EQ)O*mi{VxWjr^N+DoDAmZ$WmtznT#(h^E~+-nYVsm}Wgo@ng(sE& z7@mw4SZ?-=C}S0l#wpd1+zlRfn57#**g2(UNqe0@3=ZNMoDR5#A+$FF!)VY@W?Az^ zMNK6Bns3_;zoFGyIu$5ZeLBl-_LpJonW7?NDzfzlI6 z^IYSp?Blok>nHt6bR!o61})CG?Acw{5zIrj=28y1JNvIM{~}ZWF=}|7u8AeP>yfs1 zo{-7F!HnE80(*#hT14>MiWaP$v}NMHA3d$8ZAJIk$Ab9oMXEET#RG5pQzyld|CH5O z;cf_M;Y!)QN}jLdi`F?JvMn08iO9wOqd1yEr+u9rMlRkNGBu8Tzl`qia9fiP;*T9w z-FR!67xXHpdX1Ozm0%A4Q_LGiWwF>9sn})b0yW09-3g4*_a05q$ddWTrm>eH$Fksi zN^hN!9*5d;YQ$~V(Qa|bx3{2}kvjob+%%QKYOde?NmQc&8`HX`6TP$CJeu1MUd=&Y zv=4d<|3kq`)a{p0GSi??URh==u9mSqNwp~yOg}DznF=j=ALx&$s6 z-bggX0fIwHG2{j%dBhJ4Xr++FmN??^i^mpgv>2uuQd~FSxnw`kdEdgQ>0(wyk_Tb` z5XY)N(;SCI?S&>UL>jFY&19|bT)Bk?llD)Uvc?8uw^YQh5yGvPjjXsKAH=e0w`xOJ zkXq?7{qr(KSR+X2-TZOx}aS?k+v%^?Hm^xcpU8sCmzfVdV zb}nkp@18gDC;Q9}D!Pe~1ucE@$yz@g^sfH1)bSTdNU+$aYNVlA(!|C@g#`765l9c= zyD`Uj#BM`5)yrk{Fv75x#DI#$87eY(#{>wlpb+u!n%O}r7YCKPgXJ-vocP8yAzy<;NH^1UJxqkiP&vB@AW%kc{S)L9wKQ zuX_wo)#!EFc2pmZ;)|7JidEw8#jmakj!F?k?OudR1!r}n_;h1Bk^dxPl~qwN$vWY> zI#{)7&27XJd!aVg2|+S`#ME4;Fo+>}H`ly#<@KZgJ}z;M_za}S_!lzj<_kt1U4lom zlNJ2t_>(#!H{{XTLT7#NHx^FmpFS8i8=bIM`P(Z-2_UNkWiU|Z7|k~fIyo6e35ndp zXRJ|+L$`@h)p9qbV+t3pw(HAU)}rp|Fwp=iN1fjf0{EMR#e?>D>8Z?!@w${vjtM=_ z_9TMnv9=hvX+%QF>b7ZN@}H2pp-X- zn$oWft<;sd(W_{2u*(oDu{LKE1YY$9yU5sFj&E)v1ct!U>9G2Ua4Q`K@@Kf>4g>2&lgXP)@%EGK3CEa!n0T$U8#8)KYOEVL zC9OKe6={iK=&(yMe4r>Vj=6Js+!TIQ3hSe8ls;o8XW!7nE|^noef8X-I-+YtPKkj_3G+B zxhbfLylLF>M|$1m==DWmPfH*I_nS$>m5JB_BpfC!7?X4kGy7lKe~QKK@pR0Nki%Td zk#hV?CuL{`Thi1(ck?cm%=vUJU%C>zT?r0;Ve7S-pt>`v3wb;1^UVa3lbhL*T-+e=H*|CMd8WY2x_X68Rq%E~Sr&PLq^ zUq$XMBZr$Gp&%I6To*3iiqU$4VPpDp|kU%(X9u{T{N- zYFQP1sEfLqYKL4u-=~jL`X!Sh(^pjDPan_K{8ZYvn)(mX&B@k-om52F2t!xb{T@_% z*Y=r(gxc2O$?V=Q?6`zr#eCB1q|smJMeyRv3a~}u=`T`D#iDb|*Tm)hlTN#f;XNu_ zRjOoz+Cy#qEFZrx*+D)P0619&Ih=5Azqz}wkxSTaKyiGYQ~(A0jVbyjuV?uu9Z)LTkXx!;sPDK*^1Z}Z!8#o}L1TXd@!oo*Q)#ypQ@gI2{s?ioVHGdKR-uPqH&30DvH z)#a|heX_m25S~tru}=lh&K?S|LbhF$r6q&ymS-y4fbs}KFeaHR915oNknFD}{)XtZ z`fTcmewDtjd80mrn^(7bHwtcOsIbn)(I;*FP>+;?@90#@d3{OjoGNfV$jnNC>=tJR zQ%>D{5!Af4YO@`zb&QV&W-DEt(iVFg6~(@vobKE^;?HS(T9H9){9# z%W&5|0-f4PrWt(Vd--jF?hc=JZh7+GYK}^O738Sb`6rg09j0X62@eG1erI>-D!boV zeG7J8FQX%tjp|OqCQm`riC=W|5Tic?JZ)!*L=+0A*eou zv!?1esFIc2jNv?c;t*8=)y5vc-h{vM1zDh{@FCw$$K!`vFrAUJ?vZ{gv%~ExNm8Nz zqj^bJN6*&2Y{$V&S0*uhWh0~tg*qudis<@lULgOE;Z#UJq&`TW$q&jpT*ocbbxc0y ze1vNW7l`ls{prcAPQ?P}_>1nzUk2;^hE&a5g^3pMiKy`kc=MT;JLl3luk9St@)#?A zW{iBNn7uIVI4mC){c7igZU!Cc#O%v=^!p?Y!Y^Gd6lT8vM%i2v6+q0qeR07Af@|a#yTKY3R*>!)c7} z=C?YX{mNV8AF@P)+_22zj|(%2+}$lGo>z##b?Rdn=Ih-1$HNd2ah>6tH7ae>lL5_fYI-4`)udm;~* ztofINxs$}wf-W-X3$o10;*%3SZQ&H!lVd4W@hqHNGC`+QiyN*5E*+&R*UfXWvYBd# zni;HMjJ#jXPi|O--@UXha~MVACe!G=UGs!$NyU&836cK#>vVg1jc0ay|B6L-L&T^Vef_R4{nW5Xm%bJ~ zJJ8#YtTPpT*{Ge=g*9e|@tuvU{BC!*qy#oG?ZCCE(B^H5(bdt_;Plk&iqg^1W!7wcHvfw@))}BYS0o5Ud!KO>5BSyeoH1htz&f! zaQ@k~Iy6#K1ge@jJ4-zr{(&{LPy!j2CftLDaXM7E+@D8$qovez?-X5RhScl!XbS5( zgxABUQgeN9FSj5T!S$9JRVCr3ucByw4!HM?!R8x9X}+yaccSX+TI`BR5w$rG93K7~ zcguU)-Q#qn8?Rwg5R1{{^@R{IddGCgO%cnJxTaKj=-GHF(vy-^;a2rD0dE$2hA_k! zA?g$%1{Py=T`gvzY?`JtsGmfJ=oL#_qp%hBG|G|9o45C3WiOWgQtUe-SN+9EHMn|g3Ov5G4QpS(iT;zG1 z#_PL*|NGyUBpGdd^eoQ6>f*Gd<~)DjaBPBVV+a*8a>b?;l@ixocW2ve!B|JJ5=(sCjTv z>ag7HC!>m{ZRkV zg$S-R!=5i0LeKV9mO1P^SBmi$-~FCY7KSh0jcb2TF9o97B*%yNWyaYH5ANh!_cJ;o(+;$;$OvlkbVYpztzn}4Ya+C^5}ZlgQ_+ z(%6V0n*%Eqg$x+$WPN>QEtp>7q@&xRD+sHPamnJ@Xd&nr;~-$@m-454np?%L!|3D3 zzk420n$UNkOC2Z`*zE-M<-RHW`O9Jdh_5!UJkk*z3SH)vFeqzxuZ^}J`}+u2 zRyXe*YRew|yVRK0t%DVg&Shx^aaeD>=i&xWMZwjRT&%ve;>c!Q9_@SIxRIpbZVRI8 zMk7Vr1S?Th_SiF(gkH0FcTO<3UQm0I@Y)9hH^@_j^y7KPTNX5fD>ZbR0LflZf~0(x z?O9h?iL7-iYp9CvP$FLV2anuj!Qz~5O^_f*x$HetopwansrlEt73rVL6L$_KsXP`Z zmr~Rm^UH^jY?RiMP#RpgWp!8!Jdg&|&=CZOz{|#9u&*f043_&AvZ(FRmSq$X<=VTq zgOl$0*GF&^7oE`@kxxTC2tTDcJRmF9SVTa;M#yLvZ9tC3A+L4h^LZ?tI&lfBQ@D*O z#0xq*{?`%gg_50;SY}L7eP37bk0jdfRgJ0q#yr3Si*$nbulD)yxXL;6htDp(1w}i% zOL1zOgD*h2Q%ar^Ai5ke?H2FlxuLxR$AhlX5kEGhuRMv`WjB5V&3=@uxvag5Lz?a~ z-}8R$oXbV|lx&uBhz{K9NB%kbJGrIK3w35WP-v7%4&uV8DTYr{ctC?{59fs=Q99`o zL#JS)9L7N-}X4~hy?*UfBy{4rvFZ{K6{>Xc5-3pQJ2ZJ(IZm$<1R2|wlP4$rC3WP6jySmaK`ZB4B7ZaxPF^Lbc!xaDlMV>h%GT3|jSi zdgi!QFbkF8HwH5vzgPQFNBQpn`)U*#2~&AN0SUz{>STt+K1v#K>T1gbj^MqvU*=O9 zKhRb!#9#E1%)}!u_jHyx28x%GD5f2cOqnj|&3?M~oA)Csm`-PLDUlF*cim!wcEK5} z7&Pk&4RWyll6q39*-nlD(%@hd8yOYio{SZWiF+<}Apb=b1sUJ*tO^oOno)T`D2TE8 zoeokL&_rR?KPJerGxgp)6u|_oPL#Z0!;lIdj?^_;z}@v;^-n8O))&B3hEcV#p3g^G zP19A3uVD(U3s{LmR?CwGJ_MvYDsx*$6~7ahW!;;?f?$Ig=vg3s7rdH0iIh2*0kJp7 zh-0?NZCgi(iYMREocg1!qji)@@gU8hIt{0^-mp3gc-6^qo!h^_x>~b$##2099A9lc zhK9p>s(r-n(J`x2FBPpp3+%H;($qxL0Q+v1VUM-g`!cUHn}z3Ye{$iKu8xEPD@ul& zjHq{u_g7V4A5K1}18P@&yOLmc|46^ z-5X?3+O^bc_ol)}$uHb};XjvAA|)p>TPj`lRg)O)3pPX z7RXSwy(Q$guPqj)a%#1&m_;}bG*({f;%U)m7NogPNp06G#j*jA3;%Ku~CG|@s zgyE+pc6 zcX?%kdc@@lg}H}0ehAw#(`ICxn^ZFoePgnTiFJ`=M)DnJ&SOR20cVu(0gGRyw~Ofz zh)${mapU{qb^%rR2P($ZM2qEkCv?)&a`)Mi+r|)=oUj^-ZO$*WTeDjnO#${=(@7Xu}16JGHEF8HMJb`a5*!v zvDB2no^fbMD;ksYZBQe+01k_*?T?EKzPLm`_mqBX`j}2vY=oa;n2{0^N;ps0fFU1x zY;cY(P%T&L_~l7LqVs~yRKgE}y;&`#S1eavFZF}_oRcy2iY|F+G2m}qBQFIq1SoE_R8*Y$HMkc zge8Z;31xScVvd#QLx|T$47);A_mi=UqE;qyWciSUt?|itePxMyec|qW#HtlmGSX4( z&Qpy-xmWHYplDstiCJJvSZ`ijpBdJ()Q4NUG>SIeqhnRX91up1jwI#}{ZfQQ`9d^l zI4wl*6*IBfS1)T~QQZg1X)^nNw`$-A+E-zf4<9EaCNA&mKj*fl)ji$@bj{6O@$0_-hzP`gnlUV0 zaDB`9)m60Wkkt2eQEhBcK1aJ1?9B!Cd~sVQ(Q_wx1m@%IAqPC(Ah56aXn z$FE2O=aLnuY;@KxxWDX9uAiQf_nw>MYthEW-Zq*WiArW^KocLdvzk0yerb|6MWXl! z=!az`0q2rY;Oc)9;1Sy=h;v#g>6s01RBk97M(zl8kpl;dFx=I_>fre~t@RZJ{C*~8 z_xUU&;zX>R?8{C&?x4Nfj*+!Wqdnskasn6y0j8W0B%~O(Uis z?FCV{)QRcmg zC2uY)zKgUMCRw`Y|FHO&*BJs0q_1XW_fp6UxVa(HQaN9Nd3+SnQhtDN z7dfT-D?LMqymE(sYG`nZ6Cp{D&A z+zu9WDMNCF`3dxY3;YKddd4It-f|F*t%||8;F%H?(i{|x!Kmf1{^Ad#!4EdC-*F`N z)2{bieMv;UD3xh<=Cq4*@Fc9Drl4@DoCuf1EoJ=ZDA?!~^wPt80znCYPR4zrNI;s! ze5c=btst>2f(vfHkPqNLnKDmLcu(0(D>5H^@V+k&_zqdSBMxz#VyFGx==`9*>Ac1O z5w37PAa{bSxBLtY6jYijGFhj(!<2nmCj6Ae^QU&#M*68l!~94%8I^ZBTdP=qI!r

%ff+)8u7 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 z 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

^yJTP6oc_cjvKX=i z$~g2oxSgXx8RRjJ$st)pE5%fdV>5^kkH6{9^xxjdIIYQHV%yd3ruDU!q<_7BpYZ*h zru|x}B{nn`U&@m@R9Q0=l`TcrPW3f4_?+)s*D<&H_Aq+x+oSY(9%oYG33smnA;gB> zcQTnLo@JpQWxS8_H**qlbm=mTaGXRmR5VCbBSa)Kgd?;f(&Z44izuRf{N)sRwOo7A zqTL#6@)TBji$wUU#8qWtEVOl&nySlQ^jBSVwW_!1^Jq}s)OD6wWtEs=iY&D$rka@3 zQsz!&rf0Iu_L^yjT5al2SY370QB`l2S!H3Yv{jZ>HC0*V*Q0%W%M8}--lu)s(4|hL zcU^pg=UsKS+i}QH?L6y#LruKvjX2|OIL!APcBL8?Yf+_Qy_)tp)N0-$%_g07+El4g zap><*p(*F6E}P6c^RG7RmM^cXS+h^rT<52_>#MIlmRf0+8D*9yu{L`PRbhrK)M}kd z6!EpZuTx9&d)-c_iN)+Xc{tw$M4>{|g$I$1>Rj@HB6@lJ_fNy^XpSl)qKYJ%i;5_s z2quDNx5E#bARW)nqK+*Re7j1$m1@mTRhXr3-dd!YEBlY<#@R*uDn?NZxeAzq zadJvRDck%DnQ2}_4j zN|hw3B=N%qtPoERpHieXA^CM3KW$Q_No2F`aRPa%k}KL{rkZJMSvy;rpFuhKMT4`- z5}sfHIXOK&AVGekDp5jGTccYK1Zn3w?~j+S9Hsinoz+EoK00WBOejV^U(?I98+M01Qw1t}UgRB0b< z^Ht%~uS#82F{w}xK1&s9wE_G75T^&t@;974js@3azh@IWYVYdq`}YdW+3CJ_dv2y; zciZldGPHF{_x8g=(rkZ9hc1t(^3CPg2DK&^pgeU3vZ<9y+LkO7DEXA7guH!jv3m5p zm*0{7yu9?znaYeYWU47&Gcj4QcNmQjVpq8I7U@Mvn%BtBlFL zk&Ht}BLoG&nJAa$pJwt#W=zm|rL0)ttVRKbKZ1pnkQg_n2NIr%B%oPw3WkkBs*+TY zdos1&BDX3z5wh0hyN^9|lE_R-e8B8D%&{DKRgi_p9mjgOcL)t<`o7u5IO#xJ69&3t zI!19-#dNC`Y$kg3m5nNsz-aURYeom&pYzo>{I8w&FSwd&;Z{W+033*NovEw-#8KaA z!%vPHqy_ei1I@+^e#JF=J;Noy+e{M*-j-Q=2~nUNKgl7jD3h+vXCjhW1H9jLPi`#} zN+7s=Ovsd#rXcuaAa!(ny$QED5vy`9x>oxMI5wcf0~%bgWzJVF&T+x}_A!kUT z-Bl@q6;9pUpo~}&g3!m*(!2?$RkFKD3r5^vmmRgL42I zqCoyvO^0sZyup4yx;M6s`?f`-Qt*+tcEd4+g1Y_=gz%8v5at$r0`ueKFclXH#GG{^ z`}_6XA8Yo(eU~;IF&>VLoS-~Qz!F|FJ=nLJuLqkUZj<0R_M)fHDv-0V@~f7+(zG-E zR2t#_?tjm5J82grG6YD*bLd1_uZR{xp9d0`X*)3WRSJ9n^5igGc%cv6_E4nQY2W@ZO^}Wqfv=hSUdr^nFuFk^!p2v&i ztG5Hpv`trBs%`sgLvebk2%#=xG0?AEyupwBlHY??2z0Rsh9MN?&=>5}8IMO`oJ69G zA`o+!_KUdLPr)90@Yvv!5Z1={{V(gvmyfsmvVPZfizlm+JkTi+L8PC+Kpg|EAP~Ty zO+`x4;GlL}{s1M~0Bnjg6ROfXp#Un|qcM0?=vE^=d2-n%`zSQ6>9U~e6FvDH$ zJTb}7a6<4{1IVc?`I6f2<@$_Q0PBoW80oI$vs}yx#LHS-a9O1 zjMG!O<-u0@%RGuEGWdglk51Tx^-5y{|tbn?) zS1fle@D!~DNM&wnGiTP0NxC9wK>ZgT23AhMV?L3YQZtA1ei^U<;{c|lf}4VsB5wmb zM|6TTn9yX4f%xITVN_h^7_5?a<32$a>Kf*8u&=Df`>c0W@0it&G&@+a;QZ2}Uo4}O z*&|EidGlpRt}SRj2f#EDrQpST=XA(Kb#yFGy@rpzR(f)F?i7ES10CkEwEbNM2Um_M zjyYpz?S7z#cIC_r2Wl?_hvxml5;RmO0>vHIaATgex9{d4PFsJeyp{mOEvtJ>9jRbT z;KezjWYb`w3S4{-rHg&P{$idWGuJDtvHp}yJO)Y;i} z*UEk%U2^J&U_U{(hI~o1#>*JTq`x*|EoGPW0;aofK;^v7?*})BlLLDrc}+ym+&<6e z2^*0-z9KfkJ@Sy5-j?}8j~IG;#+a7ZPHW%G>v8V*^FDjQ2IrbEAz2~~0-ljg_6p}t zP#W^5Ft3XROe`2~ad*50QtIVv&t;StKHo%U`F@j)`Cik$G>_=`kz*%%4WA$(Q<&Zw zd&yqAiVAiI6K_Rs7g2Ks5u?gtNl|ExRCvsCl~AfFh6uoSk9LAZ_m^!qiWSZQ5r>W( zk;0n9o$j^x%}(sbDn{3V7&1)PZf-cFs@3CY=0ov%T`MYmd-Rpp18-k?< z?NM%(L!@Yt+8x>;9E-;Mw*%y5m`BrUkWdf#Te|N)D9-Sdcs0XN2K>(q3B0`=|Ha&qP81{*+>j1Hgx6oE diff --git a/worlds/pokemon_rb/basepatch_red.bsdiff4 b/worlds/pokemon_rb/basepatch_red.bsdiff4 index 826b7bf8b4e5ff0dd0926ca876c9930eebe4eefc..4b207108cf0c6f20611233888fc279b9ce44cb93 100644 GIT binary patch literal 47212 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 hHxq+uj|F+OgQN}lYl-uTcBrIq=semM;Zc_jN literal 46344 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 DjU7nf diff --git a/worlds/pokemon_rb/docs/en_Pokemon Red and Blue.md b/worlds/pokemon_rb/docs/en_Pokemon Red and Blue.md index 1e5c14eb..6811b592 100644 --- a/worlds/pokemon_rb/docs/en_Pokemon Red and Blue.md +++ b/worlds/pokemon_rb/docs/en_Pokemon Red and Blue.md @@ -60,11 +60,12 @@ and Safari Zone. Adds 4 extra item locations to Rock Tunnel B1F * Split Card Key: Splits the Card Key into 10 different Card Keys, one for each floor of Silph Co that has locked doors. Adds 9 location checks to friendly NPCs in Silph Co. You can also choose Progressive Card Keys to always obtain the keys in order from Card Key 2F to Card Key 11F. -* Trainersanity: Adds location checks to 317 trainers. Does not include scripted trainers, most of which disappear +* Trainersanity: Adds location checks to trainers. You may choose between 0 and 317 trainersanity checks. Trainers +will be randomly selected to be given checks. Does not include scripted trainers, most of which disappear after battling them, but also includes Gym Leaders. You must talk to the trainer after defeating them to receive -your prize. Adds 317 random filler items to the item pool -* Dexsanity: Location checks occur when registering Pokémon as owned in the Pokédex. You can choose a percentage -of Pokémon to have checks added to, chosen randomly. You can identify which Pokémon have location checks by an empty +your prize. Adds random filler items to the item pool. +* Dexsanity: Location checks occur when registering Pokémon as owned in the Pokédex. You can choose between 0 and 151 +Pokémon to have checks added to, chosen randomly. You can identify which Pokémon have location checks by an empty Poké Ball icon shown in battle or in the Pokédex menu. ## Which items can be in another player's world? diff --git a/worlds/pokemon_rb/encounters.py b/worlds/pokemon_rb/encounters.py index 6d1762b0..fbe4abfe 100644 --- a/worlds/pokemon_rb/encounters.py +++ b/worlds/pokemon_rb/encounters.py @@ -8,7 +8,7 @@ def get_encounter_slots(self): for location in encounter_slots: if isinstance(location.original_item, list): - location.original_item = location.original_item[not self.multiworld.game_version[self.player].value] + location.original_item = location.original_item[not self.options.game_version.value] return encounter_slots @@ -39,16 +39,16 @@ def randomize_pokemon(self, mon, mons_list, randomize_type, random): return mon -def process_trainer_data(self): +def process_trainer_data(world): mons_list = [pokemon for pokemon in poke_data.pokemon_data.keys() if pokemon not in poke_data.legendary_pokemon - or self.multiworld.trainer_legendaries[self.player].value] + or world.options.trainer_legendaries.value] unevolved_mons = [pokemon for pokemon in poke_data.first_stage_pokemon if pokemon not in poke_data.legendary_pokemon - or self.multiworld.randomize_legendary_pokemon[self.player].value == 3] + or world.options.randomize_legendary_pokemon.value == 3] evolved_mons = [mon for mon in mons_list if mon not in unevolved_mons] rival_map = { - "Charmander": self.multiworld.get_location("Oak's Lab - Starter 1", self.player).item.name[9:], # strip the - "Squirtle": self.multiworld.get_location("Oak's Lab - Starter 2", self.player).item.name[9:], # 'Missable' - "Bulbasaur": self.multiworld.get_location("Oak's Lab - Starter 3", self.player).item.name[9:], # from the name + "Charmander": world.multiworld.get_location("Oak's Lab - Starter 1", world.player).item.name[9:], # strip the + "Squirtle": world.multiworld.get_location("Oak's Lab - Starter 2", world.player).item.name[9:], # 'Missable' + "Bulbasaur": world.multiworld.get_location("Oak's Lab - Starter 3", world.player).item.name[9:], # from the name } def add_evolutions(): @@ -60,7 +60,7 @@ def process_trainer_data(self): rival_map[poke_data.evolves_to[a]] = b add_evolutions() add_evolutions() - parties_objs = [location for location in self.multiworld.get_locations(self.player) + parties_objs = [location for location in world.multiworld.get_locations(world.player) if location.type == "Trainer Parties"] # Process Rival parties in order "Route 22 " is not a typo parties_objs.sort(key=lambda i: 0 if "Oak's Lab" in i.name else 1 if "Route 22 " in i.name else 2 if "Cerulean City" @@ -75,25 +75,25 @@ def process_trainer_data(self): for i, mon in enumerate(rival_party): if mon in ("Bulbasaur", "Ivysaur", "Venusaur", "Charmander", "Charmeleon", "Charizard", "Squirtle", "Wartortle", "Blastoise"): - if self.multiworld.randomize_starter_pokemon[self.player]: + if world.options.randomize_starter_pokemon: rival_party[i] = rival_map[mon] - elif self.multiworld.randomize_trainer_parties[self.player]: + elif world.options.randomize_trainer_parties: if mon in rival_map: rival_party[i] = rival_map[mon] else: - new_mon = randomize_pokemon(self, mon, + new_mon = randomize_pokemon(world, mon, unevolved_mons if mon in unevolved_mons else evolved_mons, - self.multiworld.randomize_trainer_parties[self.player].value, - self.multiworld.random) + world.options.randomize_trainer_parties.value, + world.random) rival_map[mon] = new_mon rival_party[i] = new_mon add_evolutions() else: - if self.multiworld.randomize_trainer_parties[self.player]: + if world.options.randomize_trainer_parties: for i, mon in enumerate(party["party"]): - party["party"][i] = randomize_pokemon(self, mon, mons_list, - self.multiworld.randomize_trainer_parties[self.player].value, - self.multiworld.random) + party["party"][i] = randomize_pokemon(world, mon, mons_list, + world.options.randomize_trainer_parties.value, + world.random) def process_pokemon_locations(self): @@ -106,21 +106,21 @@ def process_pokemon_locations(self): placed_mons = {pokemon: 0 for pokemon in poke_data.pokemon_data.keys()} mons_list = [pokemon for pokemon in poke_data.first_stage_pokemon if pokemon not in poke_data.legendary_pokemon - or self.multiworld.randomize_legendary_pokemon[self.player].value == 3] - if self.multiworld.randomize_legendary_pokemon[self.player] == "vanilla": + or self.options.randomize_legendary_pokemon.value == 3] + if self.options.randomize_legendary_pokemon == "vanilla": for slot in legendary_slots: location = self.multiworld.get_location(slot.name, self.player) location.place_locked_item(self.create_item("Static " + slot.original_item)) - elif self.multiworld.randomize_legendary_pokemon[self.player] == "shuffle": - self.multiworld.random.shuffle(legendary_mons) + elif self.options.randomize_legendary_pokemon == "shuffle": + self.random.shuffle(legendary_mons) for slot in legendary_slots: location = self.multiworld.get_location(slot.name, self.player) mon = legendary_mons.pop() location.place_locked_item(self.create_item("Static " + mon)) placed_mons[mon] += 1 - elif self.multiworld.randomize_legendary_pokemon[self.player] == "static": + elif self.options.randomize_legendary_pokemon == "static": static_slots = static_slots + legendary_slots - self.multiworld.random.shuffle(static_slots) + self.random.shuffle(static_slots) static_slots.sort(key=lambda s: s.name != "Pokemon Tower 6F - Restless Soul") while legendary_slots: swap_slot = legendary_slots.pop() @@ -131,12 +131,12 @@ def process_pokemon_locations(self): location = self.multiworld.get_location(slot.name, self.player) location.place_locked_item(self.create_item(slot_type + " " + swap_slot.original_item)) swap_slot.original_item = slot.original_item - elif self.multiworld.randomize_legendary_pokemon[self.player] == "any": + elif self.options.randomize_legendary_pokemon == "any": static_slots = static_slots + legendary_slots for slot in static_slots: location = self.multiworld.get_location(slot.name, self.player) - randomize_type = self.multiworld.randomize_static_pokemon[self.player].value + randomize_type = self.options.randomize_static_pokemon.value slot_type = slot.type.split()[0] if slot_type == "Legendary": slot_type = "Static" @@ -145,7 +145,7 @@ def process_pokemon_locations(self): else: mon = self.create_item(slot_type + " " + randomize_pokemon(self, slot.original_item, mons_list, randomize_type, - self.multiworld.random)) + self.random)) location.place_locked_item(mon) if slot_type != "Missable": placed_mons[mon.name.replace("Static ", "")] += 1 @@ -153,16 +153,16 @@ def process_pokemon_locations(self): chosen_mons = set() for slot in starter_slots: location = self.multiworld.get_location(slot.name, self.player) - randomize_type = self.multiworld.randomize_starter_pokemon[self.player].value + randomize_type = self.options.randomize_starter_pokemon.value slot_type = "Missable" if not randomize_type: location.place_locked_item(self.create_item(slot_type + " " + slot.original_item)) else: mon = self.create_item(slot_type + " " + randomize_pokemon(self, slot.original_item, mons_list, - randomize_type, self.multiworld.random)) + randomize_type, self.random)) while mon.name in chosen_mons: mon = self.create_item(slot_type + " " + randomize_pokemon(self, slot.original_item, mons_list, - randomize_type, self.multiworld.random)) + randomize_type, self.random)) chosen_mons.add(mon.name) location.place_locked_item(mon) @@ -170,10 +170,10 @@ def process_pokemon_locations(self): encounter_slots = encounter_slots_master.copy() zone_mapping = {} - if self.multiworld.randomize_wild_pokemon[self.player]: + if self.options.randomize_wild_pokemon: mons_list = [pokemon for pokemon in poke_data.pokemon_data.keys() if pokemon not in poke_data.legendary_pokemon - or self.multiworld.randomize_legendary_pokemon[self.player].value == 3] - self.multiworld.random.shuffle(encounter_slots) + or self.options.randomize_legendary_pokemon.value == 3] + self.random.shuffle(encounter_slots) locations = [] for slot in encounter_slots: location = self.multiworld.get_location(slot.name, self.player) @@ -181,11 +181,11 @@ def process_pokemon_locations(self): if zone not in zone_mapping: zone_mapping[zone] = {} original_mon = slot.original_item - if self.multiworld.area_1_to_1_mapping[self.player] and original_mon in zone_mapping[zone]: + if self.options.area_1_to_1_mapping and original_mon in zone_mapping[zone]: mon = zone_mapping[zone][original_mon] else: mon = randomize_pokemon(self, original_mon, mons_list, - self.multiworld.randomize_wild_pokemon[self.player].value, self.multiworld.random) + self.options.randomize_wild_pokemon.value, self.random) # while ("Pokemon Tower 6F" in slot.name and self.multiworld.get_location("Pokemon Tower 6F - Restless Soul", self.player).item.name @@ -194,7 +194,7 @@ def process_pokemon_locations(self): # the battle is treates as the Restless Soul battle and you cannot catch it. So, prevent any wild mons # from being the same species as the Restless Soul. # to account for the possibility that only one ground type Pokemon exists, match only stats for this fix - mon = randomize_pokemon(self, original_mon, mons_list, 2, self.multiworld.random) + mon = randomize_pokemon(self, original_mon, mons_list, 2, self.random) placed_mons[mon] += 1 location.item = self.create_item(mon) location.locked = True @@ -204,28 +204,28 @@ def process_pokemon_locations(self): mons_to_add = [] remaining_pokemon = [pokemon for pokemon in poke_data.pokemon_data.keys() if placed_mons[pokemon] == 0 and - (pokemon not in poke_data.legendary_pokemon or self.multiworld.randomize_legendary_pokemon[self.player].value == 3)] - if self.multiworld.catch_em_all[self.player] == "first_stage": + (pokemon not in poke_data.legendary_pokemon or self.options.randomize_legendary_pokemon.value == 3)] + if self.options.catch_em_all == "first_stage": mons_to_add = [pokemon for pokemon in poke_data.first_stage_pokemon if placed_mons[pokemon] == 0 and - (pokemon not in poke_data.legendary_pokemon or self.multiworld.randomize_legendary_pokemon[self.player].value == 3)] - elif self.multiworld.catch_em_all[self.player] == "all_pokemon": + (pokemon not in poke_data.legendary_pokemon or self.options.randomize_legendary_pokemon.value == 3)] + elif self.options.catch_em_all == "all_pokemon": mons_to_add = remaining_pokemon.copy() - logic_needed_mons = max(self.multiworld.oaks_aide_rt_2[self.player].value, - self.multiworld.oaks_aide_rt_11[self.player].value, - self.multiworld.oaks_aide_rt_15[self.player].value) - if self.multiworld.accessibility[self.player] == "minimal": + logic_needed_mons = max(self.options.oaks_aide_rt_2.value, + self.options.oaks_aide_rt_11.value, + self.options.oaks_aide_rt_15.value) + if self.options.accessibility == "minimal": logic_needed_mons = 0 - self.multiworld.random.shuffle(remaining_pokemon) + self.random.shuffle(remaining_pokemon) while (len([pokemon for pokemon in placed_mons if placed_mons[pokemon] > 0]) + len(mons_to_add) < logic_needed_mons): mons_to_add.append(remaining_pokemon.pop()) for mon in mons_to_add: stat_base = get_base_stat_total(mon) candidate_locations = encounter_slots_master.copy() - if self.multiworld.randomize_wild_pokemon[self.player].current_key in ["match_base_stats", "match_types_and_base_stats"]: + if self.options.randomize_wild_pokemon.current_key in ["match_base_stats", "match_types_and_base_stats"]: candidate_locations.sort(key=lambda slot: abs(get_base_stat_total(slot.original_item) - stat_base)) - if self.multiworld.randomize_wild_pokemon[self.player].current_key in ["match_types", "match_types_and_base_stats"]: + if self.options.randomize_wild_pokemon.current_key in ["match_types", "match_types_and_base_stats"]: candidate_locations.sort(key=lambda slot: not any([poke_data.pokemon_data[slot.original_item]["type1"] in [self.local_poke_data[mon]["type1"], self.local_poke_data[mon]["type2"]], poke_data.pokemon_data[slot.original_item]["type2"] in @@ -233,12 +233,12 @@ def process_pokemon_locations(self): candidate_locations = [self.multiworld.get_location(location.name, self.player) for location in candidate_locations] for location in candidate_locations: zone = " - ".join(location.name.split(" - ")[:-1]) - if self.multiworld.catch_em_all[self.player] == "all_pokemon" and self.multiworld.area_1_to_1_mapping[self.player]: + if self.options.catch_em_all == "all_pokemon" and self.options.area_1_to_1_mapping: if not [self.multiworld.get_location(l.name, self.player) for l in encounter_slots_master if (not l.name.startswith(zone)) and self.multiworld.get_location(l.name, self.player).item.name == location.item.name]: continue - if self.multiworld.catch_em_all[self.player] == "first_stage" and self.multiworld.area_1_to_1_mapping[self.player]: + if self.options.catch_em_all == "first_stage" and self.options.area_1_to_1_mapping: if not [self.multiworld.get_location(l.name, self.player) for l in encounter_slots_master if (not l.name.startswith(zone)) and self.multiworld.get_location(l.name, self.player).item.name == location.item.name and l.name @@ -246,10 +246,10 @@ def process_pokemon_locations(self): continue if placed_mons[location.item.name] < 2 and (location.item.name in poke_data.first_stage_pokemon - or self.multiworld.catch_em_all[self.player]): + or self.options.catch_em_all): continue - if self.multiworld.area_1_to_1_mapping[self.player]: + if self.options.area_1_to_1_mapping: place_locations = [place_location for place_location in candidate_locations if place_location.name.startswith(zone) and place_location.item.name == location.item.name] diff --git a/worlds/pokemon_rb/items.py b/worlds/pokemon_rb/items.py index de29f341..fb439c4f 100644 --- a/worlds/pokemon_rb/items.py +++ b/worlds/pokemon_rb/items.py @@ -194,6 +194,8 @@ item_table = { "Fuji Saved": ItemData(None, ItemClassification.progression, []), "Silph Co Liberated": ItemData(None, ItemClassification.progression, []), "Become Champion": ItemData(None, ItemClassification.progression, []), + "Mt Moon Fossils": ItemData(None, ItemClassification.progression, []), + "Cinnabar Lab": ItemData(None, ItemClassification.progression, []), "Trainer Parties": ItemData(None, ItemClassification.filler, []) } diff --git a/worlds/pokemon_rb/level_scaling.py b/worlds/pokemon_rb/level_scaling.py index 79cda394..76e00d98 100644 --- a/worlds/pokemon_rb/level_scaling.py +++ b/worlds/pokemon_rb/level_scaling.py @@ -10,9 +10,9 @@ def level_scaling(multiworld): while locations: sphere = set() for world in multiworld.get_game_worlds("Pokemon Red and Blue"): - if (multiworld.level_scaling[world.player] != "by_spheres_and_distance" - and (multiworld.level_scaling[world.player] != "auto" or multiworld.door_shuffle[world.player] - in ("off", "simple"))): + if (world.options.level_scaling != "by_spheres_and_distance" + and (world.options.level_scaling != "auto" + or world.options.door_shuffle in ("off", "simple"))): continue regions = {multiworld.get_region("Menu", world.player)} checked_regions = set() @@ -41,7 +41,8 @@ def level_scaling(multiworld): # reach them earlier. We treat them both as reachable right away for this purpose return True if (location.name == "Route 25 - Item" and state.can_reach("Route 25", "Region", location.player) - and multiworld.blind_trainers[location.player].value < 100): + and multiworld.worlds[location.player].options.blind_trainers.value < 100 + and "Route 25 - Jr. Trainer M" not in multiworld.regions.location_cache[location.player]): # Assume they will take their one chance to get the trainer to walk out of the way to reach # the item behind them return True @@ -95,9 +96,9 @@ def level_scaling(multiworld): if (location.item.game == "Pokemon Red and Blue" and (location.item.name.startswith("Missable ") or location.item.name.startswith("Static ")) and location.name != "Pokemon Tower 6F - Restless Soul"): - # Normally, missable Pokemon (starters, the dojo rewards) are not considered in logic static Pokemon - # are not considered for moves or evolutions, as you could release them and potentially soft lock - # the game. However, for level scaling purposes, we will treat them as not missable or static. + # Normally, missable Pokemon (starters, the dojo rewards) are not considered in logic, and static + # Pokemon are not considered for moves or evolutions, as you could release them and potentially soft + # lock the game. However, for level scaling purposes, we will treat them as not missable or static. # We would not want someone playing a minimal accessibility Dexsanity game to get what would be # technically an "out of logic" Mansion Key from selecting Bulbasaur at the beginning of the game # and end up in the Mansion early and encountering level 67 Pokémon @@ -106,7 +107,7 @@ def level_scaling(multiworld): else: state.collect(location.item, True, location) for world in multiworld.get_game_worlds("Pokemon Red and Blue"): - if multiworld.level_scaling[world.player] == "off": + if world.options.level_scaling == "off": continue level_list_copy = level_list.copy() for sphere in spheres: @@ -136,4 +137,4 @@ def level_scaling(multiworld): else: sphere_objects[object].level = level_list_copy.pop(0) for world in multiworld.get_game_worlds("Pokemon Red and Blue"): - world.finished_level_scaling.set() + world.finished_level_scaling.set() \ No newline at end of file diff --git a/worlds/pokemon_rb/locations.py b/worlds/pokemon_rb/locations.py index 6aee25df..5885183b 100644 --- a/worlds/pokemon_rb/locations.py +++ b/worlds/pokemon_rb/locations.py @@ -5,46 +5,48 @@ from . import poke_data loc_id_start = 172000000 -def trainersanity(multiworld, player): - return multiworld.trainersanity[player] - - -def dexsanity(multiworld, player): - include = multiworld.worlds[player].dexsanity_table.pop(0) - multiworld.worlds[player].dexsanity_table.append(include) +def trainersanity(world, player): + include = world.trainersanity_table.pop(0) + world.trainersanity_table.append(include) return include -def hidden_items(multiworld, player): - return multiworld.randomize_hidden_items[player] +def dexsanity(world, player): + include = world.dexsanity_table.pop(0) + world.dexsanity_table.append(include) + return include -def hidden_moon_stones(multiworld, player): - return multiworld.randomize_hidden_items[player] or multiworld.stonesanity[player] +def hidden_items(world, player): + return world.options.randomize_hidden_items -def tea(multiworld, player): - return multiworld.tea[player] +def hidden_moon_stones(world, player): + return world.options.randomize_hidden_items or world.options.stonesanity -def extra_key_items(multiworld, player): - return multiworld.extra_key_items[player] +def tea(world, player): + return world.options.tea -def always_on(multiworld, player): +def extra_key_items(world, player): + return world.options.extra_key_items + + +def always_on(world, player): return True -def prizesanity(multiworld, player): - return multiworld.prizesanity[player] +def prizesanity(world, player): + return world.options.prizesanity -def split_card_key(multiworld, player): - return multiworld.split_card_key[player].value > 0 +def split_card_key(world, player): + return world.options.split_card_key.value > 0 -def not_stonesanity(multiworld, player): - return not multiworld.stonesanity[player] +def not_stonesanity(world, player): + return not world.options.stonesanity class LocationData: @@ -395,7 +397,7 @@ location_data = [ LocationData("Silph Co 5F", "Hidden Item Pot Plant", "Elixir", rom_addresses['Hidden_Item_Silph_Co_5F'], Hidden(18), inclusion=hidden_items), LocationData("Silph Co 9F-SW", "Hidden Item Nurse Bed", "Max Potion", rom_addresses['Hidden_Item_Silph_Co_9F'], Hidden(19), inclusion=hidden_items), LocationData("Saffron Copycat's House 2F", "Hidden Item Desk", "Nugget", rom_addresses['Hidden_Item_Copycats_House'], Hidden(20), inclusion=hidden_items), - LocationData("Cerulean Cave 1F-NW", "Hidden Item Center Rocks", "Rare Candy", rom_addresses['Hidden_Item_Cerulean_Cave_1F'], Hidden(21), inclusion=hidden_items), + LocationData("Cerulean Cave 1F-SW", "Hidden Item Center Rocks", "Rare Candy", rom_addresses['Hidden_Item_Cerulean_Cave_1F'], Hidden(21), inclusion=hidden_items), LocationData("Cerulean Cave B1F-E", "Hidden Item Northeast Rocks", "Ultra Ball", rom_addresses['Hidden_Item_Cerulean_Cave_B1F'], Hidden(22), inclusion=hidden_items), LocationData("Power Plant", "Hidden Item Central Dead End", "Max Elixir", rom_addresses['Hidden_Item_Power_Plant_1'], Hidden(23), inclusion=hidden_items), LocationData("Power Plant", "Hidden Item Before Zapdos", "PP Up", rom_addresses['Hidden_Item_Power_Plant_2'], Hidden(24), inclusion=hidden_items), @@ -786,6 +788,8 @@ location_data = [ LocationData("Celadon Game Corner", "", "Game Corner", event=True), LocationData("Cinnabar Island", "", "Cinnabar Island", event=True), + LocationData("Cinnabar Lab", "", "Cinnabar Lab", event=True), + LocationData("Mt Moon B2F", "Mt Moon Fossils", "Mt Moon Fossils", event=True), LocationData("Celadon Department Store 4F", "Buy Poke Doll", "Buy Poke Doll", event=True), LocationData("Celadon Department Store 4F", "Buy Fire Stone", "Fire Stone", event=True, inclusion=not_stonesanity), LocationData("Celadon Department Store 4F", "Buy Water Stone", "Water Stone", event=True, inclusion=not_stonesanity), diff --git a/worlds/pokemon_rb/logic.py b/worlds/pokemon_rb/logic.py index cbe28e0d..03e3fa3d 100644 --- a/worlds/pokemon_rb/logic.py +++ b/worlds/pokemon_rb/logic.py @@ -1,49 +1,47 @@ from . import poke_data -def can_surf(state, player): - return (((state.has("HM03 Surf", player) and can_learn_hm(state, "Surf", player)) - or state.has("Flippers", player)) and (state.has("Soul Badge", player) or - state.has(state.multiworld.worlds[player].extra_badges.get("Surf"), player) - or state.multiworld.badges_needed_for_hm_moves[player].value == 0)) +def can_surf(state, world, player): + return (((state.has("HM03 Surf", player) and can_learn_hm(state, world, "Surf", player))) and (state.has("Soul Badge", player) or + state.has(world.extra_badges.get("Surf"), player) + or world.options.badges_needed_for_hm_moves.value == 0)) -def can_cut(state, player): - return ((state.has("HM01 Cut", player) and can_learn_hm(state, "Cut", player) or state.has("Master Sword", player)) - and (state.has("Cascade Badge", player) or - state.has(state.multiworld.worlds[player].extra_badges.get("Cut"), player) or - state.multiworld.badges_needed_for_hm_moves[player].value == 0)) +def can_cut(state, world, player): + return ((state.has("HM01 Cut", player) and can_learn_hm(state, world, "Cut", player)) + and (state.has("Cascade Badge", player) or state.has(world.extra_badges.get("Cut"), player) or + world.options.badges_needed_for_hm_moves.value == 0)) -def can_fly(state, player): - return (((state.has("HM02 Fly", player) and can_learn_hm(state, "Fly", player)) or state.has("Flute", player)) and - (state.has("Thunder Badge", player) or state.has(state.multiworld.worlds[player].extra_badges.get("Fly"), player) - or state.multiworld.badges_needed_for_hm_moves[player].value == 0)) +def can_fly(state, world, player): + return (((state.has("HM02 Fly", player) and can_learn_hm(state, world, "Fly", player)) or state.has("Flute", player)) and + (state.has("Thunder Badge", player) or state.has(world.extra_badges.get("Fly"), player) + or world.options.badges_needed_for_hm_moves.value == 0)) -def can_strength(state, player): - return ((state.has("HM04 Strength", player) and can_learn_hm(state, "Strength", player)) or +def can_strength(state, world, player): + return ((state.has("HM04 Strength", player) and can_learn_hm(state, world, "Strength", player)) or state.has("Titan's Mitt", player)) and (state.has("Rainbow Badge", player) or - state.has(state.multiworld.worlds[player].extra_badges.get("Strength"), player) - or state.multiworld.badges_needed_for_hm_moves[player].value == 0) + state.has(world.extra_badges.get("Strength"), player) + or world.options.badges_needed_for_hm_moves.value == 0) -def can_flash(state, player): - return (((state.has("HM05 Flash", player) and can_learn_hm(state, "Flash", player)) or state.has("Lamp", player)) - and (state.has("Boulder Badge", player) or state.has(state.multiworld.worlds[player].extra_badges.get("Flash"), - player) or state.multiworld.badges_needed_for_hm_moves[player].value == 0)) +def can_flash(state, world, player): + return (((state.has("HM05 Flash", player) and can_learn_hm(state, world, "Flash", player)) or state.has("Lamp", player)) + and (state.has("Boulder Badge", player) or state.has(world.extra_badges.get("Flash"), + player) or world.options.badges_needed_for_hm_moves.value == 0)) -def can_learn_hm(state, move, player): - for pokemon, data in state.multiworld.worlds[player].local_poke_data.items(): +def can_learn_hm(state, world, move, player): + for pokemon, data in world.local_poke_data.items(): if state.has(pokemon, player) and data["tms"][6] & 1 << (["Cut", "Fly", "Surf", "Strength", "Flash"].index(move) + 2): return True return False -def can_get_hidden_items(state, player): - return state.has("Item Finder", player) or not state.multiworld.require_item_finder[player].value +def can_get_hidden_items(state, world, player): + return state.has("Item Finder", player) or not world.options.require_item_finder.value def has_key_items(state, count, player): @@ -53,13 +51,14 @@ def has_key_items(state, count, player): "Hideout Key", "Card Key 2F", "Card Key 3F", "Card Key 4F", "Card Key 5F", "Card Key 6F", "Card Key 7F", "Card Key 8F", "Card Key 9F", "Card Key 10F", "Card Key 11F", "Exp. All", "Fire Stone", "Thunder Stone", "Water Stone", - "Leaf Stone", "Moon Stone"] if state.has(item, player)]) + "Leaf Stone", "Moon Stone", "Oak's Parcel", "Helix Fossil", "Dome Fossil", + "Old Amber", "Tea", "Gold Teeth", "Bike Voucher"] if state.has(item, player)]) + min(state.count("Progressive Card Key", player), 10)) return key_items >= count -def can_pass_guards(state, player): - if state.multiworld.tea[player]: +def can_pass_guards(state, world, player): + if world.options.tea: return state.has("Tea", player) else: return state.has("Vending Machine Drinks", player) @@ -70,8 +69,8 @@ def has_badges(state, count, player): "Soul Badge", "Volcano Badge", "Earth Badge"] if state.has(item, player)]) >= count -def oaks_aide(state, count, player): - return ((not state.multiworld.require_pokedex[player] or state.has("Pokedex", player)) +def oaks_aide(state, world, count, player): + return ((not world.options.require_pokedex or state.has("Pokedex", player)) and has_pokemon(state, count, player)) @@ -85,9 +84,7 @@ def has_pokemon(state, count, player): def fossil_checks(state, count, player): - return (state.can_reach('Mt Moon B2F', 'Region', player) and - state.can_reach('Cinnabar Lab Fossil Room', 'Region', player) and - state.can_reach('Cinnabar Island', 'Region', player) and len( + return (state.has_all(["Mt Moon Fossils", "Cinnabar Lab", "Cinnabar Island"], player) and len( [item for item in ["Dome Fossil", "Helix Fossil", "Old Amber"] if state.has(item, player)]) >= count) @@ -96,19 +93,19 @@ def card_key(state, floor, player): state.has("Progressive Card Key", player, floor - 1) -def rock_tunnel(state, player): - return can_flash(state, player) or not state.multiworld.dark_rock_tunnel_logic[player] +def rock_tunnel(state, world, player): + return can_flash(state, world, player) or not world.options.dark_rock_tunnel_logic -def route_3(state, player): - if state.multiworld.route_3_condition[player] == "defeat_brock": +def route(state, world, player): + if world.options.route_3_condition == "defeat_brock": return state.has("Defeat Brock", player) - elif state.multiworld.route_3_condition[player] == "defeat_any_gym": + elif world.options.route_3_condition == "defeat_any_gym": return state.has_any(["Defeat Brock", "Defeat Misty", "Defeat Lt. Surge", "Defeat Erika", "Defeat Koga", "Defeat Blaine", "Defeat Sabrina", "Defeat Viridian Gym Giovanni"], player) - elif state.multiworld.route_3_condition[player] == "boulder_badge": + elif world.options.route_3_condition == "boulder_badge": return state.has("Boulder Badge", player) - elif state.multiworld.route_3_condition[player] == "any_badge": + elif world.options.route_3_condition == "any_badge": return state.has_any(["Boulder Badge", "Cascade Badge", "Thunder Badge", "Rainbow Badge", "Marsh Badge", "Soul Badge", "Volcano Badge", "Earth Badge"], player) # open diff --git a/worlds/pokemon_rb/options.py b/worlds/pokemon_rb/options.py index 9f217e82..21679bec 100644 --- a/worlds/pokemon_rb/options.py +++ b/worlds/pokemon_rb/options.py @@ -1,4 +1,6 @@ -from Options import Toggle, Choice, Range, NamedRange, TextChoice, DeathLink, ItemsAccessibility +from dataclasses import dataclass +from Options import (PerGameCommonOptions, Toggle, Choice, Range, NamedRange, FreeText, TextChoice, DeathLink, + ItemsAccessibility) class GameVersion(Choice): @@ -263,12 +265,18 @@ class PrizeSanity(Toggle): default = 0 -class TrainerSanity(Toggle): - """Add a location check to every trainer in the game, which can be obtained by talking to a trainer after defeating - them. Does not affect gym leaders and some scripted event battles (including all Rival, Giovanni, and - Cinnabar Gym battles).""" +class TrainerSanity(NamedRange): + """Add location checks to trainers, which can be obtained by talking to a trainer after defeating them. Does not + affect gym leaders and some scripted event battles. You may specify a number of trainers to have checks, and in + this case they will be randomly selected. There is no in-game indication as to which trainers have checks.""" display_name = "Trainersanity" default = 0 + range_start = 0 + range_end = 317 + special_range_names = { + "disabled": 0, + "full": 317 + } class RequirePokedex(Toggle): @@ -286,19 +294,19 @@ class AllPokemonSeen(Toggle): class DexSanity(NamedRange): - """Adds location checks for Pokemon flagged "owned" on your Pokedex. You may specify a percentage of Pokemon to - have checks added. If Accessibility is set to full, this will be the percentage of all logically reachable - Pokemon that will get a location check added to it. With items or minimal Accessibility, it will be the percentage - of all 151 Pokemon. - If Pokedex is required, the items for Pokemon acquired before acquiring the Pokedex can be found by talking to - Professor Oak or evaluating the Pokedex via Oak's PC.""" + """Adds location checks for Pokemon flagged "owned" on your Pokedex. You may specify the exact number of Dexsanity + checks to add, and they will be distributed to Pokemon randomly. + If Accessibility is set to Full, Dexsanity checks for Pokemon that are not logically reachable will be removed, + so the number could be lower than you specified. + If Pokedex is required, the Dexsanity checks for Pokemon you acquired before acquiring the Pokedex can be found by + talking to Professor Oak or evaluating the Pokedex via Oak's PC.""" display_name = "Dexsanity" default = 0 range_start = 0 - range_end = 100 + range_end = 151 special_range_names = { "disabled": 0, - "full": 100 + "full": 151 } @@ -519,7 +527,8 @@ class TrainerLegendaries(Toggle): class BlindTrainers(Range): """Chance each frame that you are standing on a tile in a trainer's line of sight that they will fail to initiate a - battle. If you move into and out of their line of sight without stopping, this chance will only trigger once.""" + battle. If you move into and out of their line of sight without stopping, this chance will only trigger once. + Trainers which have Trainersanity location checks ignore the Blind Trainers setting.""" display_name = "Blind Trainers" range_start = 0 range_end = 100 @@ -704,6 +713,15 @@ class RandomizeTypeChart(Choice): default = 0 +class TypeChartSeed(FreeText): + """You can enter a number to use as a seed for the type chart. If you enter anything besides a number or "random", + it will be used as a type chart group name, and everyone using the same group name will get the same type chart, + made using the type chart options of one random player within the group. If a group name is used, the type matchup + information will not be made available for trackers.""" + display_name = "Type Chart Seed" + default = "random" + + class NormalMatchups(Range): """If 'randomize' is chosen for Randomize Type Chart, this will be the weight for neutral matchups. No effect if 'chaos' is chosen""" @@ -850,8 +868,8 @@ class BicycleGateSkips(Choice): class RandomizePokemonPalettes(Choice): - """Modify palettes of Pokemon. Primary Type will set Pokemons' palettes based on their primary type, Follow - Evolutions will randomize palettes but palettes will remain the same through evolutions (except Eeveelutions), + """Modify Super Gameboy palettes of Pokemon. Primary Type will set Pokemons' palettes based on their primary type, + Follow Evolutions will randomize palettes but they will remain the same through evolutions (except Eeveelutions), Completely Random will randomize all Pokemons' palettes individually""" display_name = "Randomize Pokemon Palettes" option_vanilla = 0 @@ -860,104 +878,105 @@ class RandomizePokemonPalettes(Choice): option_completely_random = 3 -pokemon_rb_options = { - "accessibility": ItemsAccessibility, - "game_version": GameVersion, - "trainer_name": TrainerName, - "rival_name": RivalName, - #"goal": Goal, - "elite_four_badges_condition": EliteFourBadgesCondition, - "elite_four_key_items_condition": EliteFourKeyItemsCondition, - "elite_four_pokedex_condition": EliteFourPokedexCondition, - "victory_road_condition": VictoryRoadCondition, - "route_22_gate_condition": Route22GateCondition, - "viridian_gym_condition": ViridianGymCondition, - "cerulean_cave_badges_condition": CeruleanCaveBadgesCondition, - "cerulean_cave_key_items_condition": CeruleanCaveKeyItemsCondition, - "route_3_condition": Route3Condition, - "robbed_house_officer": RobbedHouseOfficer, - "second_fossil_check_condition": SecondFossilCheckCondition, - "fossil_check_item_types": FossilCheckItemTypes, - "exp_all": ExpAll, - "old_man": OldMan, - "badgesanity": BadgeSanity, - "badges_needed_for_hm_moves": BadgesNeededForHMMoves, - "key_items_only": KeyItemsOnly, - "tea": Tea, - "extra_key_items": ExtraKeyItems, - "split_card_key": SplitCardKey, - "all_elevators_locked": AllElevatorsLocked, - "extra_strength_boulders": ExtraStrengthBoulders, - "require_item_finder": RequireItemFinder, - "randomize_hidden_items": RandomizeHiddenItems, - "prizesanity": PrizeSanity, - "trainersanity": TrainerSanity, - "dexsanity": DexSanity, - "randomize_pokedex": RandomizePokedex, - "require_pokedex": RequirePokedex, - "all_pokemon_seen": AllPokemonSeen, - "oaks_aide_rt_2": OaksAidRt2, - "oaks_aide_rt_11": OaksAidRt11, - "oaks_aide_rt_15": OaksAidRt15, - "stonesanity": Stonesanity, - "door_shuffle": DoorShuffle, - "warp_tile_shuffle": WarpTileShuffle, - "randomize_rock_tunnel": RandomizeRockTunnel, - "dark_rock_tunnel_logic": DarkRockTunnelLogic, - "free_fly_location": FreeFlyLocation, - "town_map_fly_location": TownMapFlyLocation, - "blind_trainers": BlindTrainers, - "minimum_steps_between_encounters": MinimumStepsBetweenEncounters, - "level_scaling": LevelScaling, - "exp_modifier": ExpModifier, - "randomize_wild_pokemon": RandomizeWildPokemon, - "area_1_to_1_mapping": Area1To1Mapping, - "randomize_starter_pokemon": RandomizeStarterPokemon, - "randomize_static_pokemon": RandomizeStaticPokemon, - "randomize_legendary_pokemon": RandomizeLegendaryPokemon, - "catch_em_all": CatchEmAll, - "randomize_pokemon_stats": RandomizePokemonStats, - "randomize_pokemon_catch_rates": RandomizePokemonCatchRates, - "minimum_catch_rate": MinimumCatchRate, - "randomize_trainer_parties": RandomizeTrainerParties, - "trainer_legendaries": TrainerLegendaries, - "move_balancing": MoveBalancing, - "fix_combat_bugs": FixCombatBugs, - "randomize_pokemon_movesets": RandomizePokemonMovesets, - "confine_transform_to_ditto": ConfineTranstormToDitto, - "start_with_four_moves": StartWithFourMoves, - "same_type_attack_bonus": SameTypeAttackBonus, - "randomize_tm_moves": RandomizeTMMoves, - "tm_same_type_compatibility": TMSameTypeCompatibility, - "tm_normal_type_compatibility": TMNormalTypeCompatibility, - "tm_other_type_compatibility": TMOtherTypeCompatibility, - "hm_same_type_compatibility": HMSameTypeCompatibility, - "hm_normal_type_compatibility": HMNormalTypeCompatibility, - "hm_other_type_compatibility": HMOtherTypeCompatibility, - "inherit_tm_hm_compatibility": InheritTMHMCompatibility, - "randomize_move_types": RandomizeMoveTypes, - "randomize_pokemon_types": RandomizePokemonTypes, - "secondary_type_chance": SecondaryTypeChance, - "randomize_type_chart": RandomizeTypeChart, - "normal_matchups": NormalMatchups, - "super_effective_matchups": SuperEffectiveMatchups, - "not_very_effective_matchups": NotVeryEffectiveMatchups, - "immunity_matchups": ImmunityMatchups, - "safari_zone_normal_battles": SafariZoneNormalBattles, - "normalize_encounter_chances": NormalizeEncounterChances, - "reusable_tms": ReusableTMs, - "better_shops": BetterShops, - "master_ball_price": MasterBallPrice, - "starting_money": StartingMoney, - "lose_money_on_blackout": LoseMoneyOnBlackout, - "poke_doll_skip": PokeDollSkip, - "bicycle_gate_skips": BicycleGateSkips, - "trap_percentage": TrapPercentage, - "poison_trap_weight": PoisonTrapWeight, - "fire_trap_weight": FireTrapWeight, - "paralyze_trap_weight": ParalyzeTrapWeight, - "sleep_trap_weight": SleepTrapWeight, - "ice_trap_weight": IceTrapWeight, - "randomize_pokemon_palettes": RandomizePokemonPalettes, - "death_link": DeathLink -} +@dataclass +class PokemonRBOptions(PerGameCommonOptions): + accessibility: ItemsAccessibility + game_version: GameVersion + trainer_name: TrainerName + rival_name: RivalName + # goal: Goal + elite_four_badges_condition: EliteFourBadgesCondition + elite_four_key_items_condition: EliteFourKeyItemsCondition + elite_four_pokedex_condition: EliteFourPokedexCondition + victory_road_condition: VictoryRoadCondition + route_22_gate_condition: Route22GateCondition + viridian_gym_condition: ViridianGymCondition + cerulean_cave_badges_condition: CeruleanCaveBadgesCondition + cerulean_cave_key_items_condition: CeruleanCaveKeyItemsCondition + route_3_condition: Route3Condition + robbed_house_officer: RobbedHouseOfficer + second_fossil_check_condition: SecondFossilCheckCondition + fossil_check_item_types: FossilCheckItemTypes + exp_all: ExpAll + old_man: OldMan + badgesanity: BadgeSanity + badges_needed_for_hm_moves: BadgesNeededForHMMoves + key_items_only: KeyItemsOnly + tea: Tea + extra_key_items: ExtraKeyItems + split_card_key: SplitCardKey + all_elevators_locked: AllElevatorsLocked + extra_strength_boulders: ExtraStrengthBoulders + require_item_finder: RequireItemFinder + randomize_hidden_items: RandomizeHiddenItems + prizesanity: PrizeSanity + trainersanity: TrainerSanity + dexsanity: DexSanity + randomize_pokedex: RandomizePokedex + require_pokedex: RequirePokedex + all_pokemon_seen: AllPokemonSeen + oaks_aide_rt_2: OaksAidRt2 + oaks_aide_rt_11: OaksAidRt11 + oaks_aide_rt_15: OaksAidRt15 + stonesanity: Stonesanity + door_shuffle: DoorShuffle + warp_tile_shuffle: WarpTileShuffle + randomize_rock_tunnel: RandomizeRockTunnel + dark_rock_tunnel_logic: DarkRockTunnelLogic + free_fly_location: FreeFlyLocation + town_map_fly_location: TownMapFlyLocation + blind_trainers: BlindTrainers + minimum_steps_between_encounters: MinimumStepsBetweenEncounters + level_scaling: LevelScaling + exp_modifier: ExpModifier + randomize_wild_pokemon: RandomizeWildPokemon + area_1_to_1_mapping: Area1To1Mapping + randomize_starter_pokemon: RandomizeStarterPokemon + randomize_static_pokemon: RandomizeStaticPokemon + randomize_legendary_pokemon: RandomizeLegendaryPokemon + catch_em_all: CatchEmAll + randomize_pokemon_stats: RandomizePokemonStats + randomize_pokemon_catch_rates: RandomizePokemonCatchRates + minimum_catch_rate: MinimumCatchRate + randomize_trainer_parties: RandomizeTrainerParties + trainer_legendaries: TrainerLegendaries + move_balancing: MoveBalancing + fix_combat_bugs: FixCombatBugs + randomize_pokemon_movesets: RandomizePokemonMovesets + confine_transform_to_ditto: ConfineTranstormToDitto + start_with_four_moves: StartWithFourMoves + same_type_attack_bonus: SameTypeAttackBonus + randomize_tm_moves: RandomizeTMMoves + tm_same_type_compatibility: TMSameTypeCompatibility + tm_normal_type_compatibility: TMNormalTypeCompatibility + tm_other_type_compatibility: TMOtherTypeCompatibility + hm_same_type_compatibility: HMSameTypeCompatibility + hm_normal_type_compatibility: HMNormalTypeCompatibility + hm_other_type_compatibility: HMOtherTypeCompatibility + inherit_tm_hm_compatibility: InheritTMHMCompatibility + randomize_move_types: RandomizeMoveTypes + randomize_pokemon_types: RandomizePokemonTypes + secondary_type_chance: SecondaryTypeChance + randomize_type_chart: RandomizeTypeChart + normal_matchups: NormalMatchups + super_effective_matchups: SuperEffectiveMatchups + not_very_effective_matchups: NotVeryEffectiveMatchups + immunity_matchups: ImmunityMatchups + type_chart_seed: TypeChartSeed + safari_zone_normal_battles: SafariZoneNormalBattles + normalize_encounter_chances: NormalizeEncounterChances + reusable_tms: ReusableTMs + better_shops: BetterShops + master_ball_price: MasterBallPrice + starting_money: StartingMoney + lose_money_on_blackout: LoseMoneyOnBlackout + poke_doll_skip: PokeDollSkip + bicycle_gate_skips: BicycleGateSkips + trap_percentage: TrapPercentage + poison_trap_weight: PoisonTrapWeight + fire_trap_weight: FireTrapWeight + paralyze_trap_weight: ParalyzeTrapWeight + sleep_trap_weight: SleepTrapWeight + ice_trap_weight: IceTrapWeight + randomize_pokemon_palettes: RandomizePokemonPalettes + death_link: DeathLink diff --git a/worlds/pokemon_rb/pokemon.py b/worlds/pokemon_rb/pokemon.py index 28098a2c..32c0e368 100644 --- a/worlds/pokemon_rb/pokemon.py +++ b/worlds/pokemon_rb/pokemon.py @@ -3,8 +3,8 @@ from . import poke_data, logic from .rom_addresses import rom_addresses -def set_mon_palettes(self, random, data): - if self.multiworld.randomize_pokemon_palettes[self.player] == "vanilla": +def set_mon_palettes(world, random, data): + if world.options.randomize_pokemon_palettes == "vanilla": return pallet_map = { "Poison": 0x0F, @@ -25,9 +25,9 @@ def set_mon_palettes(self, random, data): } palettes = [] for mon in poke_data.pokemon_data: - if self.multiworld.randomize_pokemon_palettes[self.player] == "primary_type": - pallet = pallet_map[self.local_poke_data[mon]["type1"]] - elif (self.multiworld.randomize_pokemon_palettes[self.player] == "follow_evolutions" and mon in + if world.options.randomize_pokemon_palettes == "primary_type": + pallet = pallet_map[world.local_poke_data[mon]["type1"]] + elif (world.options.randomize_pokemon_palettes == "follow_evolutions" and mon in poke_data.evolves_from and poke_data.evolves_from[mon] != "Eevee"): pallet = palettes[-1] else: # completely_random or follow_evolutions and it is not an evolved form (except eeveelutions) @@ -93,40 +93,41 @@ def move_power(move_data): return power -def process_move_data(self): - self.local_move_data = deepcopy(poke_data.moves) +def process_move_data(world): + world.local_move_data = deepcopy(poke_data.moves) - if self.multiworld.randomize_move_types[self.player]: - for move, data in self.local_move_data.items(): + if world.options.randomize_move_types: + for move, data in world.local_move_data.items(): if move == "No Move": continue # The chance of randomized moves choosing a normal type move is high, so we want to retain having a higher # rate of normal type moves - data["type"] = self.multiworld.random.choice(list(poke_data.type_ids) + (["Normal"] * 4)) + data["type"] = world.random.choice(list(poke_data.type_ids) + (["Normal"] * 4)) - if self.multiworld.move_balancing[self.player]: - self.local_move_data["Sing"]["accuracy"] = 30 - self.local_move_data["Sleep Powder"]["accuracy"] = 40 - self.local_move_data["Spore"]["accuracy"] = 50 - self.local_move_data["Sonicboom"]["effect"] = 0 - self.local_move_data["Sonicboom"]["power"] = 50 - self.local_move_data["Dragon Rage"]["effect"] = 0 - self.local_move_data["Dragon Rage"]["power"] = 80 - self.local_move_data["Horn Drill"]["effect"] = 0 - self.local_move_data["Horn Drill"]["power"] = 70 - self.local_move_data["Horn Drill"]["accuracy"] = 90 - self.local_move_data["Guillotine"]["effect"] = 0 - self.local_move_data["Guillotine"]["power"] = 70 - self.local_move_data["Guillotine"]["accuracy"] = 90 - self.local_move_data["Fissure"]["effect"] = 0 - self.local_move_data["Fissure"]["power"] = 70 - self.local_move_data["Fissure"]["accuracy"] = 90 - self.local_move_data["Blizzard"]["accuracy"] = 70 - if self.multiworld.randomize_tm_moves[self.player]: - self.local_tms = self.multiworld.random.sample([move for move in poke_data.moves.keys() if move not in - ["No Move"] + poke_data.hm_moves], 50) + if world.options.move_balancing: + world.local_move_data["Sing"]["accuracy"] = 30 + world.local_move_data["Sleep Powder"]["accuracy"] = 40 + world.local_move_data["Spore"]["accuracy"] = 50 + world.local_move_data["Sonicboom"]["effect"] = 0 + world.local_move_data["Sonicboom"]["power"] = 50 + world.local_move_data["Dragon Rage"]["effect"] = 0 + world.local_move_data["Dragon Rage"]["power"] = 80 + world.local_move_data["Horn Drill"]["effect"] = 0 + world.local_move_data["Horn Drill"]["power"] = 70 + world.local_move_data["Horn Drill"]["accuracy"] = 90 + world.local_move_data["Guillotine"]["effect"] = 0 + world.local_move_data["Guillotine"]["power"] = 70 + world.local_move_data["Guillotine"]["accuracy"] = 90 + world.local_move_data["Fissure"]["effect"] = 0 + world.local_move_data["Fissure"]["power"] = 70 + world.local_move_data["Fissure"]["accuracy"] = 90 + world.local_move_data["Blizzard"]["accuracy"] = 70 + + if world.options.randomize_tm_moves: + world.local_tms = world.random.sample([move for move in poke_data.moves.keys() if move not in + ["No Move"] + poke_data.hm_moves], 50) else: - self.local_tms = poke_data.tm_moves.copy() + world.local_tms = poke_data.tm_moves.copy() def process_pokemon_data(self): @@ -138,12 +139,12 @@ def process_pokemon_data(self): compat_hms = set() for mon, mon_data in local_poke_data.items(): - if self.multiworld.randomize_pokemon_stats[self.player] == "shuffle": + if self.options.randomize_pokemon_stats == "shuffle": stats = [mon_data["hp"], mon_data["atk"], mon_data["def"], mon_data["spd"], mon_data["spc"]] if mon in poke_data.evolves_from: stat_shuffle_map = local_poke_data[poke_data.evolves_from[mon]]["stat_shuffle_map"] else: - stat_shuffle_map = self.multiworld.random.sample(range(0, 5), 5) + stat_shuffle_map = self.random.sample(range(0, 5), 5) mon_data["stat_shuffle_map"] = stat_shuffle_map mon_data["hp"] = stats[stat_shuffle_map[0]] @@ -151,7 +152,7 @@ def process_pokemon_data(self): mon_data["def"] = stats[stat_shuffle_map[2]] mon_data["spd"] = stats[stat_shuffle_map[3]] mon_data["spc"] = stats[stat_shuffle_map[4]] - elif self.multiworld.randomize_pokemon_stats[self.player] == "randomize": + elif self.options.randomize_pokemon_stats == "randomize": first_run = True while (mon_data["hp"] > 255 or mon_data["atk"] > 255 or mon_data["def"] > 255 or mon_data["spd"] > 255 or mon_data["spc"] > 255 or first_run): @@ -168,9 +169,9 @@ def process_pokemon_data(self): mon_data[stat] = 10 total_stats -= 10 assert total_stats >= 0, f"Error distributing stats for {mon} for player {self.player}" - dist = [self.multiworld.random.randint(1, 101) / 100, self.multiworld.random.randint(1, 101) / 100, - self.multiworld.random.randint(1, 101) / 100, self.multiworld.random.randint(1, 101) / 100, - self.multiworld.random.randint(1, 101) / 100] + dist = [self.random.randint(1, 101) / 100, self.random.randint(1, 101) / 100, + self.random.randint(1, 101) / 100, self.random.randint(1, 101) / 100, + self.random.randint(1, 101) / 100] total_dist = sum(dist) mon_data["hp"] += int(round(dist[0] / total_dist * total_stats)) @@ -178,30 +179,30 @@ def process_pokemon_data(self): mon_data["def"] += int(round(dist[2] / total_dist * total_stats)) mon_data["spd"] += int(round(dist[3] / total_dist * total_stats)) mon_data["spc"] += int(round(dist[4] / total_dist * total_stats)) - if self.multiworld.randomize_pokemon_types[self.player]: - if self.multiworld.randomize_pokemon_types[self.player].value == 1 and mon in poke_data.evolves_from: + if self.options.randomize_pokemon_types: + if self.options.randomize_pokemon_types.value == 1 and mon in poke_data.evolves_from: type1 = local_poke_data[poke_data.evolves_from[mon]]["type1"] type2 = local_poke_data[poke_data.evolves_from[mon]]["type2"] if type1 == type2: - if self.multiworld.secondary_type_chance[self.player].value == -1: + if self.options.secondary_type_chance.value == -1: if mon_data["type1"] != mon_data["type2"]: while type2 == type1: - type2 = self.multiworld.random.choice(list(poke_data.type_names.values())) - elif self.multiworld.random.randint(1, 100) <= self.multiworld.secondary_type_chance[self.player].value: - type2 = self.multiworld.random.choice(list(poke_data.type_names.values())) + type2 = self.random.choice(list(poke_data.type_names.values())) + elif self.random.randint(1, 100) <= self.options.secondary_type_chance.value: + type2 = self.random.choice(list(poke_data.type_names.values())) else: - type1 = self.multiworld.random.choice(list(poke_data.type_names.values())) + type1 = self.random.choice(list(poke_data.type_names.values())) type2 = type1 - if ((self.multiworld.secondary_type_chance[self.player].value == -1 and mon_data["type1"] - != mon_data["type2"]) or self.multiworld.random.randint(1, 100) - <= self.multiworld.secondary_type_chance[self.player].value): + if ((self.options.secondary_type_chance.value == -1 and mon_data["type1"] + != mon_data["type2"]) or self.random.randint(1, 100) + <= self.options.secondary_type_chance.value): while type2 == type1: - type2 = self.multiworld.random.choice(list(poke_data.type_names.values())) + type2 = self.random.choice(list(poke_data.type_names.values())) mon_data["type1"] = type1 mon_data["type2"] = type2 - if self.multiworld.randomize_pokemon_movesets[self.player]: - if self.multiworld.randomize_pokemon_movesets[self.player] == "prefer_types": + if self.options.randomize_pokemon_movesets: + if self.options.randomize_pokemon_movesets == "prefer_types": if mon_data["type1"] == "Normal" and mon_data["type2"] == "Normal": chances = [[75, "Normal"]] elif mon_data["type1"] == "Normal" or mon_data["type2"] == "Normal": @@ -219,9 +220,9 @@ def process_pokemon_data(self): moves = list(poke_data.moves.keys()) for move in ["No Move"] + poke_data.hm_moves: moves.remove(move) - if self.multiworld.confine_transform_to_ditto[self.player]: + if self.options.confine_transform_to_ditto: moves.remove("Transform") - if self.multiworld.start_with_four_moves[self.player]: + if self.options.start_with_four_moves: num_moves = 4 else: num_moves = len([i for i in [mon_data["start move 1"], mon_data["start move 2"], @@ -231,12 +232,12 @@ def process_pokemon_data(self): non_power_moves = [] learnsets[mon] = [] for i in range(num_moves): - if i == 0 and mon == "Ditto" and self.multiworld.confine_transform_to_ditto[self.player]: + if i == 0 and mon == "Ditto" and self.options.confine_transform_to_ditto: move = "Transform" else: - move = get_move(self.local_move_data, moves, chances, self.multiworld.random) - while move == "Transform" and self.multiworld.confine_transform_to_ditto[self.player]: - move = get_move(self.local_move_data, moves, chances, self.multiworld.random) + move = get_move(self.local_move_data, moves, chances, self.random) + while move == "Transform" and self.options.confine_transform_to_ditto: + move = get_move(self.local_move_data, moves, chances, self.random) if self.local_move_data[move]["power"] < 5: non_power_moves.append(move) else: @@ -244,59 +245,58 @@ def process_pokemon_data(self): learnsets[mon].sort(key=lambda move: move_power(self.local_move_data[move])) if learnsets[mon]: for move in non_power_moves: - learnsets[mon].insert(self.multiworld.random.randint(1, len(learnsets[mon])), move) + learnsets[mon].insert(self.random.randint(1, len(learnsets[mon])), move) else: learnsets[mon] = non_power_moves for i in range(1, 5): - if mon_data[f"start move {i}"] != "No Move" or self.multiworld.start_with_four_moves[self.player]: + if mon_data[f"start move {i}"] != "No Move" or self.options.start_with_four_moves: mon_data[f"start move {i}"] = learnsets[mon].pop(0) - if self.multiworld.randomize_pokemon_catch_rates[self.player]: - mon_data["catch rate"] = self.multiworld.random.randint(self.multiworld.minimum_catch_rate[self.player], - 255) + if self.options.randomize_pokemon_catch_rates: + mon_data["catch rate"] = self.random.randint(self.options.minimum_catch_rate, 255) else: - mon_data["catch rate"] = max(self.multiworld.minimum_catch_rate[self.player], mon_data["catch rate"]) + mon_data["catch rate"] = max(self.options.minimum_catch_rate, mon_data["catch rate"]) def roll_tm_compat(roll_move): if self.local_move_data[roll_move]["type"] in [mon_data["type1"], mon_data["type2"]]: if roll_move in poke_data.hm_moves: - if self.multiworld.hm_same_type_compatibility[self.player].value == -1: + if self.options.hm_same_type_compatibility.value == -1: return mon_data["tms"][int(flag / 8)] & 1 << (flag % 8) - r = self.multiworld.random.randint(1, 100) <= self.multiworld.hm_same_type_compatibility[self.player].value + r = self.random.randint(1, 100) <= self.options.hm_same_type_compatibility.value if r and mon not in poke_data.legendary_pokemon: compat_hms.add(roll_move) return r else: - if self.multiworld.tm_same_type_compatibility[self.player].value == -1: + if self.options.tm_same_type_compatibility.value == -1: return mon_data["tms"][int(flag / 8)] & 1 << (flag % 8) - return self.multiworld.random.randint(1, 100) <= self.multiworld.tm_same_type_compatibility[self.player].value + return self.random.randint(1, 100) <= self.options.tm_same_type_compatibility.value elif self.local_move_data[roll_move]["type"] == "Normal" and "Normal" not in [mon_data["type1"], mon_data["type2"]]: if roll_move in poke_data.hm_moves: - if self.multiworld.hm_normal_type_compatibility[self.player].value == -1: + if self.options.hm_normal_type_compatibility.value == -1: return mon_data["tms"][int(flag / 8)] & 1 << (flag % 8) - r = self.multiworld.random.randint(1, 100) <= self.multiworld.hm_normal_type_compatibility[self.player].value + r = self.random.randint(1, 100) <= self.options.hm_normal_type_compatibility.value if r and mon not in poke_data.legendary_pokemon: compat_hms.add(roll_move) return r else: - if self.multiworld.tm_normal_type_compatibility[self.player].value == -1: + if self.options.tm_normal_type_compatibility.value == -1: return mon_data["tms"][int(flag / 8)] & 1 << (flag % 8) - return self.multiworld.random.randint(1, 100) <= self.multiworld.tm_normal_type_compatibility[self.player].value + return self.random.randint(1, 100) <= self.options.tm_normal_type_compatibility.value else: if roll_move in poke_data.hm_moves: - if self.multiworld.hm_other_type_compatibility[self.player].value == -1: + if self.options.hm_other_type_compatibility.value == -1: return mon_data["tms"][int(flag / 8)] & 1 << (flag % 8) - r = self.multiworld.random.randint(1, 100) <= self.multiworld.hm_other_type_compatibility[self.player].value + r = self.random.randint(1, 100) <= self.options.hm_other_type_compatibility.value if r and mon not in poke_data.legendary_pokemon: compat_hms.add(roll_move) return r else: - if self.multiworld.tm_other_type_compatibility[self.player].value == -1: + if self.options.tm_other_type_compatibility.value == -1: return mon_data["tms"][int(flag / 8)] & 1 << (flag % 8) - return self.multiworld.random.randint(1, 100) <= self.multiworld.tm_other_type_compatibility[self.player].value + return self.random.randint(1, 100) <= self.options.tm_other_type_compatibility.value for flag, tm_move in enumerate(tms_hms): - if mon in poke_data.evolves_from and self.multiworld.inherit_tm_hm_compatibility[self.player]: + if mon in poke_data.evolves_from and self.options.inherit_tm_hm_compatibility: if local_poke_data[poke_data.evolves_from[mon]]["tms"][int(flag / 8)] & 1 << (flag % 8): # always inherit learnable tms/hms @@ -310,7 +310,7 @@ def process_pokemon_data(self): # so this gets full chance roll bit = roll_tm_compat(tm_move) # otherwise 50% reduced chance to add compatibility over pre-evolved form - elif self.multiworld.random.randint(1, 100) > 50 and roll_tm_compat(tm_move): + elif self.random.randint(1, 100) > 50 and roll_tm_compat(tm_move): bit = 1 else: bit = 0 @@ -322,15 +322,13 @@ def process_pokemon_data(self): mon_data["tms"][int(flag / 8)] &= ~(1 << (flag % 8)) hm_verify = ["Surf", "Strength"] - if self.multiworld.accessibility[self.player] != "minimal" or ((not - self.multiworld.badgesanity[self.player]) and max(self.multiworld.elite_four_badges_condition[self.player], - self.multiworld.route_22_gate_condition[self.player], self.multiworld.victory_road_condition[self.player]) - > 7) or (self.multiworld.door_shuffle[self.player] not in ("off", "simple")): + if self.options.accessibility != "minimal" or ((not + self.options.badgesanity) and max(self.options.elite_four_badges_condition, + self.options.route_22_gate_condition, self.options.victory_road_condition) + > 7) or (self.options.door_shuffle not in ("off", "simple")): hm_verify += ["Cut"] - if self.multiworld.accessibility[self.player] != "minimal" or (not - self.multiworld.dark_rock_tunnel_logic[self.player]) and ((self.multiworld.trainersanity[self.player] or - self.multiworld.extra_key_items[self.player]) - or self.multiworld.door_shuffle[self.player]): + if (self.options.accessibility != "minimal" or (not self.options.dark_rock_tunnel_logic) and + ((self.options.trainersanity or self.options.extra_key_items) or self.options.door_shuffle)): hm_verify += ["Flash"] # Fly does not need to be verified. Full/Insanity/Decoupled door shuffle connects reachable regions to unreachable # regions, so if Fly is available and can be learned, the towns you can fly to would be considered reachable for @@ -339,8 +337,7 @@ def process_pokemon_data(self): for hm_move in hm_verify: if hm_move not in compat_hms: - mon = self.multiworld.random.choice([mon for mon in poke_data.pokemon_data if mon not in - poke_data.legendary_pokemon]) + mon = self.random.choice([mon for mon in poke_data.pokemon_data if mon not in poke_data.legendary_pokemon]) flag = tms_hms.index(hm_move) local_poke_data[mon]["tms"][int(flag / 8)] |= 1 << (flag % 8) @@ -352,7 +349,7 @@ def verify_hm_moves(multiworld, world, player): def intervene(move, test_state): move_bit = pow(2, poke_data.hm_moves.index(move) + 2) viable_mons = [mon for mon in world.local_poke_data if world.local_poke_data[mon]["tms"][6] & move_bit] - if multiworld.randomize_wild_pokemon[player] and viable_mons: + if world.options.randomize_wild_pokemon and viable_mons: accessible_slots = [loc for loc in multiworld.get_reachable_locations(test_state, player) if loc.type == "Wild Encounter"] @@ -364,7 +361,7 @@ def verify_hm_moves(multiworld, world, player): placed_mons = [slot.item.name for slot in accessible_slots] - if multiworld.area_1_to_1_mapping[player]: + if world.options.area_1_to_1_mapping: placed_mons.sort(key=lambda i: number_of_zones(i)) else: # this sort method doesn't work if you reference the same list being sorted in the lambda @@ -372,10 +369,10 @@ def verify_hm_moves(multiworld, world, player): placed_mons.sort(key=lambda i: placed_mons_copy.count(i)) placed_mon = placed_mons.pop() - replace_mon = multiworld.random.choice(viable_mons) - replace_slot = multiworld.random.choice([slot for slot in accessible_slots if slot.item.name + replace_mon = world.random.choice(viable_mons) + replace_slot = world.random.choice([slot for slot in accessible_slots if slot.item.name == placed_mon]) - if multiworld.area_1_to_1_mapping[player]: + if world.options.area_1_to_1_mapping: zone = " - ".join(replace_slot.name.split(" - ")[:-1]) replace_slots = [slot for slot in accessible_slots if slot.name.startswith(zone) and slot.item.name == placed_mon] @@ -387,7 +384,7 @@ def verify_hm_moves(multiworld, world, player): tms_hms = world.local_tms + poke_data.hm_moves flag = tms_hms.index(move) mon_list = [mon for mon in poke_data.pokemon_data.keys() if test_state.has(mon, player)] - multiworld.random.shuffle(mon_list) + world.random.shuffle(mon_list) mon_list.sort(key=lambda mon: world.local_move_data[move]["type"] not in [world.local_poke_data[mon]["type1"], world.local_poke_data[mon]["type2"]]) for mon in mon_list: @@ -399,31 +396,31 @@ def verify_hm_moves(multiworld, world, player): while True: intervene_move = None test_state = multiworld.get_all_state(False) - if not logic.can_learn_hm(test_state, "Surf", player): + if not logic.can_learn_hm(test_state, world, "Surf", player): intervene_move = "Surf" - elif not logic.can_learn_hm(test_state, "Strength", player): + elif not logic.can_learn_hm(test_state, world, "Strength", player): intervene_move = "Strength" # cut may not be needed if accessibility is minimal, unless you need all 8 badges and badgesanity is off, # as you will require cut to access celadon gyn - elif ((not logic.can_learn_hm(test_state, "Cut", player)) and - (multiworld.accessibility[player] != "minimal" or ((not - multiworld.badgesanity[player]) and max( - multiworld.elite_four_badges_condition[player], - multiworld.route_22_gate_condition[player], - multiworld.victory_road_condition[player]) - > 7) or (multiworld.door_shuffle[player] not in ("off", "simple")))): + elif ((not logic.can_learn_hm(test_state, world, "Cut", player)) and + (world.options.accessibility != "minimal" or ((not + world.options.badgesanity) and max( + world.options.elite_four_badges_condition, + world.options.route_22_gate_condition, + world.options.victory_road_condition) + > 7) or (world.options.door_shuffle not in ("off", "simple")))): intervene_move = "Cut" - elif ((not logic.can_learn_hm(test_state, "Flash", player)) - and multiworld.dark_rock_tunnel_logic[player] - and (multiworld.accessibility[player] != "minimal" - or multiworld.door_shuffle[player])): + elif ((not logic.can_learn_hm(test_state, world, "Flash", player)) + and world.options.dark_rock_tunnel_logic + and (world.options.accessibility != "minimal" + or world.options.door_shuffle)): intervene_move = "Flash" # If no Pokémon can learn Fly, then during door shuffle it would simply not treat the free fly maps # as reachable, and if on no door shuffle or simple, fly is simply never necessary. # We only intervene if a Pokémon is able to learn fly but none are reachable, as that would have been # considered in door shuffle. - elif ((not logic.can_learn_hm(test_state, "Fly", player)) - and multiworld.door_shuffle[player] not in + elif ((not logic.can_learn_hm(test_state, world, "Fly", player)) + and world.options.door_shuffle not in ("off", "simple") and [world.fly_map, world.town_map_fly_map] != ["Pallet Town", "Pallet Town"]): intervene_move = "Fly" if intervene_move: @@ -432,4 +429,4 @@ def verify_hm_moves(multiworld, world, player): intervene(intervene_move, test_state) last_intervene = intervene_move else: - break \ No newline at end of file + break diff --git a/worlds/pokemon_rb/regions.py b/worlds/pokemon_rb/regions.py index 938c39b3..575f4a61 100644 --- a/worlds/pokemon_rb/regions.py +++ b/worlds/pokemon_rb/regions.py @@ -1409,21 +1409,20 @@ connecting_interior_entrances = [ ['Route 2-E to Route 2 Gate', 'Route 2-SE to Route 2 Gate'], ['Cerulean City-Badge House Backyard to Cerulean Badge House', 'Cerulean City to Cerulean Badge House'], - ['Cerulean City-T to Cerulean Trashed House', - 'Cerulean City-Outskirts to Cerulean Trashed House'], - ['Fuchsia City to Fuchsia Good Rod House', - 'Fuchsia City-Good Rod House Backyard to Fuchsia Good Rod House'], - ['Route 11-E to Route 11 Gate 1F', 'Route 11-C to Route 11 Gate 1F'], - ['Route 12-N to Route 12 Gate 1F', 'Route 12-L to Route 12 Gate 1F'], - ['Route 15 to Route 15 Gate 1F', 'Route 15-W to Route 15 Gate 1F'], - ['Route 16-NE to Route 16 Gate 1F-N', 'Route 16-NW to Route 16 Gate 1F-N'], + ['Cerulean City-Outskirts to Cerulean Trashed House', + 'Cerulean City-T to Cerulean Trashed House',], + ['Fuchsia City-Good Rod House Backyard to Fuchsia Good Rod House', 'Fuchsia City to Fuchsia Good Rod House'], + ['Route 11-C to Route 11 Gate 1F', 'Route 11-E to Route 11 Gate 1F'], + ['Route 12-L to Route 12 Gate 1F', 'Route 12-N to Route 12 Gate 1F'], + ['Route 15-W to Route 15 Gate 1F', 'Route 15 to Route 15 Gate 1F'], + ['Route 16-NW to Route 16 Gate 1F-N', 'Route 16-NE to Route 16 Gate 1F-N'], ['Route 16-SW to Route 16 Gate 1F-W', 'Route 16-C to Route 16 Gate 1F-E'], ['Route 18-W to Route 18 Gate 1F-W', 'Route 18-E to Route 18 Gate 1F-E'], ['Route 5 to Route 5 Gate-N', 'Route 5-S to Route 5 Gate-S'], - ['Route 6 to Route 6 Gate-S', 'Route 6-N to Route 6 Gate-N'], + ['Route 6-N to Route 6 Gate-N', 'Route 6 to Route 6 Gate-S'], ['Route 7 to Route 7 Gate-W', 'Route 7-E to Route 7 Gate-E'], - ['Route 8 to Route 8 Gate-E', 'Route 8-W to Route 8 Gate-W'], - ['Route 22 to Route 22 Gate-S', 'Route 23-S to Route 22 Gate-N'] + ['Route 8-W to Route 8 Gate-W', 'Route 8 to Route 8 Gate-E',], + ['Route 23-S to Route 22 Gate-N', 'Route 22 to Route 22 Gate-S'] ] dungeons = [ @@ -1484,7 +1483,7 @@ def create_region(multiworld: MultiWorld, player: int, name: str, locations_per_ for location in locations_per_region.get(name, []): location.parent_region = ret ret.locations.append(location) - if multiworld.randomize_hidden_items[player] == "exclude" and "Hidden" in location.name: + if multiworld.worlds[player].options.randomize_hidden_items == "exclude" and "Hidden" in location.name: location.progress_type = LocationProgressType.EXCLUDED if exits: for exit in exits: @@ -1500,32 +1499,34 @@ def outdoor_map(name): return False -def create_regions(self): - multiworld = self.multiworld - player = self.player +def create_regions(world): + multiworld = world.multiworld + player = world.player locations_per_region = {} - start_inventory = self.multiworld.start_inventory[self.player].value.copy() - if self.multiworld.randomize_pokedex[self.player] == "start_with": + start_inventory = world.options.start_inventory.value.copy() + if world.options.randomize_pokedex == "start_with": start_inventory["Pokedex"] = 1 - self.multiworld.push_precollected(self.create_item("Pokedex")) - if self.multiworld.exp_all[self.player] == "start_with": + world.multiworld.push_precollected(world.create_item("Pokedex")) + if world.options.exp_all == "start_with": start_inventory["Exp. All"] = 1 - self.multiworld.push_precollected(self.create_item("Exp. All")) + world.multiworld.push_precollected(world.create_item("Exp. All")) + + world.item_pool = [] + combined_traps = (world.options.poison_trap_weight.value + + world.options.fire_trap_weight.value + + world.options.paralyze_trap_weight.value + + world.options.ice_trap_weight.value + + world.options.sleep_trap_weight.value) - self.item_pool = [] - combined_traps = (self.multiworld.poison_trap_weight[self.player].value - + self.multiworld.fire_trap_weight[self.player].value - + self.multiworld.paralyze_trap_weight[self.player].value - + self.multiworld.ice_trap_weight[self.player].value) stones = ["Moon Stone", "Fire Stone", "Water Stone", "Thunder Stone", "Leaf Stone"] for location in location_data: locations_per_region.setdefault(location.region, []) # The check for list is so that we don't try to check the item table with a list as a key - if location.inclusion(multiworld, player) and (isinstance(location.original_item, list) or - not (self.multiworld.key_items_only[self.player] and item_table[location.original_item].classification - not in (ItemClassification.progression, ItemClassification.progression_skip_balancing) and not + if location.inclusion(world, player) and (isinstance(location.original_item, list) or + not (world.options.key_items_only and item_table[location.original_item].classification + not in (ItemClassification.progression, ItemClassification.progression_skip_balancing) and not location.event)): location_object = PokemonRBLocation(player, location.name, location.address, location.rom_address, location.type, location.level, location.level_address) @@ -1535,51 +1536,53 @@ def create_regions(self): event = location.event if location.original_item is None: - item = self.create_filler() - elif location.original_item == "Exp. All" and self.multiworld.exp_all[self.player] == "remove": - item = self.create_filler() + item = world.create_filler() + elif location.original_item == "Exp. All" and world.options.exp_all == "remove": + item = world.create_filler() elif location.original_item == "Pokedex": - if self.multiworld.randomize_pokedex[self.player] == "vanilla": + if world.options.randomize_pokedex == "vanilla": + location_object.event = True event = True - item = self.create_item("Pokedex") - elif location.original_item == "Moon Stone" and self.multiworld.stonesanity[self.player]: + item = world.create_item("Pokedex") + elif location.original_item == "Moon Stone" and world.options.stonesanity: stone = stones.pop() - item = self.create_item(stone) + item = world.create_item(stone) elif location.original_item.startswith("TM"): - if self.multiworld.randomize_tm_moves[self.player]: - item = self.create_item(location.original_item.split(" ")[0]) + if world.options.randomize_tm_moves: + item = world.create_item(location.original_item.split(" ")[0]) else: - item = self.create_item(location.original_item) - elif location.original_item == "Card Key" and self.multiworld.split_card_key[self.player] == "on": - item = self.create_item("Card Key 3F") - elif "Card Key" in location.original_item and self.multiworld.split_card_key[self.player] == "progressive": - item = self.create_item("Progressive Card Key") + item = world.create_item(location.original_item) + elif location.original_item == "Card Key" and world.options.split_card_key == "on": + item = world.create_item("Card Key 3F") + elif "Card Key" in location.original_item and world.options.split_card_key == "progressive": + item = world.create_item("Progressive Card Key") else: - item = self.create_item(location.original_item) - if (item.classification == ItemClassification.filler and self.multiworld.random.randint(1, 100) - <= self.multiworld.trap_percentage[self.player].value and combined_traps != 0): - item = self.create_item(self.select_trap()) + item = world.create_item(location.original_item) + if (item.classification == ItemClassification.filler and world.random.randint(1, 100) + <= world.options.trap_percentage.value and combined_traps != 0): + item = world.create_item(world.select_trap()) - if self.multiworld.key_items_only[self.player] and (not location.event) and (not item.advancement) and location.original_item != "Exp. All": + if (world.options.key_items_only and (location.original_item != "Exp. All") + and not (location.event or item.advancement)): continue if item.name in start_inventory and start_inventory[item.name] > 0 and \ location.original_item in item_groups["Unique"]: start_inventory[location.original_item] -= 1 - item = self.create_filler() + item = world.create_filler() if event: location_object.place_locked_item(item) if location.type == "Trainer Parties": location_object.party_data = deepcopy(location.party_data) else: - self.item_pool.append(item) + world.item_pool.append(item) - self.multiworld.random.shuffle(self.item_pool) - advancement_items = [item.name for item in self.item_pool if item.advancement] \ - + [item.name for item in self.multiworld.precollected_items[self.player] if + world.random.shuffle(world.item_pool) + advancement_items = [item.name for item in world.item_pool if item.advancement] \ + + [item.name for item in world.multiworld.precollected_items[world.player] if item.advancement] - self.total_key_items = len( + world.total_key_items = len( # The stonesanity items are not checked for here and instead just always added as the `+ 4` # They will always exist, but if stonesanity is off, then only as events. # We don't want to just add 4 if stonesanity is off while still putting them in this list in case @@ -1589,15 +1592,16 @@ def create_regions(self): "Secret Key", "Poke Flute", "Mansion Key", "Safari Pass", "Plant Key", "Hideout Key", "Card Key 2F", "Card Key 3F", "Card Key 4F", "Card Key 5F", "Card Key 6F", "Card Key 7F", "Card Key 8F", "Card Key 9F", "Card Key 10F", - "Card Key 11F", "Exp. All", "Moon Stone"] if item in advancement_items]) + 4 + "Card Key 11F", "Exp. All", "Moon Stone", "Oak's Parcel", "Helix Fossil", "Dome Fossil", + "Old Amber", "Tea", "Gold Teeth", "Bike Voucher"] if item in advancement_items]) + 4 if "Progressive Card Key" in advancement_items: - self.total_key_items += 10 + world.total_key_items += 10 - self.multiworld.cerulean_cave_key_items_condition[self.player].total = \ - int((self.total_key_items / 100) * self.multiworld.cerulean_cave_key_items_condition[self.player].value) + world.options.cerulean_cave_key_items_condition.total = \ + int((world.total_key_items / 100) * world.options.cerulean_cave_key_items_condition.value) - self.multiworld.elite_four_key_items_condition[self.player].total = \ - int((self.total_key_items / 100) * self.multiworld.elite_four_key_items_condition[self.player].value) + world.options.elite_four_key_items_condition.total = \ + int((world.total_key_items / 100) * world.options.elite_four_key_items_condition.value) regions = [create_region(multiworld, player, region, locations_per_region) for region in warp_data] multiworld.regions += regions @@ -1609,7 +1613,7 @@ def create_regions(self): connect(multiworld, player, "Menu", "Pokedex", one_way=True) connect(multiworld, player, "Menu", "Evolution", one_way=True) connect(multiworld, player, "Menu", "Fossil", lambda state: logic.fossil_checks(state, - state.multiworld.second_fossil_check_condition[player].value, player), one_way=True) + world.options.second_fossil_check_condition.value, player), one_way=True) connect(multiworld, player, "Pallet Town", "Route 1") connect(multiworld, player, "Route 1", "Viridian City") connect(multiworld, player, "Viridian City", "Route 22") @@ -1617,24 +1621,24 @@ def create_regions(self): connect(multiworld, player, "Route 2-SW", "Route 2-Grass", one_way=True) connect(multiworld, player, "Route 2-NW", "Route 2-Grass", one_way=True) connect(multiworld, player, "Route 22 Gate-S", "Route 22 Gate-N", - lambda state: logic.has_badges(state, state.multiworld.route_22_gate_condition[player].value, player)) - connect(multiworld, player, "Route 23-Grass", "Route 23-C", lambda state: logic.has_badges(state, state.multiworld.victory_road_condition[player].value, player)) - connect(multiworld, player, "Route 23-Grass", "Route 23-S", lambda state: logic.can_surf(state, player)) + lambda state: logic.has_badges(state, world.options.route_22_gate_condition.value, player)) + connect(multiworld, player, "Route 23-Grass", "Route 23-C", lambda state: logic.has_badges(state, world.options.victory_road_condition.value, player)) + connect(multiworld, player, "Route 23-Grass", "Route 23-S", lambda state: logic.can_surf(state, world, player)) connect(multiworld, player, "Viridian City-N", "Viridian City-G", lambda state: - logic.has_badges(state, state.multiworld.viridian_gym_condition[player].value, player)) - connect(multiworld, player, "Route 2-SW", "Route 2-SE", lambda state: logic.can_cut(state, player)) - connect(multiworld, player, "Route 2-NW", "Route 2-NE", lambda state: logic.can_cut(state, player)) - connect(multiworld, player, "Route 2-E", "Route 2-NE", lambda state: logic.can_cut(state, player)) + logic.has_badges(state, world.options.viridian_gym_condition.value, player)) + connect(multiworld, player, "Route 2-SW", "Route 2-SE", lambda state: logic.can_cut(state, world, player)) + connect(multiworld, player, "Route 2-NW", "Route 2-NE", lambda state: logic.can_cut(state, world, player)) + connect(multiworld, player, "Route 2-E", "Route 2-NE", lambda state: logic.can_cut(state, world, player)) connect(multiworld, player, "Route 2-SW", "Viridian City-N") connect(multiworld, player, "Route 2-NW", "Pewter City") connect(multiworld, player, "Pewter City", "Pewter City-E") connect(multiworld, player, "Pewter City-M", "Pewter City", one_way=True) - connect(multiworld, player, "Pewter City", "Pewter City-M", lambda state: logic.can_cut(state, player), one_way=True) - connect(multiworld, player, "Pewter City-E", "Route 3", lambda state: logic.route_3(state, player), one_way=True) + connect(multiworld, player, "Pewter City", "Pewter City-M", lambda state: logic.can_cut(state, world, player), one_way=True) + connect(multiworld, player, "Pewter City-E", "Route 3", lambda state: logic.route(state, world, player), one_way=True) connect(multiworld, player, "Route 3", "Pewter City-E", one_way=True) connect(multiworld, player, "Route 4-W", "Route 3") - connect(multiworld, player, "Route 24", "Cerulean City-Water", lambda state: logic.can_surf(state, player)) - connect(multiworld, player, "Cerulean City-Water", "Route 4-Lass", lambda state: logic.can_surf(state, player), one_way=True) + connect(multiworld, player, "Route 24", "Cerulean City-Water", lambda state: logic.can_surf(state, world, player)) + connect(multiworld, player, "Cerulean City-Water", "Route 4-Lass", lambda state: logic.can_surf(state, world, player), one_way=True) connect(multiworld, player, "Mt Moon B2F", "Mt Moon B2F-Wild", one_way=True) connect(multiworld, player, "Mt Moon B2F-NE", "Mt Moon B2F-Wild", one_way=True) connect(multiworld, player, "Mt Moon B2F-C", "Mt Moon B2F-Wild", one_way=True) @@ -1644,14 +1648,14 @@ def create_regions(self): connect(multiworld, player, "Cerulean City", "Route 24") connect(multiworld, player, "Cerulean City", "Cerulean City-T", lambda state: state.has("Help Bill", player)) connect(multiworld, player, "Cerulean City-Outskirts", "Cerulean City", one_way=True) - connect(multiworld, player, "Cerulean City", "Cerulean City-Outskirts", lambda state: logic.can_cut(state, player), one_way=True) - connect(multiworld, player, "Cerulean City-Outskirts", "Route 9", lambda state: logic.can_cut(state, player)) + connect(multiworld, player, "Cerulean City", "Cerulean City-Outskirts", lambda state: logic.can_cut(state, world, player), one_way=True) + connect(multiworld, player, "Cerulean City-Outskirts", "Route 9", lambda state: logic.can_cut(state, world, player)) connect(multiworld, player, "Cerulean City-Outskirts", "Route 5") - connect(multiworld, player, "Cerulean Cave B1F", "Cerulean Cave B1F-E", lambda state: logic.can_surf(state, player), one_way=True) + connect(multiworld, player, "Cerulean Cave B1F", "Cerulean Cave B1F-E", lambda state: logic.can_surf(state, world, player), one_way=True) connect(multiworld, player, "Route 24", "Route 25") connect(multiworld, player, "Route 9", "Route 10-N") - connect(multiworld, player, "Route 10-N", "Route 10-C", lambda state: logic.can_surf(state, player)) - connect(multiworld, player, "Route 10-C", "Route 10-P", lambda state: state.has("Plant Key", player) or not state.multiworld.extra_key_items[player].value) + connect(multiworld, player, "Route 10-N", "Route 10-C", lambda state: logic.can_surf(state, world, player)) + connect(multiworld, player, "Route 10-C", "Route 10-P", lambda state: state.has("Plant Key", player) or not world.options.extra_key_items.value) connect(multiworld, player, "Pallet Town", "Pallet/Viridian Fishing", lambda state: state.has("Super Rod", player), one_way=True) connect(multiworld, player, "Viridian City", "Pallet/Viridian Fishing", lambda state: state.has("Super Rod", player), one_way=True) connect(multiworld, player, "Route 22", "Route 22 Fishing", lambda state: state.has("Super Rod", player), one_way=True) @@ -1697,10 +1701,10 @@ def create_regions(self): connect(multiworld, player, "Pallet Town", "Old Rod Fishing", lambda state: state.has("Old Rod", player), one_way=True) connect(multiworld, player, "Pallet Town", "Good Rod Fishing", lambda state: state.has("Good Rod", player), one_way=True) connect(multiworld, player, "Cinnabar Lab Fossil Room", "Fossil Level", lambda state: logic.fossil_checks(state, 1, player), one_way=True) - connect(multiworld, player, "Route 5 Gate-N", "Route 5 Gate-S", lambda state: logic.can_pass_guards(state, player)) - connect(multiworld, player, "Route 6 Gate-N", "Route 6 Gate-S", lambda state: logic.can_pass_guards(state, player)) - connect(multiworld, player, "Route 7 Gate-W", "Route 7 Gate-E", lambda state: logic.can_pass_guards(state, player)) - connect(multiworld, player, "Route 8 Gate-W", "Route 8 Gate-E", lambda state: logic.can_pass_guards(state, player)) + connect(multiworld, player, "Route 5 Gate-N", "Route 5 Gate-S", lambda state: logic.can_pass_guards(state, world, player)) + connect(multiworld, player, "Route 6 Gate-N", "Route 6 Gate-S", lambda state: logic.can_pass_guards(state, world, player)) + connect(multiworld, player, "Route 7 Gate-W", "Route 7 Gate-E", lambda state: logic.can_pass_guards(state, world, player)) + connect(multiworld, player, "Route 8 Gate-W", "Route 8 Gate-E", lambda state: logic.can_pass_guards(state, world, player)) connect(multiworld, player, "Saffron City", "Route 5-S") connect(multiworld, player, "Saffron City", "Route 6-N") connect(multiworld, player, "Saffron City", "Route 7-E") @@ -1710,59 +1714,59 @@ def create_regions(self): connect(multiworld, player, "Saffron City", "Saffron City-G", lambda state: state.has("Silph Co Liberated", player)) connect(multiworld, player, "Saffron City", "Saffron City-Silph", lambda state: state.has("Fuji Saved", player)) connect(multiworld, player, "Route 6", "Vermilion City") - connect(multiworld, player, "Vermilion City", "Vermilion City-G", lambda state: logic.can_surf(state, player) or logic.can_cut(state, player)) + connect(multiworld, player, "Vermilion City", "Vermilion City-G", lambda state: logic.can_surf(state, world, player) or logic.can_cut(state, world, player)) connect(multiworld, player, "Vermilion City", "Vermilion City-Dock", lambda state: state.has("S.S. Ticket", player)) connect(multiworld, player, "Vermilion City", "Route 11") - connect(multiworld, player, "Route 12-N", "Route 12-S", lambda state: logic.can_surf(state, player)) + connect(multiworld, player, "Route 12-N", "Route 12-S", lambda state: logic.can_surf(state, world, player)) connect(multiworld, player, "Route 12-W", "Route 11-E", lambda state: state.has("Poke Flute", player)) connect(multiworld, player, "Route 12-W", "Route 12-N", lambda state: state.has("Poke Flute", player)) connect(multiworld, player, "Route 12-W", "Route 12-S", lambda state: state.has("Poke Flute", player)) - connect(multiworld, player, "Route 12-S", "Route 12-Grass", lambda state: logic.can_cut(state, player), one_way=True) + connect(multiworld, player, "Route 12-S", "Route 12-Grass", lambda state: logic.can_cut(state, world, player), one_way=True) connect(multiworld, player, "Route 12-L", "Lavender Town") connect(multiworld, player, "Route 10-S", "Lavender Town") connect(multiworld, player, "Route 8", "Lavender Town") - connect(multiworld, player, "Pokemon Tower 6F", "Pokemon Tower 6F-S", lambda state: state.has("Silph Scope", player) or (state.has("Buy Poke Doll", player) and state.multiworld.poke_doll_skip[player])) - connect(multiworld, player, "Route 8", "Route 8-Grass", lambda state: logic.can_cut(state, player), one_way=True) + connect(multiworld, player, "Pokemon Tower 6F", "Pokemon Tower 6F-S", lambda state: state.has("Silph Scope", player) or (state.has("Buy Poke Doll", player) and world.options.poke_doll_skip)) + connect(multiworld, player, "Route 8", "Route 8-Grass", lambda state: logic.can_cut(state, world, player), one_way=True) connect(multiworld, player, "Route 7", "Celadon City") - connect(multiworld, player, "Celadon City", "Celadon City-G", lambda state: logic.can_cut(state, player)) + connect(multiworld, player, "Celadon City", "Celadon City-G", lambda state: logic.can_cut(state, world, player)) connect(multiworld, player, "Celadon City", "Route 16-E") - connect(multiworld, player, "Route 18 Gate 1F-W", "Route 18 Gate 1F-E", lambda state: state.has("Bicycle", player) or state.multiworld.bicycle_gate_skips[player] == "in_logic") - connect(multiworld, player, "Route 16 Gate 1F-W", "Route 16 Gate 1F-E", lambda state: state.has("Bicycle", player) or state.multiworld.bicycle_gate_skips[player] == "in_logic") - connect(multiworld, player, "Route 16-E", "Route 16-NE", lambda state: logic.can_cut(state, player)) + connect(multiworld, player, "Route 18 Gate 1F-W", "Route 18 Gate 1F-E", lambda state: state.has("Bicycle", player) or world.options.bicycle_gate_skips == "in_logic") + connect(multiworld, player, "Route 16 Gate 1F-W", "Route 16 Gate 1F-E", lambda state: state.has("Bicycle", player) or world.options.bicycle_gate_skips == "in_logic") + connect(multiworld, player, "Route 16-E", "Route 16-NE", lambda state: logic.can_cut(state, world, player)) connect(multiworld, player, "Route 16-E", "Route 16-C", lambda state: state.has("Poke Flute", player)) connect(multiworld, player, "Route 17", "Route 16-SW") connect(multiworld, player, "Route 17", "Route 18-W") # connect(multiworld, player, "Pokemon Mansion 2F", "Pokemon Mansion 2F-NW", one_way=True) - connect(multiworld, player, "Safari Zone Gate-S", "Safari Zone Gate-N", lambda state: state.has("Safari Pass", player) or not state.multiworld.extra_key_items[player].value, one_way=True) + connect(multiworld, player, "Safari Zone Gate-S", "Safari Zone Gate-N", lambda state: state.has("Safari Pass", player) or not world.options.extra_key_items.value, one_way=True) connect(multiworld, player, "Fuchsia City", "Route 15-W") connect(multiworld, player, "Fuchsia City", "Route 18-E") connect(multiworld, player, "Route 15", "Route 14") - connect(multiworld, player, "Route 14", "Route 15-N", lambda state: logic.can_cut(state, player), one_way=True) - connect(multiworld, player, "Route 14", "Route 14-Grass", lambda state: logic.can_cut(state, player), one_way=True) - connect(multiworld, player, "Route 13", "Route 13-Grass", lambda state: logic.can_cut(state, player), one_way=True) + connect(multiworld, player, "Route 14", "Route 15-N", lambda state: logic.can_cut(state, world, player), one_way=True) + connect(multiworld, player, "Route 14", "Route 14-Grass", lambda state: logic.can_cut(state, world, player), one_way=True) + connect(multiworld, player, "Route 13", "Route 13-Grass", lambda state: logic.can_cut(state, world, player), one_way=True) connect(multiworld, player, "Route 14", "Route 13") - connect(multiworld, player, "Route 13", "Route 13-E", lambda state: logic.can_strength(state, player) or logic.can_surf(state, player) or not state.multiworld.extra_strength_boulders[player].value) + connect(multiworld, player, "Route 13", "Route 13-E", lambda state: logic.can_strength(state, world, player) or logic.can_surf(state, world, player) or not world.options.extra_strength_boulders.value) connect(multiworld, player, "Route 12-S", "Route 13-E") connect(multiworld, player, "Fuchsia City", "Route 19-N") - connect(multiworld, player, "Route 19-N", "Route 19-S", lambda state: logic.can_surf(state, player)) - connect(multiworld, player, "Route 20-E", "Route 20-IW", lambda state: logic.can_surf(state, player)) + connect(multiworld, player, "Route 19-N", "Route 19-S", lambda state: logic.can_surf(state, world, player)) + connect(multiworld, player, "Route 20-E", "Route 20-IW", lambda state: logic.can_surf(state, world, player)) connect(multiworld, player, "Route 20-E", "Route 19-S") - connect(multiworld, player, "Route 20-W", "Cinnabar Island", lambda state: logic.can_surf(state, player)) - connect(multiworld, player, "Route 20-IE", "Route 20-W", lambda state: logic.can_surf(state, player)) + connect(multiworld, player, "Route 20-W", "Cinnabar Island", lambda state: logic.can_surf(state, world, player)) + connect(multiworld, player, "Route 20-IE", "Route 20-W", lambda state: logic.can_surf(state, world, player)) connect(multiworld, player, "Route 20-E", "Route 19/20-Water", one_way=True) connect(multiworld, player, "Route 20-W", "Route 19/20-Water", one_way=True) connect(multiworld, player, "Route 19-S", "Route 19/20-Water", one_way=True) - connect(multiworld, player, "Safari Zone West-NW", "Safari Zone West", lambda state: logic.can_surf(state, player)) + connect(multiworld, player, "Safari Zone West-NW", "Safari Zone West", lambda state: logic.can_surf(state, world, player)) connect(multiworld, player, "Safari Zone West", "Safari Zone West-Wild", one_way=True) connect(multiworld, player, "Safari Zone West-NW", "Safari Zone West-Wild", one_way=True) - connect(multiworld, player, "Safari Zone Center-NW", "Safari Zone Center-C", lambda state: logic.can_surf(state, player)) - connect(multiworld, player, "Safari Zone Center-NE", "Safari Zone Center-C", lambda state: logic.can_surf(state, player)) - connect(multiworld, player, "Safari Zone Center-S", "Safari Zone Center-C", lambda state: logic.can_surf(state, player)) + connect(multiworld, player, "Safari Zone Center-NW", "Safari Zone Center-C", lambda state: logic.can_surf(state, world, player)) + connect(multiworld, player, "Safari Zone Center-NE", "Safari Zone Center-C", lambda state: logic.can_surf(state, world, player)) + connect(multiworld, player, "Safari Zone Center-S", "Safari Zone Center-C", lambda state: logic.can_surf(state, world, player)) connect(multiworld, player, "Safari Zone Center-S", "Safari Zone Center-Wild", one_way=True) connect(multiworld, player, "Safari Zone Center-NW", "Safari Zone Center-Wild", one_way=True) connect(multiworld, player, "Safari Zone Center-NE", "Safari Zone Center-Wild", one_way=True) - connect(multiworld, player, "Victory Road 3F-S", "Victory Road 3F", lambda state: logic.can_strength(state, player)) - connect(multiworld, player, "Victory Road 3F-SE", "Victory Road 3F-S", lambda state: logic.can_strength(state, player), one_way=True) + connect(multiworld, player, "Victory Road 3F-S", "Victory Road 3F", lambda state: logic.can_strength(state, world, player)) + connect(multiworld, player, "Victory Road 3F-SE", "Victory Road 3F-S", lambda state: logic.can_strength(state, world, player), one_way=True) connect(multiworld, player, "Victory Road 3F", "Victory Road 3F-Wild", one_way=True) connect(multiworld, player, "Victory Road 3F-SE", "Victory Road 3F-Wild", one_way=True) connect(multiworld, player, "Victory Road 3F-S", "Victory Road 3F-Wild", one_way=True) @@ -1771,10 +1775,10 @@ def create_regions(self): connect(multiworld, player, "Victory Road 2F-C", "Victory Road 2F-Wild", one_way=True) connect(multiworld, player, "Victory Road 2F-E", "Victory Road 2F-Wild", one_way=True) connect(multiworld, player, "Victory Road 2F-SE", "Victory Road 2F-Wild", one_way=True) - connect(multiworld, player, "Victory Road 2F-W", "Victory Road 2F-C", lambda state: logic.can_strength(state, player), one_way=True) - connect(multiworld, player, "Victory Road 2F-NW", "Victory Road 2F-W", lambda state: logic.can_strength(state, player), one_way=True) - connect(multiworld, player, "Victory Road 2F-C", "Victory Road 2F-SE", lambda state: logic.can_strength(state, player) and state.has("Victory Road Boulder", player), one_way=True) - connect(multiworld, player, "Victory Road 1F-S", "Victory Road 1F", lambda state: logic.can_strength(state, player)) + connect(multiworld, player, "Victory Road 2F-W", "Victory Road 2F-C", lambda state: logic.can_strength(state, world, player), one_way=True) + connect(multiworld, player, "Victory Road 2F-NW", "Victory Road 2F-W", lambda state: logic.can_strength(state, world, player), one_way=True) + connect(multiworld, player, "Victory Road 2F-C", "Victory Road 2F-SE", lambda state: logic.can_strength(state, world, player) and state.has("Victory Road Boulder", player), one_way=True) + connect(multiworld, player, "Victory Road 1F-S", "Victory Road 1F", lambda state: logic.can_strength(state, world, player)) connect(multiworld, player, "Victory Road 1F", "Victory Road 1F-Wild", one_way=True) connect(multiworld, player, "Victory Road 1F-S", "Victory Road 1F-Wild", one_way=True) connect(multiworld, player, "Mt Moon B1F-W", "Mt Moon B1F-Wild", one_way=True) @@ -1796,50 +1800,50 @@ def create_regions(self): connect(multiworld, player, "Seafoam Islands B3F", "Seafoam Islands B3F-Wild", one_way=True) connect(multiworld, player, "Seafoam Islands B3F-NE", "Seafoam Islands B3F-Wild", one_way=True) connect(multiworld, player, "Seafoam Islands B3F-SE", "Seafoam Islands B3F-Wild", one_way=True) - connect(multiworld, player, "Seafoam Islands B4F", "Seafoam Islands B4F-W", lambda state: logic.can_surf(state, player), one_way=True) + connect(multiworld, player, "Seafoam Islands B4F", "Seafoam Islands B4F-W", lambda state: logic.can_surf(state, world, player), one_way=True) connect(multiworld, player, "Seafoam Islands B4F-W", "Seafoam Islands B4F", one_way=True) - connect(multiworld, player, "Seafoam Islands B3F", "Seafoam Islands B3F-SE", lambda state: logic.can_surf(state, player) and logic.can_strength(state, player) and state.has("Seafoam Exit Boulder", player, 6)) - connect(multiworld, player, "Viridian City", "Viridian City-N", lambda state: state.has("Oak's Parcel", player) or state.multiworld.old_man[player].value == 2 or logic.can_cut(state, player)) - connect(multiworld, player, "Route 11", "Route 11-C", lambda state: logic.can_strength(state, player) or not state.multiworld.extra_strength_boulders[player]) + connect(multiworld, player, "Seafoam Islands B3F", "Seafoam Islands B3F-SE", lambda state: logic.can_surf(state, world, player) and logic.can_strength(state, world, player) and state.has("Seafoam Exit Boulder", player, 6)) + connect(multiworld, player, "Viridian City", "Viridian City-N", lambda state: state.has("Oak's Parcel", player) or world.options.old_man.value == 2 or logic.can_cut(state, world, player)) + connect(multiworld, player, "Route 11", "Route 11-C", lambda state: logic.can_strength(state, world, player) or not world.options.extra_strength_boulders) connect(multiworld, player, "Cinnabar Island", "Cinnabar Island-G", lambda state: state.has("Secret Key", player)) - connect(multiworld, player, "Cinnabar Island", "Cinnabar Island-M", lambda state: state.has("Mansion Key", player) or not state.multiworld.extra_key_items[player].value) - connect(multiworld, player, "Route 21", "Cinnabar Island", lambda state: logic.can_surf(state, player)) - connect(multiworld, player, "Pallet Town", "Route 21", lambda state: logic.can_surf(state, player)) - connect(multiworld, player, "Celadon Gym", "Celadon Gym-C", lambda state: logic.can_cut(state, player), one_way=True) - connect(multiworld, player, "Celadon Game Corner", "Celadon Game Corner-Hidden Stairs", lambda state: (not state.multiworld.extra_key_items[player]) or state.has("Hideout Key", player), one_way=True) + connect(multiworld, player, "Cinnabar Island", "Cinnabar Island-M", lambda state: state.has("Mansion Key", player) or not world.options.extra_key_items.value) + connect(multiworld, player, "Route 21", "Cinnabar Island", lambda state: logic.can_surf(state, world, player)) + connect(multiworld, player, "Pallet Town", "Route 21", lambda state: logic.can_surf(state, world, player)) + connect(multiworld, player, "Celadon Gym", "Celadon Gym-C", lambda state: logic.can_cut(state, world, player), one_way=True) + connect(multiworld, player, "Celadon Game Corner", "Celadon Game Corner-Hidden Stairs", lambda state: (not world.options.extra_key_items) or state.has("Hideout Key", player), one_way=True) connect(multiworld, player, "Celadon Game Corner-Hidden Stairs", "Celadon Game Corner", one_way=True) connect(multiworld, player, "Rocket Hideout B1F-SE", "Rocket Hideout B1F", one_way=True) - connect(multiworld, player, "Indigo Plateau Lobby", "Indigo Plateau Lobby-N", lambda state: logic.has_badges(state, state.multiworld.elite_four_badges_condition[player].value, player) and logic.has_pokemon(state, state.multiworld.elite_four_pokedex_condition[player].total, player) and logic.has_key_items(state, state.multiworld.elite_four_key_items_condition[player].total, player) and (state.has("Pokedex", player, int(state.multiworld.elite_four_pokedex_condition[player].total > 1) * state.multiworld.require_pokedex[player].value))) + connect(multiworld, player, "Indigo Plateau Lobby", "Indigo Plateau Lobby-N", lambda state: logic.has_badges(state, world.options.elite_four_badges_condition.value, player) and logic.has_pokemon(state, world.options.elite_four_pokedex_condition.total, player) and logic.has_key_items(state, world.options.elite_four_key_items_condition.total, player) and (state.has("Pokedex", player, int(world.options.elite_four_pokedex_condition.total > 1) * world.options.require_pokedex.value))) connect(multiworld, player, "Pokemon Mansion 3F", "Pokemon Mansion 3F-Wild", one_way=True) connect(multiworld, player, "Pokemon Mansion 3F-SW", "Pokemon Mansion 3F-Wild", one_way=True) connect(multiworld, player, "Pokemon Mansion 3F-SE", "Pokemon Mansion 3F-Wild", one_way=True) connect(multiworld, player, "Pokemon Mansion 2F-E", "Pokemon Mansion 2F-Wild", one_way=True) connect(multiworld, player, "Pokemon Mansion 1F-SE", "Pokemon Mansion 1F-Wild", one_way=True) connect(multiworld, player, "Pokemon Mansion 1F", "Pokemon Mansion 1F-Wild", one_way=True) - connect(multiworld, player, "Rock Tunnel 1F-S 1", "Rock Tunnel 1F-S", lambda state: logic.rock_tunnel(state, player)) - connect(multiworld, player, "Rock Tunnel 1F-S 2", "Rock Tunnel 1F-S", lambda state: logic.rock_tunnel(state, player)) - connect(multiworld, player, "Rock Tunnel 1F-NW 1", "Rock Tunnel 1F-NW", lambda state: logic.rock_tunnel(state, player)) - connect(multiworld, player, "Rock Tunnel 1F-NW 2", "Rock Tunnel 1F-NW", lambda state: logic.rock_tunnel(state, player)) - connect(multiworld, player, "Rock Tunnel 1F-NE 1", "Rock Tunnel 1F-NE", lambda state: logic.rock_tunnel(state, player)) - connect(multiworld, player, "Rock Tunnel 1F-NE 2", "Rock Tunnel 1F-NE", lambda state: logic.rock_tunnel(state, player)) - connect(multiworld, player, "Rock Tunnel B1F-W 1", "Rock Tunnel B1F-W", lambda state: logic.rock_tunnel(state, player)) - connect(multiworld, player, "Rock Tunnel B1F-W 2", "Rock Tunnel B1F-W", lambda state: logic.rock_tunnel(state, player)) - connect(multiworld, player, "Rock Tunnel B1F-E 1", "Rock Tunnel B1F-E", lambda state: logic.rock_tunnel(state, player)) - connect(multiworld, player, "Rock Tunnel B1F-E 2", "Rock Tunnel B1F-E", lambda state: logic.rock_tunnel(state, player)) - connect(multiworld, player, "Rock Tunnel 1F-S", "Rock Tunnel 1F-Wild", lambda state: logic.rock_tunnel(state, player), one_way=True) - connect(multiworld, player, "Rock Tunnel 1F-NW", "Rock Tunnel 1F-Wild", lambda state: logic.rock_tunnel(state, player), one_way=True) - connect(multiworld, player, "Rock Tunnel 1F-NE", "Rock Tunnel 1F-Wild", lambda state: logic.rock_tunnel(state, player), one_way=True) - connect(multiworld, player, "Rock Tunnel B1F-W", "Rock Tunnel B1F-Wild", lambda state: logic.rock_tunnel(state, player), one_way=True) - connect(multiworld, player, "Rock Tunnel B1F-E", "Rock Tunnel B1F-Wild", lambda state: logic.rock_tunnel(state, player), one_way=True) + connect(multiworld, player, "Rock Tunnel 1F-S 1", "Rock Tunnel 1F-S", lambda state: logic.rock_tunnel(state, world, player)) + connect(multiworld, player, "Rock Tunnel 1F-S 2", "Rock Tunnel 1F-S", lambda state: logic.rock_tunnel(state, world, player)) + connect(multiworld, player, "Rock Tunnel 1F-NW 1", "Rock Tunnel 1F-NW", lambda state: logic.rock_tunnel(state, world, player)) + connect(multiworld, player, "Rock Tunnel 1F-NW 2", "Rock Tunnel 1F-NW", lambda state: logic.rock_tunnel(state, world, player)) + connect(multiworld, player, "Rock Tunnel 1F-NE 1", "Rock Tunnel 1F-NE", lambda state: logic.rock_tunnel(state, world, player)) + connect(multiworld, player, "Rock Tunnel 1F-NE 2", "Rock Tunnel 1F-NE", lambda state: logic.rock_tunnel(state, world, player)) + connect(multiworld, player, "Rock Tunnel B1F-W 1", "Rock Tunnel B1F-W", lambda state: logic.rock_tunnel(state, world, player)) + connect(multiworld, player, "Rock Tunnel B1F-W 2", "Rock Tunnel B1F-W", lambda state: logic.rock_tunnel(state, world, player)) + connect(multiworld, player, "Rock Tunnel B1F-E 1", "Rock Tunnel B1F-E", lambda state: logic.rock_tunnel(state, world, player)) + connect(multiworld, player, "Rock Tunnel B1F-E 2", "Rock Tunnel B1F-E", lambda state: logic.rock_tunnel(state, world, player)) + connect(multiworld, player, "Rock Tunnel 1F-S", "Rock Tunnel 1F-Wild", lambda state: logic.rock_tunnel(state, world, player), one_way=True) + connect(multiworld, player, "Rock Tunnel 1F-NW", "Rock Tunnel 1F-Wild", lambda state: logic.rock_tunnel(state, world, player), one_way=True) + connect(multiworld, player, "Rock Tunnel 1F-NE", "Rock Tunnel 1F-Wild", lambda state: logic.rock_tunnel(state, world, player), one_way=True) + connect(multiworld, player, "Rock Tunnel B1F-W", "Rock Tunnel B1F-Wild", lambda state: logic.rock_tunnel(state, world, player), one_way=True) + connect(multiworld, player, "Rock Tunnel B1F-E", "Rock Tunnel B1F-Wild", lambda state: logic.rock_tunnel(state, world, player), one_way=True) connect(multiworld, player, "Cerulean Cave 1F-SE", "Cerulean Cave 1F-Wild", one_way=True) connect(multiworld, player, "Cerulean Cave 1F-SW", "Cerulean Cave 1F-Wild", one_way=True) connect(multiworld, player, "Cerulean Cave 1F-NE", "Cerulean Cave 1F-Wild", one_way=True) connect(multiworld, player, "Cerulean Cave 1F-N", "Cerulean Cave 1F-Wild", one_way=True) connect(multiworld, player, "Cerulean Cave 1F-NW", "Cerulean Cave 1F-Wild", one_way=True) - connect(multiworld, player, "Cerulean Cave 1F-SE", "Cerulean Cave 1F-Water", lambda state: logic.can_surf(state, player)) - connect(multiworld, player, "Cerulean Cave 1F-SW", "Cerulean Cave 1F-Water", lambda state: logic.can_surf(state, player)) - connect(multiworld, player, "Cerulean Cave 1F-N", "Cerulean Cave 1F-Water", lambda state: logic.can_surf(state, player)) - connect(multiworld, player, "Cerulean Cave 1F-NE", "Cerulean Cave 1F-Water", lambda state: logic.can_surf(state, player)) + connect(multiworld, player, "Cerulean Cave 1F-SE", "Cerulean Cave 1F-Water", lambda state: logic.can_surf(state, world, player)) + connect(multiworld, player, "Cerulean Cave 1F-SW", "Cerulean Cave 1F-Water", lambda state: logic.can_surf(state, world, player)) + connect(multiworld, player, "Cerulean Cave 1F-N", "Cerulean Cave 1F-Water", lambda state: logic.can_surf(state, world, player)) + connect(multiworld, player, "Cerulean Cave 1F-NE", "Cerulean Cave 1F-Water", lambda state: logic.can_surf(state, world, player)) connect(multiworld, player, "Pokemon Mansion 3F", "Pokemon Mansion 3F-SE", one_way=True) connect(multiworld, player, "Silph Co 2F", "Silph Co 2F-NW", lambda state: logic.card_key(state, 2, player)) connect(multiworld, player, "Silph Co 2F", "Silph Co 2F-SW", lambda state: logic.card_key(state, 2, player)) @@ -1858,80 +1862,80 @@ def create_regions(self): connect(multiworld, player, "Silph Co 9F-NW", "Silph Co 9F-SW", lambda state: logic.card_key(state, 9, player)) connect(multiworld, player, "Silph Co 10F", "Silph Co 10F-SE", lambda state: logic.card_key(state, 10, player)) connect(multiworld, player, "Silph Co 11F-W", "Silph Co 11F-C", lambda state: logic.card_key(state, 11, player)) - connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-1F", lambda state: (not state.multiworld.all_elevators_locked[player]) or state.has("Lift Key", player)), - connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-2F", lambda state: (not state.multiworld.all_elevators_locked[player]) or state.has("Lift Key", player)), - connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-3F", lambda state: (not state.multiworld.all_elevators_locked[player]) or state.has("Lift Key", player)), - connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-4F", lambda state: (not state.multiworld.all_elevators_locked[player]) or state.has("Lift Key", player)), - connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-5F", lambda state: (not state.multiworld.all_elevators_locked[player]) or state.has("Lift Key", player)), - connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-6F", lambda state: (not state.multiworld.all_elevators_locked[player]) or state.has("Lift Key", player)), - connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-7F", lambda state: (not state.multiworld.all_elevators_locked[player]) or state.has("Lift Key", player)), - connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-8F", lambda state: (not state.multiworld.all_elevators_locked[player]) or state.has("Lift Key", player)), - connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-9F", lambda state: (not state.multiworld.all_elevators_locked[player]) or state.has("Lift Key", player)), - connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-10F", lambda state: (not state.multiworld.all_elevators_locked[player]) or state.has("Lift Key", player)), - connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-11F", lambda state: (not state.multiworld.all_elevators_locked[player]) or state.has("Lift Key", player)), + connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-1F", lambda state: (not world.options.all_elevators_locked) or state.has("Lift Key", player)), + connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-2F", lambda state: (not world.options.all_elevators_locked) or state.has("Lift Key", player)), + connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-3F", lambda state: (not world.options.all_elevators_locked) or state.has("Lift Key", player)), + connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-4F", lambda state: (not world.options.all_elevators_locked) or state.has("Lift Key", player)), + connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-5F", lambda state: (not world.options.all_elevators_locked) or state.has("Lift Key", player)), + connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-6F", lambda state: (not world.options.all_elevators_locked) or state.has("Lift Key", player)), + connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-7F", lambda state: (not world.options.all_elevators_locked) or state.has("Lift Key", player)), + connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-8F", lambda state: (not world.options.all_elevators_locked) or state.has("Lift Key", player)), + connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-9F", lambda state: (not world.options.all_elevators_locked) or state.has("Lift Key", player)), + connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-10F", lambda state: (not world.options.all_elevators_locked) or state.has("Lift Key", player)), + connect(multiworld, player, "Silph Co Elevator", "Silph Co Elevator-11F", lambda state: (not world.options.all_elevators_locked) or state.has("Lift Key", player)), connect(multiworld, player, "Rocket Hideout Elevator", "Rocket Hideout Elevator-B1F", lambda state: state.has("Lift Key", player)) connect(multiworld, player, "Rocket Hideout Elevator", "Rocket Hideout Elevator-B2F", lambda state: state.has("Lift Key", player)) connect(multiworld, player, "Rocket Hideout Elevator", "Rocket Hideout Elevator-B4F", lambda state: state.has("Lift Key", player)) - connect(multiworld, player, "Celadon Department Store Elevator", "Celadon Department Store Elevator-1F", lambda state: (not state.multiworld.all_elevators_locked[player]) or state.has("Lift Key", player)), - connect(multiworld, player, "Celadon Department Store Elevator", "Celadon Department Store Elevator-2F", lambda state: (not state.multiworld.all_elevators_locked[player]) or state.has("Lift Key", player)), - connect(multiworld, player, "Celadon Department Store Elevator", "Celadon Department Store Elevator-3F", lambda state: (not state.multiworld.all_elevators_locked[player]) or state.has("Lift Key", player)), - connect(multiworld, player, "Celadon Department Store Elevator", "Celadon Department Store Elevator-4F", lambda state: (not state.multiworld.all_elevators_locked[player]) or state.has("Lift Key", player)), - connect(multiworld, player, "Celadon Department Store Elevator", "Celadon Department Store Elevator-5F", lambda state: (not state.multiworld.all_elevators_locked[player]) or state.has("Lift Key", player)), + connect(multiworld, player, "Celadon Department Store Elevator", "Celadon Department Store Elevator-1F", lambda state: (not world.options.all_elevators_locked) or state.has("Lift Key", player)), + connect(multiworld, player, "Celadon Department Store Elevator", "Celadon Department Store Elevator-2F", lambda state: (not world.options.all_elevators_locked) or state.has("Lift Key", player)), + connect(multiworld, player, "Celadon Department Store Elevator", "Celadon Department Store Elevator-3F", lambda state: (not world.options.all_elevators_locked) or state.has("Lift Key", player)), + connect(multiworld, player, "Celadon Department Store Elevator", "Celadon Department Store Elevator-4F", lambda state: (not world.options.all_elevators_locked) or state.has("Lift Key", player)), + connect(multiworld, player, "Celadon Department Store Elevator", "Celadon Department Store Elevator-5F", lambda state: (not world.options.all_elevators_locked) or state.has("Lift Key", player)), connect(multiworld, player, "Route 23-N", "Indigo Plateau") connect(multiworld, player, "Cerulean City-Water", "Cerulean City-Cave", lambda state: - logic.has_badges(state, self.multiworld.cerulean_cave_badges_condition[player].value, player) and - logic.has_key_items(state, self.multiworld.cerulean_cave_key_items_condition[player].total, player) and logic.can_surf(state, player)) + logic.has_badges(state, world.options.cerulean_cave_badges_condition.value, player) and + logic.has_key_items(state, world.options.cerulean_cave_key_items_condition.total, player) and logic.can_surf(state, world, player)) # access to any part of a city will enable flying to the Pokemon Center - connect(multiworld, player, "Cerulean City-Cave", "Cerulean City", lambda state: logic.can_fly(state, player), one_way=True) - connect(multiworld, player, "Cerulean City-Badge House Backyard", "Cerulean City", lambda state: logic.can_fly(state, player), one_way=True) - connect(multiworld, player, "Cerulean City-T", "Cerulean City", lambda state: logic.can_fly(state, player), one_way=True, name="Cerulean City-T to Cerulean City (Fly)") - connect(multiworld, player, "Fuchsia City-Good Rod House Backyard", "Fuchsia City", lambda state: logic.can_fly(state, player), one_way=True) - connect(multiworld, player, "Saffron City-G", "Saffron City", lambda state: logic.can_fly(state, player), one_way=True, name="Saffron City-G to Saffron City (Fly)") - connect(multiworld, player, "Saffron City-Pidgey", "Saffron City", lambda state: logic.can_fly(state, player), one_way=True, name="Saffron City-Pidgey to Saffron City (Fly)") - connect(multiworld, player, "Saffron City-Silph", "Saffron City", lambda state: logic.can_fly(state, player), one_way=True, name="Saffron City-Silph to Saffron City (Fly)") - connect(multiworld, player, "Saffron City-Copycat", "Saffron City", lambda state: logic.can_fly(state, player), one_way=True, name="Saffron City-Copycat to Saffron City (Fly)") - connect(multiworld, player, "Celadon City-G", "Celadon City", lambda state: logic.can_fly(state, player), one_way=True, name="Celadon City-G to Celadon City (Fly)") - connect(multiworld, player, "Vermilion City-G", "Vermilion City", lambda state: logic.can_fly(state, player), one_way=True, name="Vermilion City-G to Vermilion City (Fly)") - connect(multiworld, player, "Vermilion City-Dock", "Vermilion City", lambda state: logic.can_fly(state, player), one_way=True, name="Vermilion City-Dock to Vermilion City (Fly)") - connect(multiworld, player, "Cinnabar Island-G", "Cinnabar Island", lambda state: logic.can_fly(state, player), one_way=True, name="Cinnabar Island-G to Cinnabar Island (Fly)") - connect(multiworld, player, "Cinnabar Island-M", "Cinnabar Island", lambda state: logic.can_fly(state, player), one_way=True, name="Cinnabar Island-M to Cinnabar Island (Fly)") + connect(multiworld, player, "Cerulean City-Cave", "Cerulean City", lambda state: logic.can_fly(state, world, player), one_way=True) + connect(multiworld, player, "Cerulean City-Badge House Backyard", "Cerulean City", lambda state: logic.can_fly(state, world, player), one_way=True) + connect(multiworld, player, "Cerulean City-T", "Cerulean City", lambda state: logic.can_fly(state, world, player), one_way=True, name="Cerulean City-T to Cerulean City (Fly)") + connect(multiworld, player, "Fuchsia City-Good Rod House Backyard", "Fuchsia City", lambda state: logic.can_fly(state, world, player), one_way=True) + connect(multiworld, player, "Saffron City-G", "Saffron City", lambda state: logic.can_fly(state, world, player), one_way=True, name="Saffron City-G to Saffron City (Fly)") + connect(multiworld, player, "Saffron City-Pidgey", "Saffron City", lambda state: logic.can_fly(state, world, player), one_way=True, name="Saffron City-Pidgey to Saffron City (Fly)") + connect(multiworld, player, "Saffron City-Silph", "Saffron City", lambda state: logic.can_fly(state, world, player), one_way=True, name="Saffron City-Silph to Saffron City (Fly)") + connect(multiworld, player, "Saffron City-Copycat", "Saffron City", lambda state: logic.can_fly(state, world, player), one_way=True, name="Saffron City-Copycat to Saffron City (Fly)") + connect(multiworld, player, "Celadon City-G", "Celadon City", lambda state: logic.can_fly(state, world, player), one_way=True, name="Celadon City-G to Celadon City (Fly)") + connect(multiworld, player, "Vermilion City-G", "Vermilion City", lambda state: logic.can_fly(state, world, player), one_way=True, name="Vermilion City-G to Vermilion City (Fly)") + connect(multiworld, player, "Vermilion City-Dock", "Vermilion City", lambda state: logic.can_fly(state, world, player), one_way=True, name="Vermilion City-Dock to Vermilion City (Fly)") + connect(multiworld, player, "Cinnabar Island-G", "Cinnabar Island", lambda state: logic.can_fly(state, world, player), one_way=True, name="Cinnabar Island-G to Cinnabar Island (Fly)") + connect(multiworld, player, "Cinnabar Island-M", "Cinnabar Island", lambda state: logic.can_fly(state, world, player), one_way=True, name="Cinnabar Island-M to Cinnabar Island (Fly)") # drops connect(multiworld, player, "Seafoam Islands 1F", "Seafoam Islands B1F", one_way=True, name="Seafoam Islands 1F to Seafoam Islands B1F (Drop)") connect(multiworld, player, "Seafoam Islands 1F", "Seafoam Islands B1F-NE", one_way=True, name="Seafoam Islands 1F to Seafoam Islands B1F-NE (Drop)") connect(multiworld, player, "Seafoam Islands B1F", "Seafoam Islands B2F-NW", one_way=True, name="Seafoam Islands 1F to Seafoam Islands B2F-NW (Drop)") connect(multiworld, player, "Seafoam Islands B1F-NE", "Seafoam Islands B2F-NE", one_way=True) - connect(multiworld, player, "Seafoam Islands B2F-NW", "Seafoam Islands B3F", lambda state: logic.can_strength(state, player) and state.has("Seafoam Exit Boulder", player, 6), one_way=True) - connect(multiworld, player, "Seafoam Islands B2F-NE", "Seafoam Islands B3F", lambda state: logic.can_strength(state, player) and state.has("Seafoam Exit Boulder", player, 6), one_way=True) - connect(multiworld, player, "Seafoam Islands B2F-NW", "Seafoam Islands B3F-SE", lambda state: logic.can_strength(state, player) and state.has("Seafoam Exit Boulder", player, 6), one_way=True) - connect(multiworld, player, "Seafoam Islands B2F-NE", "Seafoam Islands B3F-SE", lambda state: logic.can_strength(state, player) and state.has("Seafoam Exit Boulder", player, 6), one_way=True) + connect(multiworld, player, "Seafoam Islands B2F-NW", "Seafoam Islands B3F", lambda state: logic.can_strength(state, world, player) and state.has("Seafoam Exit Boulder", player, 6), one_way=True) + connect(multiworld, player, "Seafoam Islands B2F-NE", "Seafoam Islands B3F", lambda state: logic.can_strength(state, world, player) and state.has("Seafoam Exit Boulder", player, 6), one_way=True) + connect(multiworld, player, "Seafoam Islands B2F-NW", "Seafoam Islands B3F-SE", lambda state: logic.can_strength(state, world, player) and state.has("Seafoam Exit Boulder", player, 6), one_way=True) + connect(multiworld, player, "Seafoam Islands B2F-NE", "Seafoam Islands B3F-SE", lambda state: logic.can_strength(state, world, player) and state.has("Seafoam Exit Boulder", player, 6), one_way=True) # If you haven't dropped the boulders, you'll go straight to B4F connect(multiworld, player, "Seafoam Islands B2F-NW", "Seafoam Islands B4F-W", one_way=True) connect(multiworld, player, "Seafoam Islands B2F-NE", "Seafoam Islands B4F-W", one_way=True) connect(multiworld, player, "Seafoam Islands B3F", "Seafoam Islands B4F", one_way=True, name="Seafoam Islands B1F to Seafoam Islands B4F (Drop)") - connect(multiworld, player, "Seafoam Islands B3F", "Seafoam Islands B4F-W", lambda state: logic.can_surf(state, player), one_way=True) + connect(multiworld, player, "Seafoam Islands B3F", "Seafoam Islands B4F-W", lambda state: logic.can_surf(state, world, player), one_way=True) connect(multiworld, player, "Pokemon Mansion 3F-SE", "Pokemon Mansion 2F", one_way=True) connect(multiworld, player, "Pokemon Mansion 3F-SE", "Pokemon Mansion 1F-SE", one_way=True) connect(multiworld, player, "Victory Road 3F-S", "Victory Road 2F-C", one_way=True) - if multiworld.worlds[player].fly_map != "Pallet Town": - connect(multiworld, player, "Menu", multiworld.worlds[player].fly_map, - lambda state: logic.can_fly(state, player), one_way=True, name="Free Fly Location") + if world.fly_map != "Pallet Town": + connect(multiworld, player, "Menu", world.fly_map, + lambda state: logic.can_fly(state, world, player), one_way=True, name="Free Fly Location") - if multiworld.worlds[player].town_map_fly_map != "Pallet Town": - connect(multiworld, player, "Menu", multiworld.worlds[player].town_map_fly_map, - lambda state: logic.can_fly(state, player) and state.has("Town Map", player), one_way=True, + if world.town_map_fly_map != "Pallet Town": + connect(multiworld, player, "Menu", world.town_map_fly_map, + lambda state: logic.can_fly(state, world, player) and state.has("Town Map", player), one_way=True, name="Town Map Fly Location") - cache = multiworld.regions.entrance_cache[self.player].copy() - if multiworld.badgesanity[player] or multiworld.door_shuffle[player] in ("off", "simple"): + cache = multiworld.regions.entrance_cache[world.player].copy() + if world.options.badgesanity or world.options.door_shuffle in ("off", "simple"): badges = None badge_locs = None else: - badges = [item for item in self.item_pool if "Badge" in item.name] + badges = [item for item in world.item_pool if "Badge" in item.name] for badge in badges: - self.item_pool.remove(badge) + world.item_pool.remove(badge) badge_locs = [multiworld.get_location(loc, player) for loc in [ "Pewter Gym - Brock Prize", "Cerulean Gym - Misty Prize", "Vermilion Gym - Lt. Surge Prize", "Celadon Gym - Erika Prize", "Fuchsia Gym - Koga Prize", "Saffron Gym - Sabrina Prize", @@ -1939,15 +1943,18 @@ def create_regions(self): ]] for attempt in range(10): try: - door_shuffle(self, multiworld, player, badges, badge_locs) + door_shuffle(world, multiworld, player, badges, badge_locs) except DoorShuffleException as e: if attempt == 9: raise e - for region in self.multiworld.get_regions(player): + for region in world.multiworld.get_regions(player): for entrance in reversed(region.exits): if isinstance(entrance, PokemonRBWarp): region.exits.remove(entrance) - multiworld.regions.entrance_cache[self.player] = cache.copy() + for entrance in reversed(region.entrances): + if isinstance(entrance, PokemonRBWarp): + region.entrances.remove(entrance) + multiworld.regions.entrance_cache[world.player] = cache.copy() if badge_locs: for loc in badge_locs: loc.item = None @@ -1965,36 +1972,36 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): shuffle = True interior = False if not outdoor_map(region.name) and not outdoor_map(entrance_data['to']['map']): - if multiworld.door_shuffle[player] not in ("full", "insanity", "decoupled"): + if world.options.door_shuffle not in ("full", "insanity", "decoupled"): shuffle = False interior = True - if multiworld.door_shuffle[player] == "simple": + if world.options.door_shuffle == "simple": if sorted([entrance_data['to']['map'], region.name]) == ["Celadon Game Corner-Hidden Stairs", "Rocket Hideout B1F"]: shuffle = True elif sorted([entrance_data['to']['map'], region.name]) == ["Celadon City", "Celadon Game Corner"]: shuffle = False - if (multiworld.randomize_rock_tunnel[player] and "Rock Tunnel" in region.name and "Rock Tunnel" in + if (world.options.randomize_rock_tunnel and "Rock Tunnel" in region.name and "Rock Tunnel" in entrance_data['to']['map']): shuffle = False elif (f"{region.name} to {entrance_data['to']['map']}" if "name" not in entrance_data else entrance_data["name"]) in silph_co_warps + saffron_gym_warps: - if multiworld.warp_tile_shuffle[player]: + if world.options.warp_tile_shuffle: shuffle = True - if multiworld.warp_tile_shuffle[player] == "mixed" and multiworld.door_shuffle[player] == "full": + if world.options.warp_tile_shuffle == "mixed" and world.options.door_shuffle == "full": interior = True else: interior = False else: shuffle = False - elif not multiworld.door_shuffle[player]: + elif not world.options.door_shuffle: shuffle = False if shuffle: entrance = PokemonRBWarp(player, f"{region.name} to {entrance_data['to']['map']}" if "name" not in entrance_data else entrance_data["name"], region, entrance_data["id"], entrance_data["address"], entrance_data["flags"] if "flags" in entrance_data else "") - if interior and multiworld.door_shuffle[player] == "full": + if interior and world.options.door_shuffle == "full": full_interiors.append(entrance) else: entrances.append(entrance) @@ -2006,22 +2013,22 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): forced_connections = set() one_way_forced_connections = set() - if multiworld.door_shuffle[player]: - if multiworld.door_shuffle[player] in ("full", "insanity", "decoupled"): + if world.options.door_shuffle: + if world.options.door_shuffle in ("full", "insanity", "decoupled"): safari_zone_doors = [door for pair in safari_zone_connections for door in pair] safari_zone_doors.sort() order = ["Center", "East", "North", "West"] - multiworld.random.shuffle(order) + world.random.shuffle(order) usable_doors = ["Safari Zone Gate-N to Safari Zone Center-S"] for section in order: section_doors = [door for door in safari_zone_doors if door.startswith(f"Safari Zone {section}")] - connect_door_a = multiworld.random.choice(usable_doors) - connect_door_b = multiworld.random.choice(section_doors) + connect_door_a = world.random.choice(usable_doors) + connect_door_b = world.random.choice(section_doors) usable_doors.remove(connect_door_a) section_doors.remove(connect_door_b) forced_connections.add((connect_door_a, connect_door_b)) usable_doors += section_doors - multiworld.random.shuffle(usable_doors) + world.random.shuffle(usable_doors) while usable_doors: forced_connections.add((usable_doors.pop(), usable_doors.pop())) else: @@ -2029,32 +2036,32 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): usable_safe_rooms = safe_rooms.copy() - if multiworld.door_shuffle[player] == "simple": + if world.options.door_shuffle == "simple": forced_connections.update(simple_mandatory_connections) else: usable_safe_rooms += pokemarts - if multiworld.key_items_only[player]: + if world.options.key_items_only: usable_safe_rooms.remove("Viridian Pokemart to Viridian City") - if multiworld.door_shuffle[player] in ("full", "insanity", "decoupled"): + if world.options.door_shuffle in ("full", "insanity", "decoupled"): forced_connections.update(full_mandatory_connections) - r = multiworld.random.randint(0, 3) + r = world.random.randint(0, 3) if r == 2: forced_connections.add(("Pokemon Mansion 1F-SE to Pokemon Mansion B1F", "Pokemon Mansion 3F-SE to Pokemon Mansion 2F-E")) forced_connections.add(("Pokemon Mansion 2F to Pokemon Mansion 3F", - multiworld.random.choice(mansion_stair_destinations + mansion_dead_ends + world.random.choice(mansion_stair_destinations + mansion_dead_ends + ["Pokemon Mansion B1F to Pokemon Mansion 1F-SE"]))) - if multiworld.door_shuffle[player] == "full": + if world.options.door_shuffle == "full": forced_connections.add(("Pokemon Mansion 1F to Pokemon Mansion 2F", "Pokemon Mansion 3F to Pokemon Mansion 2F")) elif r == 3: - dead_end = multiworld.random.randint(0, 1) + dead_end = world.random.randint(0, 1) forced_connections.add(("Pokemon Mansion 3F-SE to Pokemon Mansion 2F-E", mansion_dead_ends[dead_end])) forced_connections.add(("Pokemon Mansion 1F-SE to Pokemon Mansion B1F", "Pokemon Mansion B1F to Pokemon Mansion 1F-SE")) forced_connections.add(("Pokemon Mansion 2F to Pokemon Mansion 3F", - multiworld.random.choice(mansion_stair_destinations + world.random.choice(mansion_stair_destinations + [mansion_dead_ends[dead_end ^ 1]]))) else: forced_connections.add(("Pokemon Mansion 3F-SE to Pokemon Mansion 2F-E", @@ -2062,40 +2069,40 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): forced_connections.add(("Pokemon Mansion 1F-SE to Pokemon Mansion B1F", mansion_dead_ends[r ^ 1])) forced_connections.add(("Pokemon Mansion 2F to Pokemon Mansion 3F", - multiworld.random.choice(mansion_stair_destinations + world.random.choice(mansion_stair_destinations + ["Pokemon Mansion B1F to Pokemon Mansion 1F-SE"]))) - if multiworld.door_shuffle[player] in ("insanity", "decoupled"): + if world.options.door_shuffle in ("insanity", "decoupled"): usable_safe_rooms += insanity_safe_rooms - safe_rooms_sample = multiworld.random.sample(usable_safe_rooms, 6) + safe_rooms_sample = world.random.sample(usable_safe_rooms, 6) pallet_safe_room = safe_rooms_sample[-1] - for a, b in zip(multiworld.random.sample(["Pallet Town to Player's House 1F", "Pallet Town to Oak's Lab", + for a, b in zip(world.random.sample(["Pallet Town to Player's House 1F", "Pallet Town to Oak's Lab", "Pallet Town to Rival's House"], 3), ["Oak's Lab to Pallet Town", "Player's House 1F to Pallet Town", pallet_safe_room]): one_way_forced_connections.add((a, b)) - if multiworld.door_shuffle[player] == "decoupled": + if world.options.door_shuffle == "decoupled": for a, b in zip(["Oak's Lab to Pallet Town", "Player's House 1F to Pallet Town", pallet_safe_room], - multiworld.random.sample(["Pallet Town to Player's House 1F", "Pallet Town to Oak's Lab", + world.random.sample(["Pallet Town to Player's House 1F", "Pallet Town to Oak's Lab", "Pallet Town to Rival's House"], 3)): one_way_forced_connections.add((a, b)) for a, b in zip(safari_zone_houses, safe_rooms_sample): one_way_forced_connections.add((a, b)) - if multiworld.door_shuffle[player] == "decoupled": - for a, b in zip(multiworld.random.sample(safe_rooms_sample[:-1], len(safe_rooms_sample) - 1), + if world.options.door_shuffle == "decoupled": + for a, b in zip(world.random.sample(safe_rooms_sample[:-1], len(safe_rooms_sample) - 1), safari_zone_houses): one_way_forced_connections.add((a, b)) - if multiworld.door_shuffle[player] == "simple": + if world.options.door_shuffle == "simple": # force Indigo Plateau Lobby to vanilla location on simple, otherwise shuffle with Pokemon Centers. - for a, b in zip(multiworld.random.sample(pokemon_center_entrances[0:-1], 11), pokemon_centers[0:-1]): + for a, b in zip(world.random.sample(pokemon_center_entrances[0:-1], 11), pokemon_centers[0:-1]): forced_connections.add((a, b)) forced_connections.add((pokemon_center_entrances[-1], pokemon_centers[-1])) - forced_pokemarts = multiworld.random.sample(pokemart_entrances, 8) - if multiworld.key_items_only[player]: + forced_pokemarts = world.random.sample(pokemart_entrances, 8) + if world.options.key_items_only: forced_pokemarts.sort(key=lambda i: i[0] != "Viridian Pokemart to Viridian City") for a, b in zip(forced_pokemarts, pokemarts): forced_connections.add((a, b)) @@ -2104,21 +2111,21 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): # fly / blackout warps. Rather than mess with those coordinates (besides in Pallet Town) or have players # warping outside an entrance that isn't the Pokemon Center, just always put Pokemon Centers at Pokemon # Center entrances - for a, b in zip(multiworld.random.sample(pokemon_center_entrances, 12), pokemon_centers): + for a, b in zip(world.random.sample(pokemon_center_entrances, 12), pokemon_centers): one_way_forced_connections.add((a, b)) # Ensure a Pokemart is available at the beginning of the game - if multiworld.key_items_only[player]: - one_way_forced_connections.add((multiworld.random.choice(initial_doors), + if world.options.key_items_only: + one_way_forced_connections.add((world.random.choice(initial_doors), "Viridian Pokemart to Viridian City")) elif "Pokemart" not in pallet_safe_room: - one_way_forced_connections.add((multiworld.random.choice(initial_doors), multiworld.random.choice( + one_way_forced_connections.add((world.random.choice(initial_doors), world.random.choice( [mart for mart in pokemarts if mart not in safe_rooms_sample]))) - if multiworld.warp_tile_shuffle[player] == "shuffle" or (multiworld.warp_tile_shuffle[player] == "mixed" - and multiworld.door_shuffle[player] - in ("off", "simple", "interiors")): - warps = multiworld.random.sample(silph_co_warps, len(silph_co_warps)) + if world.options.warp_tile_shuffle == "shuffle" or (world.options.warp_tile_shuffle == "mixed" + and world.options.door_shuffle + in ("off", "simple", "interiors")): + warps = world.random.sample(silph_co_warps, len(silph_co_warps)) # The only warp tiles never reachable from the stairs/elevators are the two 7F-NW warps (where the rival is) # and the final 11F-W warp. As long as the two 7F-NW warps aren't connected to each other, everything should # always be reachable. @@ -2129,9 +2136,9 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): # Shuffle Saffron Gym sections, then connect one warp from each section to the next. # Then connect the rest at random. - warps = multiworld.random.sample(saffron_gym_warps, len(saffron_gym_warps)) + warps = world.random.sample(saffron_gym_warps, len(saffron_gym_warps)) solution = ["SW", "W", "NW", "N", "NE", "E", "SE"] - multiworld.random.shuffle(solution) + world.random.shuffle(solution) solution = ["S"] + solution + ["C"] for i in range(len(solution) - 1): f, t = solution[i], solution[i + 1] @@ -2151,7 +2158,7 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): forced_connections.add((warps.pop(), warps.pop(),)) dc_destinations = None - if multiworld.door_shuffle[player] == "decoupled": + if world.options.door_shuffle == "decoupled": dc_destinations = entrances.copy() for pair in one_way_forced_connections: entrance_a = multiworld.get_entrance(pair[0], player) @@ -2179,11 +2186,11 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): full_interiors.remove(entrance_b) else: raise DoorShuffleException("Attempted to force connection with entrance not in any entrance pool, likely because it tried to force an entrance to connect twice.") - if multiworld.door_shuffle[player] == "decoupled": + if world.options.door_shuffle == "decoupled": dc_destinations.remove(entrance_a) dc_destinations.remove(entrance_b) - if multiworld.door_shuffle[player] == "simple": + if world.options.door_shuffle == "simple": def connect_connecting_interiors(interior_exits, exterior_entrances): for interior, exterior in zip(interior_exits, exterior_entrances): for a, b in zip(interior, exterior): @@ -2222,68 +2229,68 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): single_entrance_dungeon_entrances = dungeon_entrances.copy() for i in range(2): - if not multiworld.random.randint(0, 2): + if not world.random.randint(0, 2): placed_connecting_interior_dungeons.append(multi_purpose_dungeons[i]) interior_dungeon_entrances.append([multi_purpose_dungeon_entrances[i], None]) else: placed_single_entrance_dungeons.append(multi_purpose_dungeons[i]) single_entrance_dungeon_entrances.append(multi_purpose_dungeon_entrances[i]) - multiworld.random.shuffle(placed_connecting_interior_dungeons) + world.random.shuffle(placed_connecting_interior_dungeons) while placed_connecting_interior_dungeons[0] in unsafe_connecting_interior_dungeons: - multiworld.random.shuffle(placed_connecting_interior_dungeons) + world.random.shuffle(placed_connecting_interior_dungeons) connect_connecting_interiors(placed_connecting_interior_dungeons, interior_dungeon_entrances) interiors = connecting_interiors.copy() - multiworld.random.shuffle(interiors) + world.random.shuffle(interiors) while ((connecting_interiors[2] in (interiors[2], interiors[10], interiors[11]) # Dept Store at Dept Store # or Rt 16 Gate S or N and (interiors[11] in connecting_interiors[13:17] # Saffron Gate at Rt 16 Gate S or interiors[12] in connecting_interiors[13:17])) # Saffron Gate at Rt 18 Gate and interiors[15] in connecting_interiors[13:17] # Saffron Gate at Rt 7 Gate and interiors[1] in connecting_interiors[13:17] # Saffron Gate at Rt 7-8 Underground Path - and (not multiworld.tea[player]) and multiworld.worlds[player].fly_map != "Celadon City" - and multiworld.worlds[player].town_map_fly_map != "Celadon City"): - multiworld.random.shuffle(interiors) + and (not world.options.tea) and world.fly_map != "Celadon City" + and world.town_map_fly_map != "Celadon City"): + world.random.shuffle(interiors) connect_connecting_interiors(interiors, connecting_interior_entrances) placed_gyms = gyms.copy() - multiworld.random.shuffle(placed_gyms) + world.random.shuffle(placed_gyms) # Celadon Gym requires Cut access to reach the Gym Leader. There are some scenarios where its placement # could make badge placement impossible def celadon_gym_problem(): # Badgesanity or no badges needed for HM moves means gyms can go anywhere - if multiworld.badgesanity[player] or not multiworld.badges_needed_for_hm_moves[player]: + if world.options.badgesanity or not world.options.badges_needed_for_hm_moves: return False # Celadon Gym in Pewter City and need one or more badges for Viridian City gym. # No gym leaders would be reachable. - if gyms[3] == placed_gyms[0] and multiworld.viridian_gym_condition[player] > 0: + if gyms[3] == placed_gyms[0] and world.options.viridian_gym_condition > 0: return True # Celadon Gym not on Cinnabar Island or can access Viridian City gym with one badge - if not gyms[3] == placed_gyms[6] and multiworld.viridian_gym_condition[player] > 1: + if not gyms[3] == placed_gyms[6] and world.options.viridian_gym_condition > 1: return False # At this point we need to see if we can get beyond Pewter/Cinnabar with just one badge # Can get Fly access from Pewter City gym and fly beyond Pewter/Cinnabar - if multiworld.worlds[player].fly_map not in ("Pallet Town", "Viridian City", "Cinnabar Island", - "Indigo Plateau") and multiworld.worlds[player].town_map_fly_map not in ("Pallet Town", + if world.fly_map not in ("Pallet Town", "Viridian City", "Cinnabar Island", + "Indigo Plateau") and world.town_map_fly_map not in ("Pallet Town", "Viridian City", "Cinnabar Island", "Indigo Plateau"): return False # Route 3 condition is boulder badge but Mt Moon entrance leads to safe dungeons or Rock Tunnel - if multiworld.route_3_condition[player] == "boulder_badge" and placed_connecting_interior_dungeons[2] not \ + if world.options.route_3_condition == "boulder_badge" and placed_connecting_interior_dungeons[2] not \ in (unsafe_connecting_interior_dungeons[0], unsafe_connecting_interior_dungeons[2]): return False # Route 3 condition is Defeat Brock and he is in Pewter City, or any other condition besides Boulder Badge. # Any badge can land in Pewter City, so the only problematic dungeon at Mt Moon is Seafoam Islands since # it requires two badges - if (((multiworld.route_3_condition[player] == "defeat_brock" and gyms[0] == placed_gyms[0]) - or multiworld.route_3_condition[player] not in ("defeat_brock", "boulder_badge")) + if (((world.options.route_3_condition == "defeat_brock" and gyms[0] == placed_gyms[0]) + or world.options.route_3_condition not in ("defeat_brock", "boulder_badge")) and placed_connecting_interior_dungeons[2] != unsafe_connecting_interior_dungeons[0]): return False @@ -2305,31 +2312,31 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): and interiors[0] in connecting_interiors[13:17] # Saffron Gate at Underground Path North South and interiors[13] in connecting_interiors[13:17] # Saffron Gate at Route 5 Saffron Gate and multi_purpose_dungeons[0] == placed_connecting_interior_dungeons[4] # Pokémon Mansion at Rock Tunnel, which is - and (not multiworld.tea[player]) # not traversable backwards - and multiworld.route_3_condition[player] == "defeat_brock" - and multiworld.worlds[player].fly_map != "Cerulean City" - and multiworld.worlds[player].town_map_fly_map != "Cerulean City"): + and (not world.options.tea) # not traversable backwards + and world.options.route_3_condition == "defeat_brock" + and world.fly_map != "Cerulean City" + and world.town_map_fly_map != "Cerulean City"): return True while celadon_gym_problem() or cerulean_city_problem(): - multiworld.random.shuffle(placed_gyms) + world.random.shuffle(placed_gyms) connect_interiors(placed_gyms, gym_entrances) - multiworld.random.shuffle(placed_single_entrance_dungeons) + world.random.shuffle(placed_single_entrance_dungeons) while dungeons[4] == placed_single_entrance_dungeons[0]: # Pokémon Tower at Silph Co - multiworld.random.shuffle(placed_single_entrance_dungeons) + world.random.shuffle(placed_single_entrance_dungeons) connect_interiors(placed_single_entrance_dungeons, single_entrance_dungeon_entrances) remaining_entrances = [entrance for entrance in entrances if outdoor_map(entrance.parent_region.name)] - multiworld.random.shuffle(remaining_entrances) + world.random.shuffle(remaining_entrances) remaining_interiors = [entrance for entrance in entrances if entrance not in remaining_entrances] for entrance_a, entrance_b in zip(remaining_entrances, remaining_interiors): entrance_a.connect(entrance_b) entrance_b.connect(entrance_a) - elif multiworld.door_shuffle[player]: - if multiworld.door_shuffle[player] == "full": - multiworld.random.shuffle(full_interiors) + elif world.options.door_shuffle: + if world.options.door_shuffle == "full": + world.random.shuffle(full_interiors) def search_for_exit(entrance, region, checked_regions): checked_regions.add(region) @@ -2344,6 +2351,7 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): return found_exit return None + e = multiworld.get_entrance("Underground Path Route 5 to Underground Path North South", player) while True: for entrance_a in full_interiors: if search_for_exit(entrance_a, entrance_a.parent_region, set()) is None: @@ -2363,7 +2371,7 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): break loop_out_interiors = [] - multiworld.random.shuffle(entrances) + world.random.shuffle(entrances) for entrance in reversed(entrances): if not outdoor_map(entrance.parent_region.name): found_exit = search_for_exit(entrance, entrance.parent_region, set()) @@ -2380,26 +2388,26 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): entrance_a.connect(entrance_b) entrance_b.connect(entrance_a) - elif multiworld.door_shuffle[player] == "interiors": + elif world.options.door_shuffle == "interiors": loop_out_interiors = [[multiworld.get_entrance(e[0], player), multiworld.get_entrance(e[1], player)] for e - in multiworld.random.sample(unsafe_connecting_interior_dungeons - + safe_connecting_interior_dungeons, 2)] + in world.random.sample(unsafe_connecting_interior_dungeons + + safe_connecting_interior_dungeons, 2)] entrances.remove(loop_out_interiors[0][1]) entrances.remove(loop_out_interiors[1][1]) - if not multiworld.badgesanity[player]: - multiworld.random.shuffle(badges) - while badges[3].name == "Cascade Badge" and multiworld.badges_needed_for_hm_moves[player]: - multiworld.random.shuffle(badges) + if not world.options.badgesanity: + world.random.shuffle(badges) + while badges[3].name == "Cascade Badge" and world.options.badges_needed_for_hm_moves: + world.random.shuffle(badges) for badge, loc in zip(badges, badge_locs): loc.place_locked_item(badge) state = multiworld.state.copy() for item, data in item_table.items(): if (data.id or item in poke_data.pokemon_data) and data.classification == ItemClassification.progression \ - and ("Badge" not in item or multiworld.badgesanity[player]): + and ("Badge" not in item or world.options.badgesanity): state.collect(world.create_item(item)) - multiworld.random.shuffle(entrances) + world.random.shuffle(entrances) reachable_entrances = [] relevant_events = [ @@ -2415,13 +2423,13 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): "Victory Road Boulder", "Silph Co Liberated", ] - if multiworld.robbed_house_officer[player]: + if world.options.robbed_house_officer: relevant_events.append("Help Bill") - if multiworld.tea[player]: + if world.options.tea: relevant_events.append("Vending Machine Drinks") - if multiworld.route_3_condition[player] == "defeat_brock": + if world.options.route_3_condition == "defeat_brock": relevant_events.append("Defeat Brock") - elif multiworld.route_3_condition[player] == "defeat_any_gym": + elif world.options.route_3_condition == "defeat_any_gym": relevant_events += [ "Defeat Brock", "Defeat Misty", @@ -2447,7 +2455,7 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): def dead_end(e): if e.can_reach(state): return True - elif multiworld.door_shuffle[player] == "decoupled": + elif world.options.door_shuffle == "decoupled": # Any unreachable exit in decoupled is not a dead end return False region = e.parent_region @@ -2482,10 +2490,10 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): state.update_reachable_regions(player) state.sweep_for_advancements(locations=event_locations) - multiworld.random.shuffle(entrances) + world.random.shuffle(entrances) - if multiworld.door_shuffle[player] == "decoupled": - multiworld.random.shuffle(dc_destinations) + if world.options.door_shuffle == "decoupled": + world.random.shuffle(dc_destinations) else: entrances.sort(key=lambda e: e.name not in entrance_only) @@ -2502,15 +2510,15 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): is_outdoor_map = outdoor_map(entrance_a.parent_region.name) - if multiworld.door_shuffle[player] in ("interiors", "full") or len(entrances) != len(reachable_entrances): + if world.options.door_shuffle in ("interiors", "full") or len(entrances) != len(reachable_entrances): find_dead_end = False if (len(reachable_entrances) > - (1 if multiworld.door_shuffle[player] in ("insanity", "decoupled") else 8) and len(entrances) + (1 if world.options.door_shuffle in ("insanity", "decoupled") else 8) and len(entrances) <= (starting_entrances - 3)): find_dead_end = True - if (multiworld.door_shuffle[player] in ("interiors", "full") and len(entrances) < 48 + if (world.options.door_shuffle in ("interiors", "full") and len(entrances) < 48 and not is_outdoor_map): # Try to prevent a situation where the only remaining outdoor entrances are ones that cannot be # reached except by connecting directly to it. @@ -2519,9 +2527,9 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): in reachable_entrances if not outdoor_map(entrance.parent_region.name)]) > 1: find_dead_end = True - if multiworld.door_shuffle[player] == "decoupled": + if world.options.door_shuffle == "decoupled": destinations = dc_destinations - elif multiworld.door_shuffle[player] in ("interiors", "full"): + elif world.options.door_shuffle in ("interiors", "full"): destinations = [entrance for entrance in entrances if outdoor_map(entrance.parent_region.name) is not is_outdoor_map] if not destinations: @@ -2531,7 +2539,7 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): destinations.sort(key=lambda e: e == entrance_a) for entrance in destinations: - if (dead_end(entrance) is find_dead_end and (multiworld.door_shuffle[player] != "decoupled" + if (dead_end(entrance) is find_dead_end and (world.options.door_shuffle != "decoupled" or entrance.parent_region.name.split("-")[0] != entrance_a.parent_region.name.split("-")[0])): entrance_b = entrance @@ -2540,28 +2548,28 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): else: entrance_b = destinations.pop(0) - if multiworld.door_shuffle[player] in ("interiors", "full"): + if world.options.door_shuffle in ("interiors", "full"): # on Interiors/Full, the destinations variable does not point to the entrances list, so we need to # remove from that list here. entrances.remove(entrance_b) else: # Everything is reachable. Just start connecting the rest of the doors at random. - if multiworld.door_shuffle[player] == "decoupled": + if world.options.door_shuffle == "decoupled": entrance_b = dc_destinations.pop(0) else: entrance_b = entrances.pop(0) entrance_a.connect(entrance_b) - if multiworld.door_shuffle[player] != "decoupled": + if world.options.door_shuffle != "decoupled": entrance_b.connect(entrance_a) - if multiworld.door_shuffle[player] in ("interiors", "full"): + if world.options.door_shuffle in ("interiors", "full"): for pair in loop_out_interiors: pair[1].connected_region = pair[0].connected_region pair[1].parent_region.entrances.append(pair[0]) pair[1].target = pair[0].target - if multiworld.door_shuffle[player]: + if world.options.door_shuffle: for region in multiworld.get_regions(player): checked_regions = {region} @@ -2585,10 +2593,10 @@ def door_shuffle(world, multiworld, player, badges, badge_locs): region.entrance_hint = check_region(region) -def connect(world: MultiWorld, player: int, source: str, target: str, rule: callable = lambda state: True, +def connect(multiworld: MultiWorld, player: int, source: str, target: str, rule: callable = lambda state: True, one_way=False, name=None): - source_region = world.get_region(source, player) - target_region = world.get_region(target, player) + source_region = multiworld.get_region(source, player) + target_region = multiworld.get_region(target, player) if name is None: name = source + " to " + target @@ -2604,7 +2612,7 @@ def connect(world: MultiWorld, player: int, source: str, target: str, rule: call source_region.exits.append(connection) connection.connect(target_region) if not one_way: - connect(world, player, target, source, rule, True) + connect(multiworld, player, target, source, rule, True) class PokemonRBWarp(Entrance): @@ -2621,7 +2629,7 @@ class PokemonRBWarp(Entrance): if self.connected_region is None: return False if "Elevator" in self.parent_region.name and ( - (state.multiworld.all_elevators_locked[self.player] + (state.multiworld.worlds[self.player].options.all_elevators_locked or "Rocket Hideout" in self.parent_region.name) and not state.has("Lift Key", self.player)): return False diff --git a/worlds/pokemon_rb/rom.py b/worlds/pokemon_rb/rom.py index b6c1221a..5ebd204c 100644 --- a/worlds/pokemon_rb/rom.py +++ b/worlds/pokemon_rb/rom.py @@ -13,22 +13,22 @@ from .regions import PokemonRBWarp, map_ids, town_map_coords from . import poke_data -def write_quizzes(self, data, random): +def write_quizzes(world, data, random): def get_quiz(q, a): if q == 0: r = random.randint(0, 3) if r == 0: - mon = self.trade_mons["Trade_Dux"] + mon = world.trade_mons["Trade_Dux"] text = "A woman inVermilion City" elif r == 1: - mon = self.trade_mons["Trade_Lola"] + mon = world.trade_mons["Trade_Lola"] text = "A man inCerulean City" elif r == 2: - mon = self.trade_mons["Trade_Marcel"] + mon = world.trade_mons["Trade_Marcel"] text = "Someone on Route 2" elif r == 3: - mon = self.trade_mons["Trade_Spot"] + mon = world.trade_mons["Trade_Spot"] text = "Someone on Route 5" if not a: answers.append(0) @@ -38,21 +38,30 @@ def write_quizzes(self, data, random): return encode_text(f"{text}was looking for{mon}?") elif q == 1: - for location in self.multiworld.get_filled_locations(): - if location.item.name == "Secret Key" and location.item.player == self.player: + for location in world.multiworld.get_filled_locations(): + if location.item.name == "Secret Key" and location.item.player == world.player: break - player_name = self.multiworld.player_name[location.player] + player_name = world.multiworld.player_name[location.player] if not a: - if len(self.multiworld.player_name) > 1: + if len(world.multiworld.player_name) > 1: old_name = player_name while old_name == player_name: - player_name = random.choice(list(self.multiworld.player_name.values())) + player_name = random.choice(list(world.multiworld.player_name.values())) else: return encode_text("You're playingin a multiworldwith otherplayers?") - if player_name == self.multiworld.player_name[self.player]: - player_name = "yourself" - player_name = encode_text(player_name, force=True, safety=True) - return encode_text(f"The Secret Key wasfound by") + player_name + encode_text("") + if world.multiworld.get_entrance( + "Cinnabar Island-G to Cinnabar Gym", world.player).connected_region.name == "Cinnabar Gym": + if player_name == world.multiworld.player_name[world.player]: + player_name = "yourself" + player_name = encode_text(player_name, force=True, safety=True) + return encode_text(f"The Secret Key wasfound by") + player_name + encode_text("?") + else: + # Might not have found it yet + if player_name == world.multiworld.player_name[world.player]: + return encode_text(f"The Secret Key wasplaced inyour own world?") + player_name = encode_text(player_name, force=True, safety=True) + return (encode_text(f"The Secret Key wasplaced in") + player_name + + encode_text("'sworld?")) elif q == 2: if a: return encode_text(f"#mon ispronouncedPo-kay-mon?") @@ -62,8 +71,8 @@ def write_quizzes(self, data, random): else: return encode_text(f"#mon ispronouncedPo-kuh-mon?") elif q == 3: - starters = [" ".join(self.multiworld.get_location( - f"Oak's Lab - Starter {i}", self.player).item.name.split(" ")[1:]) for i in range(1, 4)] + starters = [" ".join(world.multiworld.get_location( + f"Oak's Lab - Starter {i}", world.player).item.name.split(" ")[1:]) for i in range(1, 4)] mon = random.choice(starters) nots = random.choice(range(8, 16, 2)) if random.randint(0, 1): @@ -82,10 +91,10 @@ def write_quizzes(self, data, random): return encode_text(text) elif q == 4: if a: - tm_text = self.local_tms[27] + tm_text = world.local_tms[27] else: - if self.multiworld.randomize_tm_moves[self.player]: - wrong_tms = self.local_tms.copy() + if world.options.randomize_tm_moves: + wrong_tms = world.local_tms.copy() wrong_tms.pop(27) tm_text = random.choice(wrong_tms) else: @@ -102,12 +111,36 @@ def write_quizzes(self, data, random): i = random.randint(0, random.choice([9, 99])) return encode_text(f"POLIWAG evolves {i}times?") elif q == 7: - entity = "Motor Carrier" - if not a: - entity = random.choice(["Driver", "Shipper"]) - return encode_text("Title 49 of theU.S. Code ofFederalRegulations part397.67 states" - f"that the{entity}is responsiblefor planningroutes when" - "hazardousmaterials aretransported?") + q2 = random.randint(0, 2) + if q2 == 0: + entity = "Motor Carrier" + if not a: + entity = random.choice(["Driver", "Shipper"]) + return encode_text("Title 49 of theU.S. Code ofFederalRegulations part397.67 " + f"statesthat the{entity}is responsiblefor planning" + "routes whenhazardousmaterials aretransported?") + elif q2 == 1: + if a: + state = random.choice( + ['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', + 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', + 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', + 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Jersey', 'New Mexico', + 'New York', 'North Carolina', 'North Dakota', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', + 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', + 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming']) + else: + state = "New Hampshire" + return encode_text( + f"As of 2024,{state}has a lawrequiring allfront seat vehicleoccupants to useseatbelts?") + elif q2 == 2: + if a: + country = random.choice(["The United States", "Mexico", "Canada", "Germany", "France", "China", + "Russia", "Spain", "Brazil", "Ukraine", "Saudi Arabia", "Egypt"]) + else: + country = random.choice(["The U.K.", "Pakistan", "India", "Japan", "Australia", + "New Zealand", "Thailand"]) + return encode_text(f"As of 2020,drivers in{country}drive on theright side ofthe road?") elif q == 8: mon = random.choice(list(poke_data.evolution_levels.keys())) level = poke_data.evolution_levels[mon] @@ -115,17 +148,17 @@ def write_quizzes(self, data, random): level += random.choice(range(1, 6)) * random.choice((-1, 1)) return encode_text(f"{mon} evolvesat level {level}?") elif q == 9: - move = random.choice(list(self.local_move_data.keys())) - actual_type = self.local_move_data[move]["type"] + move = random.choice(list(world.local_move_data.keys())) + actual_type = world.local_move_data[move]["type"] question_type = actual_type while question_type == actual_type and not a: question_type = random.choice(list(poke_data.type_ids.keys())) return encode_text(f"{move} is{question_type} type?") elif q == 10: mon = random.choice(list(poke_data.pokemon_data.keys())) - actual_type = self.local_poke_data[mon][random.choice(("type1", "type2"))] + actual_type = world.local_poke_data[mon][random.choice(("type1", "type2"))] question_type = actual_type - while question_type in [self.local_poke_data[mon]["type1"], self.local_poke_data[mon]["type2"]] and not a: + while question_type in [world.local_poke_data[mon]["type1"], world.local_poke_data[mon]["type2"]] and not a: question_type = random.choice(list(poke_data.type_ids.keys())) return encode_text(f"{mon} is{question_type} type?") elif q == 11: @@ -147,8 +180,8 @@ def write_quizzes(self, data, random): return encode_text(f"{equation}= {question_result}?") elif q == 12: route = random.choice((12, 16)) - actual_mon = self.multiworld.get_location(f"Route {route} - Sleeping Pokemon", - self.player).item.name.split("Static ")[1] + actual_mon = world.multiworld.get_location(f"Route {route} - Sleeping Pokemon", + world.player).item.name.split("Static ")[1] question_mon = actual_mon while question_mon == actual_mon and not a: question_mon = random.choice(list(poke_data.pokemon_data.keys())) @@ -157,7 +190,7 @@ def write_quizzes(self, data, random): type1 = random.choice(list(poke_data.type_ids.keys())) type2 = random.choice(list(poke_data.type_ids.keys())) eff_msgs = ["super effective", "no ", "not veryeffective", "normal "] - for matchup in self.type_chart: + for matchup in world.type_chart: if matchup[0] == type1 and matchup[1] == type2: if matchup[2] > 10: eff = eff_msgs[0] @@ -175,15 +208,25 @@ def write_quizzes(self, data, random): eff = random.choice(eff_msgs) return encode_text(f"{type1} deals{eff}damage to{type2} type?") elif q == 14: - fossil_level = self.multiworld.get_location("Fossil Level - Trainer Parties", - self.player).party_data[0]['level'] + fossil_level = world.multiworld.get_location("Fossil Level - Trainer Parties", + world.player).party_data[0]['level'] if not a: fossil_level += random.choice((-5, 5)) return encode_text(f"Fossil #MONrevive at level{fossil_level}?") + elif q == 15: + if a: + fodmap = random.choice(["garlic", "onion", "milk", "watermelon", "cherries", "wheat", "barley", + "pistachios", "cashews", "kidney beans", "apples", "honey"]) + else: + fodmap = random.choice(["carrots", "potatoes", "oranges", "pineapple", "blueberries", "parmesan", + "eggs", "beef", "chicken", "oat", "rice", "maple syrup", "peanuts"]) + are_is = "are" if fodmap[-1] == "s" else "is" + return encode_text(f"According toMonash Uni.,{fodmap} {are_is}considered highin FODMAPs?") answers = [random.randint(0, 1) for _ in range(6)] - questions = random.sample((range(0, 15)), 6) + questions = random.sample((range(0, 16)), 6) + question_texts = [] for i, question in enumerate(questions): question_texts.append(get_quiz(question, answers[i])) @@ -193,9 +236,9 @@ def write_quizzes(self, data, random): write_bytes(data, question_texts[i], rom_addresses[f"Text_Quiz_{quiz}"]) -def generate_output(self, output_directory: str): - random = self.multiworld.per_slot_randoms[self.player] - game_version = self.multiworld.game_version[self.player].current_key +def generate_output(world, output_directory: str): + random = world.random + game_version = world.options.game_version.current_key data = bytes(get_base_rom_bytes(game_version)) base_patch = pkgutil.get_data(__name__, f'basepatch_{game_version}.bsdiff4') @@ -205,8 +248,8 @@ def generate_output(self, output_directory: str): basemd5 = hashlib.md5() basemd5.update(data) - pallet_connections = {entrance: self.multiworld.get_entrance(f"Pallet Town to {entrance}", - self.player).connected_region.name for + pallet_connections = {entrance: world.multiworld.get_entrance(f"Pallet Town to {entrance}", + world.player).connected_region.name for entrance in ["Player's House 1F", "Oak's Lab", "Rival's House"]} paths = None @@ -222,11 +265,11 @@ def generate_output(self, output_directory: str): elif pallet_connections["Oak's Lab"] == "Player's House 1F": write_bytes(data, [0x5F, 0xC7, 0x0C, 0x0C, 0x00, 0x00], rom_addresses["Pallet_Fly_Coords"]) - for region in self.multiworld.get_regions(self.player): + for region in world.multiworld.get_regions(world.player): for entrance in region.exits: if isinstance(entrance, PokemonRBWarp): - self.multiworld.spoiler.set_entrance(entrance.name, entrance.connected_region.name, "entrance", - self.player) + world.multiworld.spoiler.set_entrance(entrance.name, entrance.connected_region.name, "entrance", + world.player) warp_ids = (entrance.warp_id,) if isinstance(entrance.warp_id, int) else entrance.warp_id warp_to_ids = (entrance.target,) if isinstance(entrance.target, int) else entrance.target for i, warp_id in enumerate(warp_ids): @@ -241,32 +284,32 @@ def generate_output(self, output_directory: str): data[address] = 0 if "Elevator" in connected_map_name else warp_to_ids[i] data[address + 1] = map_ids[connected_map_name] - if self.multiworld.door_shuffle[self.player] == "simple": + if world.options.door_shuffle == "simple": for (entrance, _, _, map_coords_entries, map_name, _) in town_map_coords.values(): - destination = self.multiworld.get_entrance(entrance, self.player).connected_region.name + destination = world.multiworld.get_entrance(entrance, world.player).connected_region.name (_, x, y, _, _, map_order_entry) = town_map_coords[destination] for map_coord_entry in map_coords_entries: data[rom_addresses["Town_Map_Coords"] + (map_coord_entry * 4) + 1] = (y << 4) | x data[rom_addresses["Town_Map_Order"] + map_order_entry] = map_ids[map_name] - if not self.multiworld.key_items_only[self.player]: + if not world.options.key_items_only: for i, gym_leader in enumerate(("Pewter Gym - Brock TM", "Cerulean Gym - Misty TM", "Vermilion Gym - Lt. Surge TM", "Celadon Gym - Erika TM", "Fuchsia Gym - Koga TM", "Saffron Gym - Sabrina TM", "Cinnabar Gym - Blaine TM", "Viridian Gym - Giovanni TM")): - item_name = self.multiworld.get_location(gym_leader, self.player).item.name + item_name = world.multiworld.get_location(gym_leader, world.player).item.name if item_name.startswith("TM"): try: tm = int(item_name[2:4]) - move = poke_data.moves[self.local_tms[tm - 1]]["id"] + move = poke_data.moves[world.local_tms[tm - 1]]["id"] data[rom_addresses["Gym_Leader_Moves"] + (2 * i)] = move except KeyError: pass def set_trade_mon(address, loc): - mon = self.multiworld.get_location(loc, self.player).item.name + mon = world.multiworld.get_location(loc, world.player).item.name data[rom_addresses[address]] = poke_data.pokemon_data[mon]["id"] - self.trade_mons[address] = mon + world.trade_mons[address] = mon if game_version == "red": set_trade_mon("Trade_Terry", "Safari Zone Center - Wild Pokemon - 5") @@ -282,10 +325,10 @@ def generate_output(self, output_directory: str): set_trade_mon("Trade_Doris", "Cerulean Cave 1F - Wild Pokemon - 9") set_trade_mon("Trade_Crinkles", "Route 12 - Wild Pokemon - 4") - data[rom_addresses['Fly_Location']] = self.fly_map_code - data[rom_addresses['Map_Fly_Location']] = self.town_map_fly_map_code + data[rom_addresses['Fly_Location']] = world.fly_map_code + data[rom_addresses['Map_Fly_Location']] = world.town_map_fly_map_code - if self.multiworld.fix_combat_bugs[self.player]: + if world.options.fix_combat_bugs: data[rom_addresses["Option_Fix_Combat_Bugs"]] = 1 data[rom_addresses["Option_Fix_Combat_Bugs_Focus_Energy"]] = 0x28 # jr z data[rom_addresses["Option_Fix_Combat_Bugs_HP_Drain_Dream_Eater"]] = 0x1A # ld a, (de) @@ -298,25 +341,25 @@ def generate_output(self, output_directory: str): data[rom_addresses["Option_Fix_Combat_Bugs_Heal_Effect"] + 1] = 5 # 5 bytes ahead data[rom_addresses["Option_Fix_Combat_Bugs_Heal_Stat_Modifiers"]] = 1 - if self.multiworld.poke_doll_skip[self.player] == "in_logic": + if world.options.poke_doll_skip == "in_logic": data[rom_addresses["Option_Silph_Scope_Skip"]] = 0x00 # nop data[rom_addresses["Option_Silph_Scope_Skip"] + 1] = 0x00 # nop data[rom_addresses["Option_Silph_Scope_Skip"] + 2] = 0x00 # nop - if self.multiworld.bicycle_gate_skips[self.player] == "patched": + if world.options.bicycle_gate_skips == "patched": data[rom_addresses["Option_Route_16_Gate_Fix"]] = 0x00 # nop data[rom_addresses["Option_Route_16_Gate_Fix"] + 1] = 0x00 # nop data[rom_addresses["Option_Route_18_Gate_Fix"]] = 0x00 # nop data[rom_addresses["Option_Route_18_Gate_Fix"] + 1] = 0x00 # nop - if self.multiworld.door_shuffle[self.player]: + if world.options.door_shuffle: data[rom_addresses["Entrance_Shuffle_Fuji_Warp"]] = 1 # prevent warping to Fuji's House from Pokemon Tower 7F - if self.multiworld.all_elevators_locked[self.player]: + if world.options.all_elevators_locked: data[rom_addresses["Option_Locked_Elevator_Celadon"]] = 0x20 # jr nz data[rom_addresses["Option_Locked_Elevator_Silph"]] = 0x20 # jr nz - if self.multiworld.tea[self.player].value: + if world.options.tea: data[rom_addresses["Option_Tea"]] = 1 data[rom_addresses["Guard_Drink_List"]] = 0x54 data[rom_addresses["Guard_Drink_List"] + 1] = 0 @@ -325,90 +368,94 @@ def generate_output(self, output_directory: str): "Oh wait there,the road's closed."), rom_addresses["Text_Saffron_Gate"]) + data[rom_addresses["Tea_Key_Item_A"]] = 0x28 # jr .z + data[rom_addresses["Tea_Key_Item_B"]] = 0x28 # jr .z + data[rom_addresses["Tea_Key_Item_C"]] = 0x28 # jr .z + data[rom_addresses["Fossils_Needed_For_Second_Item"]] = ( - self.multiworld.second_fossil_check_condition[self.player].value) + world.options.second_fossil_check_condition.value) - data[rom_addresses["Option_Lose_Money"]] = int(not self.multiworld.lose_money_on_blackout[self.player].value) + data[rom_addresses["Option_Lose_Money"]] = int(not world.options.lose_money_on_blackout.value) - if self.multiworld.extra_key_items[self.player]: + if world.options.extra_key_items: data[rom_addresses['Option_Extra_Key_Items_A']] = 1 data[rom_addresses['Option_Extra_Key_Items_B']] = 1 data[rom_addresses['Option_Extra_Key_Items_C']] = 1 data[rom_addresses['Option_Extra_Key_Items_D']] = 1 - data[rom_addresses["Option_Split_Card_Key"]] = self.multiworld.split_card_key[self.player].value - data[rom_addresses["Option_Blind_Trainers"]] = round(self.multiworld.blind_trainers[self.player].value * 2.55) - data[rom_addresses["Option_Cerulean_Cave_Badges"]] = self.multiworld.cerulean_cave_badges_condition[self.player].value - data[rom_addresses["Option_Cerulean_Cave_Key_Items"]] = self.multiworld.cerulean_cave_key_items_condition[self.player].total - write_bytes(data, encode_text(str(self.multiworld.cerulean_cave_badges_condition[self.player].value)), rom_addresses["Text_Cerulean_Cave_Badges"]) - write_bytes(data, encode_text(str(self.multiworld.cerulean_cave_key_items_condition[self.player].total) + " key items."), rom_addresses["Text_Cerulean_Cave_Key_Items"]) - data[rom_addresses['Option_Encounter_Minimum_Steps']] = self.multiworld.minimum_steps_between_encounters[self.player].value - data[rom_addresses['Option_Route23_Badges']] = self.multiworld.victory_road_condition[self.player].value - data[rom_addresses['Option_Victory_Road_Badges']] = self.multiworld.route_22_gate_condition[self.player].value - data[rom_addresses['Option_Elite_Four_Pokedex']] = self.multiworld.elite_four_pokedex_condition[self.player].total - data[rom_addresses['Option_Elite_Four_Key_Items']] = self.multiworld.elite_four_key_items_condition[self.player].total - data[rom_addresses['Option_Elite_Four_Badges']] = self.multiworld.elite_four_badges_condition[self.player].value - write_bytes(data, encode_text(str(self.multiworld.elite_four_badges_condition[self.player].value)), rom_addresses["Text_Elite_Four_Badges"]) - write_bytes(data, encode_text(str(self.multiworld.elite_four_key_items_condition[self.player].total) + " key items, and"), rom_addresses["Text_Elite_Four_Key_Items"]) - write_bytes(data, encode_text(str(self.multiworld.elite_four_pokedex_condition[self.player].total) + " #MON"), rom_addresses["Text_Elite_Four_Pokedex"]) - write_bytes(data, encode_text(str(self.total_key_items), length=2), rom_addresses["Trainer_Screen_Total_Key_Items"]) + data[rom_addresses["Option_Split_Card_Key"]] = world.options.split_card_key.value + data[rom_addresses["Option_Blind_Trainers"]] = round(world.options.blind_trainers.value * 2.55) + data[rom_addresses["Option_Cerulean_Cave_Badges"]] = world.options.cerulean_cave_badges_condition.value + data[rom_addresses["Option_Cerulean_Cave_Key_Items"]] = world.options.cerulean_cave_key_items_condition.total + write_bytes(data, encode_text(str(world.options.cerulean_cave_badges_condition.value)), rom_addresses["Text_Cerulean_Cave_Badges"]) + write_bytes(data, encode_text(str(world.options.cerulean_cave_key_items_condition.total) + " key items."), rom_addresses["Text_Cerulean_Cave_Key_Items"]) + data[rom_addresses['Option_Encounter_Minimum_Steps']] = world.options.minimum_steps_between_encounters.value + data[rom_addresses['Option_Route23_Badges']] = world.options.victory_road_condition.value + data[rom_addresses['Option_Victory_Road_Badges']] = world.options.route_22_gate_condition.value + data[rom_addresses['Option_Elite_Four_Pokedex']] = world.options.elite_four_pokedex_condition.total + data[rom_addresses['Option_Elite_Four_Key_Items']] = world.options.elite_four_key_items_condition.total + data[rom_addresses['Option_Elite_Four_Badges']] = world.options.elite_four_badges_condition.value + write_bytes(data, encode_text(str(world.options.elite_four_badges_condition.value)), rom_addresses["Text_Elite_Four_Badges"]) + write_bytes(data, encode_text(str(world.options.elite_four_key_items_condition.total) + " key items, and"), rom_addresses["Text_Elite_Four_Key_Items"]) + write_bytes(data, encode_text(str(world.options.elite_four_pokedex_condition.total) + " #MON"), rom_addresses["Text_Elite_Four_Pokedex"]) + write_bytes(data, encode_text(str(world.total_key_items), length=2), rom_addresses["Trainer_Screen_Total_Key_Items"]) - data[rom_addresses['Option_Viridian_Gym_Badges']] = self.multiworld.viridian_gym_condition[self.player].value - data[rom_addresses['Option_EXP_Modifier']] = self.multiworld.exp_modifier[self.player].value - if not self.multiworld.require_item_finder[self.player]: + data[rom_addresses['Option_Viridian_Gym_Badges']] = world.options.viridian_gym_condition.value + data[rom_addresses['Option_EXP_Modifier']] = world.options.exp_modifier.value + if not world.options.require_item_finder: data[rom_addresses['Option_Itemfinder']] = 0 # nop - if self.multiworld.extra_strength_boulders[self.player]: + if world.options.extra_strength_boulders: for i in range(0, 3): data[rom_addresses['Option_Boulders'] + (i * 3)] = 0x15 - if self.multiworld.extra_key_items[self.player]: + if world.options.extra_key_items: for i in range(0, 4): data[rom_addresses['Option_Rock_Tunnel_Extra_Items'] + (i * 3)] = 0x15 - if self.multiworld.old_man[self.player] == "open_viridian_city": + if world.options.old_man == "open_viridian_city": data[rom_addresses['Option_Old_Man']] = 0x11 data[rom_addresses['Option_Old_Man_Lying']] = 0x15 - data[rom_addresses['Option_Route3_Guard_B']] = self.multiworld.route_3_condition[self.player].value - if self.multiworld.route_3_condition[self.player] == "open": + data[rom_addresses['Option_Route3_Guard_B']] = world.options.route_3_condition.value + if world.options.route_3_condition == "open": data[rom_addresses['Option_Route3_Guard_A']] = 0x11 - if not self.multiworld.robbed_house_officer[self.player]: + if not world.options.robbed_house_officer: data[rom_addresses['Option_Trashed_House_Guard_A']] = 0x15 data[rom_addresses['Option_Trashed_House_Guard_B']] = 0x11 - if self.multiworld.require_pokedex[self.player]: + if world.options.require_pokedex: data[rom_addresses["Require_Pokedex_A"]] = 1 data[rom_addresses["Require_Pokedex_B"]] = 1 data[rom_addresses["Require_Pokedex_C"]] = 1 else: data[rom_addresses["Require_Pokedex_D"]] = 0x18 # jr - if self.multiworld.dexsanity[self.player]: + if world.options.dexsanity: data[rom_addresses["Option_Dexsanity_A"]] = 1 data[rom_addresses["Option_Dexsanity_B"]] = 1 - if self.multiworld.all_pokemon_seen[self.player]: + if world.options.all_pokemon_seen: data[rom_addresses["Option_Pokedex_Seen"]] = 1 - money = str(self.multiworld.starting_money[self.player].value).zfill(6) + money = str(world.options.starting_money.value).zfill(6) data[rom_addresses["Starting_Money_High"]] = int(money[:2], 16) data[rom_addresses["Starting_Money_Middle"]] = int(money[2:4], 16) data[rom_addresses["Starting_Money_Low"]] = int(money[4:], 16) data[rom_addresses["Text_Badges_Needed_Viridian_Gym"]] = encode_text( - str(self.multiworld.viridian_gym_condition[self.player].value))[0] + str(world.options.viridian_gym_condition.value))[0] data[rom_addresses["Text_Rt23_Badges_A"]] = encode_text( - str(self.multiworld.victory_road_condition[self.player].value))[0] + str(world.options.victory_road_condition.value))[0] data[rom_addresses["Text_Rt23_Badges_B"]] = encode_text( - str(self.multiworld.victory_road_condition[self.player].value))[0] + str(world.options.victory_road_condition.value))[0] data[rom_addresses["Text_Rt23_Badges_C"]] = encode_text( - str(self.multiworld.victory_road_condition[self.player].value))[0] + str(world.options.victory_road_condition.value))[0] data[rom_addresses["Text_Rt23_Badges_D"]] = encode_text( - str(self.multiworld.victory_road_condition[self.player].value))[0] + str(world.options.victory_road_condition.value))[0] data[rom_addresses["Text_Badges_Needed"]] = encode_text( - str(self.multiworld.elite_four_badges_condition[self.player].value))[0] + str(world.options.elite_four_badges_condition.value))[0] write_bytes(data, encode_text( - " ".join(self.multiworld.get_location("Route 4 Pokemon Center - Pokemon For Sale", self.player).item.name.upper().split()[1:])), + " ".join(world.multiworld.get_location("Route 4 Pokemon Center - Pokemon For Sale", world.player).item.name.upper().split()[1:])), rom_addresses["Text_Magikarp_Salesman"]) - if self.multiworld.badges_needed_for_hm_moves[self.player].value == 0: + if world.options.badges_needed_for_hm_moves.value == 0: for hm_move in poke_data.hm_moves: write_bytes(data, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), rom_addresses["HM_" + hm_move + "_Badge_a"]) - elif self.extra_badges: + elif world.extra_badges: written_badges = {} - for hm_move, badge in self.extra_badges.items(): + for hm_move, badge in world.extra_badges.items(): data[rom_addresses["HM_" + hm_move + "_Badge_b"]] = {"Boulder Badge": 0x47, "Cascade Badge": 0x4F, "Thunder Badge": 0x57, "Rainbow Badge": 0x5F, "Soul Badge": 0x67, "Marsh Badge": 0x6F, @@ -427,7 +474,7 @@ def generate_output(self, output_directory: str): write_bytes(data, encode_text("Nothing"), rom_addresses["Badge_Text_" + badge.replace(" ", "_")]) type_loc = rom_addresses["Type_Chart"] - for matchup in self.type_chart: + for matchup in world.type_chart: if matchup[2] != 10: # don't needlessly divide damage by 10 and multiply by 10 data[type_loc] = poke_data.type_ids[matchup[0]] data[type_loc + 1] = poke_data.type_ids[matchup[1]] @@ -437,52 +484,49 @@ def generate_output(self, output_directory: str): data[type_loc + 1] = 0xFF data[type_loc + 2] = 0xFF - if self.multiworld.normalize_encounter_chances[self.player].value: + if world.options.normalize_encounter_chances.value: chances = [25, 51, 77, 103, 129, 155, 180, 205, 230, 255] for i, chance in enumerate(chances): data[rom_addresses['Encounter_Chances'] + (i * 2)] = chance - for mon, mon_data in self.local_poke_data.items(): + for mon, mon_data in world.local_poke_data.items(): if mon == "Mew": address = rom_addresses["Base_Stats_Mew"] else: address = rom_addresses["Base_Stats"] + (28 * (mon_data["dex"] - 1)) - data[address + 1] = self.local_poke_data[mon]["hp"] - data[address + 2] = self.local_poke_data[mon]["atk"] - data[address + 3] = self.local_poke_data[mon]["def"] - data[address + 4] = self.local_poke_data[mon]["spd"] - data[address + 5] = self.local_poke_data[mon]["spc"] - data[address + 6] = poke_data.type_ids[self.local_poke_data[mon]["type1"]] - data[address + 7] = poke_data.type_ids[self.local_poke_data[mon]["type2"]] - data[address + 8] = self.local_poke_data[mon]["catch rate"] - data[address + 15] = poke_data.moves[self.local_poke_data[mon]["start move 1"]]["id"] - data[address + 16] = poke_data.moves[self.local_poke_data[mon]["start move 2"]]["id"] - data[address + 17] = poke_data.moves[self.local_poke_data[mon]["start move 3"]]["id"] - data[address + 18] = poke_data.moves[self.local_poke_data[mon]["start move 4"]]["id"] - write_bytes(data, self.local_poke_data[mon]["tms"], address + 20) - if mon in self.learnsets and self.learnsets[mon]: + data[address + 1] = world.local_poke_data[mon]["hp"] + data[address + 2] = world.local_poke_data[mon]["atk"] + data[address + 3] = world.local_poke_data[mon]["def"] + data[address + 4] = world.local_poke_data[mon]["spd"] + data[address + 5] = world.local_poke_data[mon]["spc"] + data[address + 6] = poke_data.type_ids[world.local_poke_data[mon]["type1"]] + data[address + 7] = poke_data.type_ids[world.local_poke_data[mon]["type2"]] + data[address + 8] = world.local_poke_data[mon]["catch rate"] + data[address + 15] = poke_data.moves[world.local_poke_data[mon]["start move 1"]]["id"] + data[address + 16] = poke_data.moves[world.local_poke_data[mon]["start move 2"]]["id"] + data[address + 17] = poke_data.moves[world.local_poke_data[mon]["start move 3"]]["id"] + data[address + 18] = poke_data.moves[world.local_poke_data[mon]["start move 4"]]["id"] + write_bytes(data, world.local_poke_data[mon]["tms"], address + 20) + if mon in world.learnsets and world.learnsets[mon]: address = rom_addresses["Learnset_" + mon.replace(" ", "")] - for i, move in enumerate(self.learnsets[mon]): + for i, move in enumerate(world.learnsets[mon]): data[(address + 1) + i * 2] = poke_data.moves[move]["id"] - data[rom_addresses["Option_Aide_Rt2"]] = self.multiworld.oaks_aide_rt_2[self.player].value - data[rom_addresses["Option_Aide_Rt11"]] = self.multiworld.oaks_aide_rt_11[self.player].value - data[rom_addresses["Option_Aide_Rt15"]] = self.multiworld.oaks_aide_rt_15[self.player].value + data[rom_addresses["Option_Aide_Rt2"]] = world.options.oaks_aide_rt_2.value + data[rom_addresses["Option_Aide_Rt11"]] = world.options.oaks_aide_rt_11.value + data[rom_addresses["Option_Aide_Rt15"]] = world.options.oaks_aide_rt_15.value - if self.multiworld.safari_zone_normal_battles[self.player].value == 1: + if world.options.safari_zone_normal_battles.value == 1: data[rom_addresses["Option_Safari_Zone_Battle_Type"]] = 255 - if self.multiworld.reusable_tms[self.player].value: + if world.options.reusable_tms.value: data[rom_addresses["Option_Reusable_TMs"]] = 0xC9 - for i in range(1, 10): - data[rom_addresses[f"Option_Trainersanity{i}"]] = self.multiworld.trainersanity[self.player].value + data[rom_addresses["Option_Always_Half_STAB"]] = int(not world.options.same_type_attack_bonus.value) - data[rom_addresses["Option_Always_Half_STAB"]] = int(not self.multiworld.same_type_attack_bonus[self.player].value) - - if self.multiworld.better_shops[self.player]: + if world.options.better_shops: inventory = ["Poke Ball", "Great Ball", "Ultra Ball"] - if self.multiworld.better_shops[self.player].value == 2: + if world.options.better_shops.value == 2: inventory.append("Master Ball") inventory += ["Potion", "Super Potion", "Hyper Potion", "Max Potion", "Full Restore", "Revive", "Antidote", "Awakening", "Burn Heal", "Ice Heal", "Paralyze Heal", "Full Heal", "Repel", "Super Repel", @@ -492,30 +536,30 @@ def generate_output(self, output_directory: str): shop_data.append(0xFF) for shop in range(1, 11): write_bytes(data, shop_data, rom_addresses[f"Shop{shop}"]) - if self.multiworld.stonesanity[self.player]: + if world.options.stonesanity: write_bytes(data, bytearray([0xFE, 1, item_table["Poke Doll"].id - 172000000, 0xFF]), rom_addresses[f"Shop_Stones"]) - price = str(self.multiworld.master_ball_price[self.player].value).zfill(6) + price = str(world.options.master_ball_price.value).zfill(6) price = bytearray([int(price[:2], 16), int(price[2:4], 16), int(price[4:], 16)]) write_bytes(data, price, rom_addresses["Price_Master_Ball"]) # Money values in Red and Blue are weird - for item in reversed(self.multiworld.precollected_items[self.player]): + for item in reversed(world.multiworld.precollected_items[world.player]): if data[rom_addresses["Start_Inventory"] + item.code - 172000000] < 255: data[rom_addresses["Start_Inventory"] + item.code - 172000000] += 1 - set_mon_palettes(self, random, data) + set_mon_palettes(world, random, data) - for move_data in self.local_move_data.values(): + for move_data in world.local_move_data.values(): if move_data["id"] == 0: continue address = rom_addresses["Move_Data"] + ((move_data["id"] - 1) * 6) write_bytes(data, bytearray([move_data["id"], move_data["effect"], move_data["power"], poke_data.type_ids[move_data["type"]], round(move_data["accuracy"] * 2.55), move_data["pp"]]), address) - TM_IDs = bytearray([poke_data.moves[move]["id"] for move in self.local_tms]) + TM_IDs = bytearray([poke_data.moves[move]["id"] for move in world.local_tms]) write_bytes(data, TM_IDs, rom_addresses["TM_Moves"]) - if self.multiworld.randomize_rock_tunnel[self.player]: + if world.options.randomize_rock_tunnel: seed = randomize_rock_tunnel(data, random) write_bytes(data, encode_text(f"SEED: {seed}"), rom_addresses["Text_Rock_Tunnel_Sign"]) @@ -524,44 +568,44 @@ def generate_output(self, output_directory: str): data[rom_addresses['Title_Mon_First']] = mons.pop() for mon in range(0, 16): data[rom_addresses['Title_Mons'] + mon] = mons.pop() - if self.multiworld.game_version[self.player].value: - mons.sort(key=lambda mon: 0 if mon == self.multiworld.get_location("Oak's Lab - Starter 1", self.player).item.name - else 1 if mon == self.multiworld.get_location("Oak's Lab - Starter 2", self.player).item.name else - 2 if mon == self.multiworld.get_location("Oak's Lab - Starter 3", self.player).item.name else 3) + if world.options.game_version.value: + mons.sort(key=lambda mon: 0 if mon == world.multiworld.get_location("Oak's Lab - Starter 1", world.player).item.name + else 1 if mon == world.multiworld.get_location("Oak's Lab - Starter 2", world.player).item.name else + 2 if mon == world.multiworld.get_location("Oak's Lab - Starter 3", world.player).item.name else 3) else: - mons.sort(key=lambda mon: 0 if mon == self.multiworld.get_location("Oak's Lab - Starter 2", self.player).item.name - else 1 if mon == self.multiworld.get_location("Oak's Lab - Starter 1", self.player).item.name else - 2 if mon == self.multiworld.get_location("Oak's Lab - Starter 3", self.player).item.name else 3) - write_bytes(data, encode_text(self.multiworld.seed_name[-20:], 20, True), rom_addresses['Title_Seed']) + mons.sort(key=lambda mon: 0 if mon == world.multiworld.get_location("Oak's Lab - Starter 2", world.player).item.name + else 1 if mon == world.multiworld.get_location("Oak's Lab - Starter 1", world.player).item.name else + 2 if mon == world.multiworld.get_location("Oak's Lab - Starter 3", world.player).item.name else 3) + write_bytes(data, encode_text(world.multiworld.seed_name[-20:], 20, True), rom_addresses['Title_Seed']) - slot_name = self.multiworld.player_name[self.player] + slot_name = world.multiworld.player_name[world.player] slot_name.replace("@", " ") slot_name.replace("<", " ") slot_name.replace(">", " ") write_bytes(data, encode_text(slot_name, 16, True, True), rom_addresses['Title_Slot_Name']) - if self.trainer_name == "choose_in_game": + if world.trainer_name == "choose_in_game": data[rom_addresses["Skip_Player_Name"]] = 0 else: - write_bytes(data, self.trainer_name, rom_addresses['Player_Name']) - if self.rival_name == "choose_in_game": + write_bytes(data, world.trainer_name, rom_addresses['Player_Name']) + if world.rival_name == "choose_in_game": data[rom_addresses["Skip_Rival_Name"]] = 0 else: - write_bytes(data, self.rival_name, rom_addresses['Rival_Name']) + write_bytes(data, world.rival_name, rom_addresses['Rival_Name']) data[0xFF00] = 2 # client compatibility version - rom_name = bytearray(f'AP{Utils.__version__.replace(".", "")[0:3]}_{self.player}_{self.multiworld.seed:11}\0', + rom_name = bytearray(f'AP{Utils.__version__.replace(".", "")[0:3]}_{world.player}_{world.multiworld.seed:11}\0', 'utf8')[:21] rom_name.extend([0] * (21 - len(rom_name))) write_bytes(data, rom_name, 0xFFC6) - write_bytes(data, self.multiworld.seed_name.encode(), 0xFFDB) - write_bytes(data, self.multiworld.player_name[self.player].encode(), 0xFFF0) + write_bytes(data, world.multiworld.seed_name.encode(), 0xFFDB) + write_bytes(data, world.multiworld.player_name[world.player].encode(), 0xFFF0) - self.finished_level_scaling.wait() + world.finished_level_scaling.wait() - write_quizzes(self, data, random) + write_quizzes(world, data, random) - for location in self.multiworld.get_locations(self.player): + for location in world.multiworld.get_locations(world.player): if location.party_data: for party in location.party_data: if not isinstance(party["party_address"], list): @@ -588,7 +632,7 @@ def generate_output(self, output_directory: str): continue elif location.rom_address is None: continue - if location.item and location.item.player == self.player: + if location.item and location.item.player == world.player: if location.rom_address: rom_address = location.rom_address if not isinstance(rom_address, list): @@ -599,7 +643,7 @@ def generate_output(self, output_directory: str): elif " ".join(location.item.name.split()[1:]) in poke_data.pokemon_data.keys(): data[address] = poke_data.pokemon_data[" ".join(location.item.name.split()[1:])]["id"] else: - item_id = self.item_name_to_id[location.item.name] - 172000000 + item_id = world.item_name_to_id[location.item.name] - 172000000 if item_id > 255: item_id -= 256 data[address] = item_id @@ -613,18 +657,18 @@ def generate_output(self, output_directory: str): for address in rom_address: data[address] = 0x2C # AP Item - outfilepname = f'_P{self.player}' - outfilepname += f"_{self.multiworld.get_file_safe_player_name(self.player).replace(' ', '_')}" \ - if self.multiworld.player_name[self.player] != 'Player%d' % self.player else '' - rompath = os.path.join(output_directory, f'AP_{self.multiworld.seed_name}{outfilepname}.gb') + outfilepname = f'_P{world.player}' + outfilepname += f"_{world.multiworld.get_file_safe_player_name(world.player).replace(' ', '_')}" \ + if world.multiworld.player_name[world.player] != 'Player%d' % world.player else '' + rompath = os.path.join(output_directory, f'AP_{world.multiworld.seed_name}{outfilepname}.gb') with open(rompath, 'wb') as outfile: outfile.write(data) - if self.multiworld.game_version[self.player].current_key == "red": - patch = RedDeltaPatch(os.path.splitext(rompath)[0] + RedDeltaPatch.patch_file_ending, player=self.player, - player_name=self.multiworld.player_name[self.player], patched_path=rompath) + if world.options.game_version.current_key == "red": + patch = RedDeltaPatch(os.path.splitext(rompath)[0] + RedDeltaPatch.patch_file_ending, player=world.player, + player_name=world.multiworld.player_name[world.player], patched_path=rompath) else: - patch = BlueDeltaPatch(os.path.splitext(rompath)[0] + BlueDeltaPatch.patch_file_ending, player=self.player, - player_name=self.multiworld.player_name[self.player], patched_path=rompath) + patch = BlueDeltaPatch(os.path.splitext(rompath)[0] + BlueDeltaPatch.patch_file_ending, player=world.player, + player_name=world.multiworld.player_name[world.player], patched_path=rompath) patch.write() os.unlink(rompath) diff --git a/worlds/pokemon_rb/rom_addresses.py b/worlds/pokemon_rb/rom_addresses.py index e5c07397..ec233d94 100644 --- a/worlds/pokemon_rb/rom_addresses.py +++ b/worlds/pokemon_rb/rom_addresses.py @@ -1,10 +1,9 @@ rom_addresses = { "Option_Encounter_Minimum_Steps": 0x3c1, "Option_Pitch_Black_Rock_Tunnel": 0x76a, - "Option_Blind_Trainers": 0x30d5, - "Option_Trainersanity1": 0x3165, - "Option_Split_Card_Key": 0x3e1e, - "Option_Fix_Combat_Bugs": 0x3e1f, + "Option_Blind_Trainers": 0x32f0, + "Option_Split_Card_Key": 0x3e19, + "Option_Fix_Combat_Bugs": 0x3e1a, "Option_Lose_Money": 0x40d4, "Base_Stats_Mew": 0x4260, "Title_Mon_First": 0x4373, @@ -115,9 +114,10 @@ rom_addresses = { "HM_Strength_Badge_b": 0x131ed, "HM_Flash_Badge_a": 0x131fc, "HM_Flash_Badge_b": 0x13201, - "Trainer_Screen_Total_Key_Items": 0x135dc, - "TM_Moves": 0x137b1, - "Encounter_Chances": 0x13950, + "Tea_Key_Item_A": 0x135ac, + "Trainer_Screen_Total_Key_Items": 0x1361b, + "TM_Moves": 0x137f0, + "Encounter_Chances": 0x1398f, "Warps_CeladonCity": 0x18026, "Warps_PalletTown": 0x182c7, "Warps_ViridianCity": 0x18388, @@ -128,52 +128,54 @@ rom_addresses = { "Option_Viridian_Gym_Badges": 0x1901d, "Event_Sleepy_Guy": 0x191d1, "Option_Route3_Guard_B": 0x1928a, - "Starter2_K": 0x19611, - "Starter3_K": 0x19619, - "Event_Rocket_Thief": 0x19733, - "Option_Cerulean_Cave_Badges": 0x19861, - "Option_Cerulean_Cave_Key_Items": 0x19868, - "Text_Cerulean_Cave_Badges": 0x198d7, - "Text_Cerulean_Cave_Key_Items": 0x198e5, - "Event_Stranded_Man": 0x19b3c, - "Event_Rivals_Sister": 0x19d0f, - "Warps_BluesHouse": 0x19d65, - "Warps_VermilionTradeHouse": 0x19dbc, - "Require_Pokedex_D": 0x19e53, - "Option_Elite_Four_Key_Items": 0x19e9d, - "Option_Elite_Four_Pokedex": 0x19ea4, - "Option_Elite_Four_Badges": 0x19eab, - "Text_Elite_Four_Badges": 0x19f47, - "Text_Elite_Four_Key_Items": 0x19f51, - "Text_Elite_Four_Pokedex": 0x19f64, - "Shop10": 0x1a018, - "Warps_IndigoPlateauLobby": 0x1a044, - "Trainersanity_EVENT_BEAT_SILPH_CO_4F_TRAINER_0_ITEM": 0x1a16c, - "Trainersanity_EVENT_BEAT_SILPH_CO_4F_TRAINER_1_ITEM": 0x1a17a, - "Trainersanity_EVENT_BEAT_SILPH_CO_4F_TRAINER_2_ITEM": 0x1a188, - "Event_SKC4F": 0x1a19b, - "Warps_SilphCo4F": 0x1a21d, - "Missable_Silph_Co_4F_Item_1": 0x1a25d, - "Missable_Silph_Co_4F_Item_2": 0x1a264, - "Missable_Silph_Co_4F_Item_3": 0x1a26b, - "Trainersanity_EVENT_BEAT_SILPH_CO_5F_TRAINER_0_ITEM": 0x1a3c3, - "Trainersanity_EVENT_BEAT_SILPH_CO_5F_TRAINER_1_ITEM": 0x1a3d1, - "Trainersanity_EVENT_BEAT_SILPH_CO_5F_TRAINER_2_ITEM": 0x1a3df, - "Trainersanity_EVENT_BEAT_SILPH_CO_5F_TRAINER_3_ITEM": 0x1a3ed, - "Event_SKC5F": 0x1a400, - "Warps_SilphCo5F": 0x1a4aa, - "Missable_Silph_Co_5F_Item_1": 0x1a4f2, - "Missable_Silph_Co_5F_Item_2": 0x1a4f9, - "Missable_Silph_Co_5F_Item_3": 0x1a500, - "Trainersanity_EVENT_BEAT_SILPH_CO_6F_TRAINER_0_ITEM": 0x1a630, - "Trainersanity_EVENT_BEAT_SILPH_CO_6F_TRAINER_1_ITEM": 0x1a63e, - "Trainersanity_EVENT_BEAT_SILPH_CO_6F_TRAINER_2_ITEM": 0x1a64c, - "Event_SKC6F": 0x1a66d, - "Warps_SilphCo6F": 0x1a74b, - "Missable_Silph_Co_6F_Item_1": 0x1a79b, - "Missable_Silph_Co_6F_Item_2": 0x1a7a2, - "Path_Pallet_Oak": 0x1a928, - "Path_Pallet_Player": 0x1a935, + "Starter2_K": 0x19618, + "Starter3_K": 0x19620, + "Event_Rocket_Thief": 0x1973a, + "Tea_Key_Item_C": 0x1988f, + "Option_Cerulean_Cave_Badges": 0x198a0, + "Option_Cerulean_Cave_Key_Items": 0x198a7, + "Text_Cerulean_Cave_Badges": 0x19916, + "Text_Cerulean_Cave_Key_Items": 0x19924, + "Event_Stranded_Man": 0x19b7b, + "Event_Rivals_Sister": 0x19d4e, + "Warps_BluesHouse": 0x19da4, + "Warps_VermilionTradeHouse": 0x19dfb, + "Require_Pokedex_D": 0x19e99, + "Tea_Key_Item_B": 0x19f13, + "Option_Elite_Four_Key_Items": 0x19f1b, + "Option_Elite_Four_Pokedex": 0x19f22, + "Option_Elite_Four_Badges": 0x19f29, + "Text_Elite_Four_Badges": 0x19fc5, + "Text_Elite_Four_Key_Items": 0x19fcf, + "Text_Elite_Four_Pokedex": 0x19fe2, + "Shop10": 0x1a096, + "Warps_IndigoPlateauLobby": 0x1a0c2, + "Trainersanity_EVENT_BEAT_SILPH_CO_4F_TRAINER_0_ITEM": 0x1a1ea, + "Trainersanity_EVENT_BEAT_SILPH_CO_4F_TRAINER_1_ITEM": 0x1a1f8, + "Trainersanity_EVENT_BEAT_SILPH_CO_4F_TRAINER_2_ITEM": 0x1a206, + "Event_SKC4F": 0x1a219, + "Warps_SilphCo4F": 0x1a29b, + "Missable_Silph_Co_4F_Item_1": 0x1a2db, + "Missable_Silph_Co_4F_Item_2": 0x1a2e2, + "Missable_Silph_Co_4F_Item_3": 0x1a2e9, + "Trainersanity_EVENT_BEAT_SILPH_CO_5F_TRAINER_0_ITEM": 0x1a441, + "Trainersanity_EVENT_BEAT_SILPH_CO_5F_TRAINER_1_ITEM": 0x1a44f, + "Trainersanity_EVENT_BEAT_SILPH_CO_5F_TRAINER_2_ITEM": 0x1a45d, + "Trainersanity_EVENT_BEAT_SILPH_CO_5F_TRAINER_3_ITEM": 0x1a46b, + "Event_SKC5F": 0x1a47e, + "Warps_SilphCo5F": 0x1a528, + "Missable_Silph_Co_5F_Item_1": 0x1a570, + "Missable_Silph_Co_5F_Item_2": 0x1a577, + "Missable_Silph_Co_5F_Item_3": 0x1a57e, + "Trainersanity_EVENT_BEAT_SILPH_CO_6F_TRAINER_0_ITEM": 0x1a6ae, + "Trainersanity_EVENT_BEAT_SILPH_CO_6F_TRAINER_1_ITEM": 0x1a6bc, + "Trainersanity_EVENT_BEAT_SILPH_CO_6F_TRAINER_2_ITEM": 0x1a6ca, + "Event_SKC6F": 0x1a6eb, + "Warps_SilphCo6F": 0x1a7c9, + "Missable_Silph_Co_6F_Item_1": 0x1a819, + "Missable_Silph_Co_6F_Item_2": 0x1a820, + "Path_Pallet_Oak": 0x1a9a6, + "Path_Pallet_Player": 0x1a9b3, "Warps_CinnabarIsland": 0x1c026, "Warps_Route1": 0x1c0e9, "Option_Extra_Key_Items_B": 0x1ca46, @@ -191,75 +193,75 @@ rom_addresses = { "Starter2_E": 0x1d2f7, "Starter3_E": 0x1d2ff, "Event_Pokedex": 0x1d363, - "Event_Oaks_Gift": 0x1d393, - "Starter2_P": 0x1d481, - "Starter3_P": 0x1d489, - "Warps_OaksLab": 0x1d6af, - "Event_Pokemart_Quest": 0x1d76b, - "Shop1": 0x1d795, - "Warps_ViridianMart": 0x1d7d8, - "Warps_ViridianSchoolHouse": 0x1d82b, - "Warps_ViridianNicknameHouse": 0x1d889, - "Warps_PewterNidoranHouse": 0x1d8e4, - "Warps_PewterSpeechHouse": 0x1d927, - "Warps_CeruleanTrashedHouse": 0x1d98d, - "Warps_CeruleanTradeHouse": 0x1d9de, - "Event_Bicycle_Shop": 0x1da2f, - "Bike_Shop_Item_Display": 0x1da8a, - "Warps_BikeShop": 0x1db45, - "Event_Fuji": 0x1dbfd, - "Warps_MrFujisHouse": 0x1dc44, - "Warps_LavenderCuboneHouse": 0x1dcc0, - "Warps_NameRatersHouse": 0x1ddae, - "Warps_VermilionPidgeyHouse": 0x1ddf8, - "Trainersanity_EVENT_BEAT_MEW_ITEM": 0x1de4e, - "Warps_VermilionDock": 0x1de70, - "Static_Encounter_Mew": 0x1de7e, - "Gift_Eevee": 0x1def7, - "Warps_CeladonMansionRoofHouse": 0x1df0e, - "Shop7": 0x1df49, - "Warps_FuchsiaMart": 0x1df74, - "Warps_SaffronPidgeyHouse": 0x1dfdd, - "Event_Mr_Psychic": 0x1e020, - "Warps_MrPsychicsHouse": 0x1e05d, - "Warps_DiglettsCaveRoute2": 0x1e092, - "Warps_Route2TradeHouse": 0x1e0da, - "Warps_Route5Gate": 0x1e1db, - "Warps_Route6Gate": 0x1e2ad, - "Warps_Route7Gate": 0x1e383, - "Warps_Route8Gate": 0x1e454, - "Warps_UndergroundPathRoute8": 0x1e4a5, - "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_0_ITEM": 0x1e511, - "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_1_ITEM": 0x1e51f, - "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_2_ITEM": 0x1e52d, - "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_3_ITEM": 0x1e53b, - "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_4_ITEM": 0x1e549, - "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_5_ITEM": 0x1e557, - "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_6_ITEM": 0x1e565, - "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_7_ITEM": 0x1e573, - "Trainersanity_EVENT_BEAT_ZAPDOS_ITEM": 0x1e581, - "Warps_PowerPlant": 0x1e5de, - "Static_Encounter_Voltorb_A": 0x1e5f0, - "Static_Encounter_Voltorb_B": 0x1e5f8, - "Static_Encounter_Voltorb_C": 0x1e600, - "Static_Encounter_Electrode_A": 0x1e608, - "Static_Encounter_Voltorb_D": 0x1e610, - "Static_Encounter_Voltorb_E": 0x1e618, - "Static_Encounter_Electrode_B": 0x1e620, - "Static_Encounter_Voltorb_F": 0x1e628, - "Static_Encounter_Zapdos": 0x1e630, - "Missable_Power_Plant_Item_1": 0x1e638, - "Missable_Power_Plant_Item_2": 0x1e63f, - "Missable_Power_Plant_Item_3": 0x1e646, - "Missable_Power_Plant_Item_4": 0x1e64d, - "Missable_Power_Plant_Item_5": 0x1e654, - "Warps_DiglettsCaveRoute11": 0x1e7e9, - "Event_Rt16_House_Woman": 0x1e827, - "Warps_Route16FlyHouse": 0x1e870, - "Option_Victory_Road_Badges": 0x1e8f3, - "Warps_Route22Gate": 0x1e9e3, - "Event_Bill": 0x1eb24, - "Warps_BillsHouse": 0x1eb83, + "Event_Oaks_Gift": 0x1d398, + "Starter2_P": 0x1d486, + "Starter3_P": 0x1d48e, + "Warps_OaksLab": 0x1d6b4, + "Event_Pokemart_Quest": 0x1d770, + "Shop1": 0x1d79a, + "Warps_ViridianMart": 0x1d7dd, + "Warps_ViridianSchoolHouse": 0x1d830, + "Warps_ViridianNicknameHouse": 0x1d88e, + "Warps_PewterNidoranHouse": 0x1d8e9, + "Warps_PewterSpeechHouse": 0x1d92c, + "Warps_CeruleanTrashedHouse": 0x1d992, + "Warps_CeruleanTradeHouse": 0x1d9e3, + "Event_Bicycle_Shop": 0x1da34, + "Bike_Shop_Item_Display": 0x1da8f, + "Warps_BikeShop": 0x1db4a, + "Event_Fuji": 0x1dc02, + "Warps_MrFujisHouse": 0x1dc49, + "Warps_LavenderCuboneHouse": 0x1dcc5, + "Warps_NameRatersHouse": 0x1ddb3, + "Warps_VermilionPidgeyHouse": 0x1ddfd, + "Trainersanity_EVENT_BEAT_MEW_ITEM": 0x1de53, + "Warps_VermilionDock": 0x1de75, + "Static_Encounter_Mew": 0x1de83, + "Gift_Eevee": 0x1defc, + "Warps_CeladonMansionRoofHouse": 0x1df13, + "Shop7": 0x1df4e, + "Warps_FuchsiaMart": 0x1df79, + "Warps_SaffronPidgeyHouse": 0x1dfe2, + "Event_Mr_Psychic": 0x1e025, + "Warps_MrPsychicsHouse": 0x1e062, + "Warps_DiglettsCaveRoute2": 0x1e097, + "Warps_Route2TradeHouse": 0x1e0df, + "Warps_Route5Gate": 0x1e1e0, + "Warps_Route6Gate": 0x1e2b2, + "Warps_Route7Gate": 0x1e388, + "Warps_Route8Gate": 0x1e459, + "Warps_UndergroundPathRoute8": 0x1e4aa, + "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_0_ITEM": 0x1e516, + "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_1_ITEM": 0x1e524, + "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_2_ITEM": 0x1e532, + "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_3_ITEM": 0x1e540, + "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_4_ITEM": 0x1e54e, + "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_5_ITEM": 0x1e55c, + "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_6_ITEM": 0x1e56a, + "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_7_ITEM": 0x1e578, + "Trainersanity_EVENT_BEAT_ZAPDOS_ITEM": 0x1e586, + "Warps_PowerPlant": 0x1e5e3, + "Static_Encounter_Voltorb_A": 0x1e5f5, + "Static_Encounter_Voltorb_B": 0x1e5fd, + "Static_Encounter_Voltorb_C": 0x1e605, + "Static_Encounter_Electrode_A": 0x1e60d, + "Static_Encounter_Voltorb_D": 0x1e615, + "Static_Encounter_Voltorb_E": 0x1e61d, + "Static_Encounter_Electrode_B": 0x1e625, + "Static_Encounter_Voltorb_F": 0x1e62d, + "Static_Encounter_Zapdos": 0x1e635, + "Missable_Power_Plant_Item_1": 0x1e63d, + "Missable_Power_Plant_Item_2": 0x1e644, + "Missable_Power_Plant_Item_3": 0x1e64b, + "Missable_Power_Plant_Item_4": 0x1e652, + "Missable_Power_Plant_Item_5": 0x1e659, + "Warps_DiglettsCaveRoute11": 0x1e7ee, + "Event_Rt16_House_Woman": 0x1e82c, + "Warps_Route16FlyHouse": 0x1e875, + "Option_Victory_Road_Badges": 0x1e8f8, + "Warps_Route22Gate": 0x1e9e8, + "Event_Bill": 0x1eb29, + "Warps_BillsHouse": 0x1eb88, "Starter1_O": 0x372b0, "Starter2_O": 0x372b4, "Starter3_O": 0x372b8, @@ -1470,74 +1472,73 @@ rom_addresses = { "Trainersanity_EVENT_BEAT_POKEMONTOWER_5_TRAINER_3_ITEM": 0x609ea, "Warps_PokemonTower5F": 0x60a5e, "Missable_Pokemon_Tower_5F_Item": 0x60a92, - "Option_Trainersanity2": 0x60b2a, - "Ghost_Battle1": 0x60b83, - "Ghost_Battle_Level": 0x60b88, - "Trainersanity_EVENT_BEAT_POKEMONTOWER_6_TRAINER_0_ITEM": 0x60c25, - "Trainersanity_EVENT_BEAT_POKEMONTOWER_6_TRAINER_1_ITEM": 0x60c33, - "Trainersanity_EVENT_BEAT_POKEMONTOWER_6_TRAINER_2_ITEM": 0x60c41, - "Ghost_Battle2": 0x60c69, - "Warps_PokemonTower6F": 0x60cbe, - "Missable_Pokemon_Tower_6F_Item_1": 0x60ce4, - "Missable_Pokemon_Tower_6F_Item_2": 0x60ceb, - "Entrance_Shuffle_Fuji_Warp": 0x60deb, - "Trainersanity_EVENT_BEAT_POKEMONTOWER_7_TRAINER_0_ITEM": 0x60edf, - "Trainersanity_EVENT_BEAT_POKEMONTOWER_7_TRAINER_1_ITEM": 0x60eed, - "Trainersanity_EVENT_BEAT_POKEMONTOWER_7_TRAINER_2_ITEM": 0x60efb, - "Warps_PokemonTower7F": 0x60f8b, - "Warps_CeladonMart1F": 0x61033, - "Gift_Aerodactyl": 0x610f5, - "Gift_Omanyte": 0x610f9, - "Gift_Kabuto": 0x610fd, - "Trainersanity_EVENT_BEAT_VIRIDIAN_FOREST_TRAINER_0_ITEM": 0x611de, - "Trainersanity_EVENT_BEAT_VIRIDIAN_FOREST_TRAINER_1_ITEM": 0x611ec, - "Trainersanity_EVENT_BEAT_VIRIDIAN_FOREST_TRAINER_2_ITEM": 0x611fa, - "Warps_ViridianForest": 0x61273, - "Missable_Viridian_Forest_Item_1": 0x612c1, - "Missable_Viridian_Forest_Item_2": 0x612c8, - "Missable_Viridian_Forest_Item_3": 0x612cf, - "Warps_SSAnne1F": 0x61310, - "Starter2_M": 0x614e5, - "Starter3_M": 0x614ed, - "Warps_SSAnne2F": 0x615ab, - "Warps_SSAnneB1F": 0x616c9, - "Trainersanity_EVENT_BEAT_SS_ANNE_5_TRAINER_0_ITEM": 0x61771, - "Trainersanity_EVENT_BEAT_SS_ANNE_5_TRAINER_1_ITEM": 0x6177f, - "Warps_SSAnneBow": 0x617c6, - "Warps_SSAnneKitchen": 0x618b6, - "Event_SS_Anne_Captain": 0x6194e, - "Warps_SSAnneCaptainsRoom": 0x619d5, - "Trainersanity_EVENT_BEAT_SS_ANNE_8_TRAINER_0_ITEM": 0x61a3d, - "Trainersanity_EVENT_BEAT_SS_ANNE_8_TRAINER_1_ITEM": 0x61a4b, - "Trainersanity_EVENT_BEAT_SS_ANNE_8_TRAINER_2_ITEM": 0x61a59, - "Trainersanity_EVENT_BEAT_SS_ANNE_8_TRAINER_3_ITEM": 0x61a67, - "Warps_SSAnne1FRooms": 0x61af7, - "Missable_SS_Anne_1F_Item": 0x61b53, - "Trainersanity_EVENT_BEAT_SS_ANNE_9_TRAINER_0_ITEM": 0x61c24, - "Trainersanity_EVENT_BEAT_SS_ANNE_9_TRAINER_1_ITEM": 0x61c32, - "Trainersanity_EVENT_BEAT_SS_ANNE_9_TRAINER_2_ITEM": 0x61c40, - "Trainersanity_EVENT_BEAT_SS_ANNE_9_TRAINER_3_ITEM": 0x61c4e, - "Warps_SSAnne2FRooms": 0x61d2c, - "Missable_SS_Anne_2F_Item_1": 0x61d88, - "Missable_SS_Anne_2F_Item_2": 0x61d9b, - "Trainersanity_EVENT_BEAT_SS_ANNE_10_TRAINER_0_ITEM": 0x61e2c, - "Trainersanity_EVENT_BEAT_SS_ANNE_10_TRAINER_1_ITEM": 0x61e3a, - "Trainersanity_EVENT_BEAT_SS_ANNE_10_TRAINER_2_ITEM": 0x61e48, - "Trainersanity_EVENT_BEAT_SS_ANNE_10_TRAINER_3_ITEM": 0x61e56, - "Trainersanity_EVENT_BEAT_SS_ANNE_10_TRAINER_4_ITEM": 0x61e64, - "Trainersanity_EVENT_BEAT_SS_ANNE_10_TRAINER_5_ITEM": 0x61e72, - "Warps_SSAnneB1FRooms": 0x61f20, - "Missable_SS_Anne_B1F_Item_1": 0x61f8a, - "Missable_SS_Anne_B1F_Item_2": 0x61f91, - "Missable_SS_Anne_B1F_Item_3": 0x61f98, - "Warps_UndergroundPathNorthSouth": 0x61fd5, - "Warps_UndergroundPathWestEast": 0x61ff9, - "Warps_DiglettsCave": 0x6201d, - "Trainersanity_EVENT_BEAT_SILPH_CO_11F_TRAINER_0_ITEM": 0x62358, - "Trainersanity_EVENT_BEAT_SILPH_CO_11F_TRAINER_1_ITEM": 0x62366, - "Event_Silph_Co_President": 0x62373, - "Event_SKC11F": 0x623bd, - "Warps_SilphCo11F": 0x62446, + "Ghost_Battle1": 0x60b93, + "Ghost_Battle_Level": 0x60b98, + "Trainersanity_EVENT_BEAT_POKEMONTOWER_6_TRAINER_0_ITEM": 0x60c35, + "Trainersanity_EVENT_BEAT_POKEMONTOWER_6_TRAINER_1_ITEM": 0x60c43, + "Trainersanity_EVENT_BEAT_POKEMONTOWER_6_TRAINER_2_ITEM": 0x60c51, + "Ghost_Battle2": 0x60c79, + "Warps_PokemonTower6F": 0x60cce, + "Missable_Pokemon_Tower_6F_Item_1": 0x60cf4, + "Missable_Pokemon_Tower_6F_Item_2": 0x60cfb, + "Entrance_Shuffle_Fuji_Warp": 0x60dfb, + "Trainersanity_EVENT_BEAT_POKEMONTOWER_7_TRAINER_0_ITEM": 0x60eef, + "Trainersanity_EVENT_BEAT_POKEMONTOWER_7_TRAINER_1_ITEM": 0x60efd, + "Trainersanity_EVENT_BEAT_POKEMONTOWER_7_TRAINER_2_ITEM": 0x60f0b, + "Warps_PokemonTower7F": 0x60f9b, + "Warps_CeladonMart1F": 0x61043, + "Gift_Aerodactyl": 0x61105, + "Gift_Omanyte": 0x61109, + "Gift_Kabuto": 0x6110d, + "Trainersanity_EVENT_BEAT_VIRIDIAN_FOREST_TRAINER_0_ITEM": 0x61209, + "Trainersanity_EVENT_BEAT_VIRIDIAN_FOREST_TRAINER_1_ITEM": 0x61217, + "Trainersanity_EVENT_BEAT_VIRIDIAN_FOREST_TRAINER_2_ITEM": 0x61225, + "Warps_ViridianForest": 0x6129e, + "Missable_Viridian_Forest_Item_1": 0x612ec, + "Missable_Viridian_Forest_Item_2": 0x612f3, + "Missable_Viridian_Forest_Item_3": 0x612fa, + "Warps_SSAnne1F": 0x6133b, + "Starter2_M": 0x61510, + "Starter3_M": 0x61518, + "Warps_SSAnne2F": 0x615d6, + "Warps_SSAnneB1F": 0x616f4, + "Trainersanity_EVENT_BEAT_SS_ANNE_5_TRAINER_0_ITEM": 0x6179c, + "Trainersanity_EVENT_BEAT_SS_ANNE_5_TRAINER_1_ITEM": 0x617aa, + "Warps_SSAnneBow": 0x617f1, + "Warps_SSAnneKitchen": 0x618e1, + "Event_SS_Anne_Captain": 0x61979, + "Warps_SSAnneCaptainsRoom": 0x61a00, + "Trainersanity_EVENT_BEAT_SS_ANNE_8_TRAINER_0_ITEM": 0x61a68, + "Trainersanity_EVENT_BEAT_SS_ANNE_8_TRAINER_1_ITEM": 0x61a76, + "Trainersanity_EVENT_BEAT_SS_ANNE_8_TRAINER_2_ITEM": 0x61a84, + "Trainersanity_EVENT_BEAT_SS_ANNE_8_TRAINER_3_ITEM": 0x61a92, + "Warps_SSAnne1FRooms": 0x61b22, + "Missable_SS_Anne_1F_Item": 0x61b7e, + "Trainersanity_EVENT_BEAT_SS_ANNE_9_TRAINER_0_ITEM": 0x61c4f, + "Trainersanity_EVENT_BEAT_SS_ANNE_9_TRAINER_1_ITEM": 0x61c5d, + "Trainersanity_EVENT_BEAT_SS_ANNE_9_TRAINER_2_ITEM": 0x61c6b, + "Trainersanity_EVENT_BEAT_SS_ANNE_9_TRAINER_3_ITEM": 0x61c79, + "Warps_SSAnne2FRooms": 0x61d57, + "Missable_SS_Anne_2F_Item_1": 0x61db3, + "Missable_SS_Anne_2F_Item_2": 0x61dc6, + "Trainersanity_EVENT_BEAT_SS_ANNE_10_TRAINER_0_ITEM": 0x61e57, + "Trainersanity_EVENT_BEAT_SS_ANNE_10_TRAINER_1_ITEM": 0x61e65, + "Trainersanity_EVENT_BEAT_SS_ANNE_10_TRAINER_2_ITEM": 0x61e73, + "Trainersanity_EVENT_BEAT_SS_ANNE_10_TRAINER_3_ITEM": 0x61e81, + "Trainersanity_EVENT_BEAT_SS_ANNE_10_TRAINER_4_ITEM": 0x61e8f, + "Trainersanity_EVENT_BEAT_SS_ANNE_10_TRAINER_5_ITEM": 0x61e9d, + "Warps_SSAnneB1FRooms": 0x61f4b, + "Missable_SS_Anne_B1F_Item_1": 0x61fb5, + "Missable_SS_Anne_B1F_Item_2": 0x61fbc, + "Missable_SS_Anne_B1F_Item_3": 0x61fc3, + "Warps_UndergroundPathNorthSouth": 0x62000, + "Warps_UndergroundPathWestEast": 0x62024, + "Warps_DiglettsCave": 0x62048, + "Trainersanity_EVENT_BEAT_SILPH_CO_11F_TRAINER_0_ITEM": 0x62383, + "Trainersanity_EVENT_BEAT_SILPH_CO_11F_TRAINER_1_ITEM": 0x62391, + "Event_Silph_Co_President": 0x6239e, + "Event_SKC11F": 0x623e8, + "Warps_SilphCo11F": 0x62471, "Ghost_Battle4": 0x708e1, "Town_Map_Order": 0x70f0f, "Town_Map_Coords": 0x71381, @@ -1589,44 +1590,37 @@ rom_addresses = { "Warps_FuchsiaMeetingRoom": 0x75879, "Badge_Cinnabar_Gym": 0x759de, "Event_Cinnabar_Gym": 0x759f2, - "Option_Trainersanity4": 0x75ace, - "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_B_ITEM": 0x75ada, - "Option_Trainersanity3": 0x75b1e, - "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_A_ITEM": 0x75b2a, - "Option_Trainersanity5": 0x75b85, - "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_2_ITEM": 0x75b91, - "Option_Trainersanity6": 0x75bd5, - "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_3_ITEM": 0x75be1, - "Option_Trainersanity7": 0x75c25, - "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_4_ITEM": 0x75c31, - "Option_Trainersanity8": 0x75c75, - "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_5_ITEM": 0x75c81, - "Option_Trainersanity9": 0x75cc5, - "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_6_ITEM": 0x75cd1, - "Warps_CinnabarGym": 0x75d1b, - "Warps_CinnabarLab": 0x75e02, - "Warps_CinnabarLabTradeRoom": 0x75e94, - "Event_Lab_Scientist": 0x75ee9, - "Warps_CinnabarLabMetronomeRoom": 0x75f35, - "Fossils_Needed_For_Second_Item": 0x75fb6, - "Fossil_Level": 0x76017, - "Event_Dome_Fossil_B": 0x76031, - "Event_Helix_Fossil_B": 0x76051, - "Warps_CinnabarLabFossilRoom": 0x760d2, - "Warps_CinnabarPokecenter": 0x76128, - "Shop8": 0x7616f, - "Warps_CinnabarMart": 0x7619b, - "Warps_CopycatsHouse1F": 0x761ed, - "Starter2_N": 0x762a2, - "Starter3_N": 0x762aa, - "Warps_ChampionsRoom": 0x764d5, - "Trainersanity_EVENT_BEAT_LORELEIS_ROOM_TRAINER_0_ITEM": 0x76604, - "Warps_LoreleisRoom": 0x76628, - "Trainersanity_EVENT_BEAT_BRUNOS_ROOM_TRAINER_0_ITEM": 0x7675d, - "Warps_BrunosRoom": 0x76781, - "Trainersanity_EVENT_BEAT_AGATHAS_ROOM_TRAINER_0_ITEM": 0x768bc, - "Warps_AgathasRoom": 0x768e0, - "Option_Itemfinder": 0x76a33, + "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_B_ITEM": 0x75adc, + "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_A_ITEM": 0x75b2e, + "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_2_ITEM": 0x75b97, + "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_3_ITEM": 0x75be9, + "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_4_ITEM": 0x75c3b, + "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_5_ITEM": 0x75c8d, + "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_6_ITEM": 0x75cdf, + "Warps_CinnabarGym": 0x75d29, + "Warps_CinnabarLab": 0x75e10, + "Warps_CinnabarLabTradeRoom": 0x75ea2, + "Event_Lab_Scientist": 0x75ef7, + "Warps_CinnabarLabMetronomeRoom": 0x75f43, + "Fossils_Needed_For_Second_Item": 0x75fc4, + "Fossil_Level": 0x76025, + "Event_Dome_Fossil_B": 0x7603f, + "Event_Helix_Fossil_B": 0x7605f, + "Warps_CinnabarLabFossilRoom": 0x760e0, + "Warps_CinnabarPokecenter": 0x76136, + "Shop8": 0x7617d, + "Warps_CinnabarMart": 0x761a9, + "Warps_CopycatsHouse1F": 0x761fb, + "Starter2_N": 0x762b0, + "Starter3_N": 0x762b8, + "Warps_ChampionsRoom": 0x764e3, + "Trainersanity_EVENT_BEAT_LORELEIS_ROOM_TRAINER_0_ITEM": 0x76612, + "Warps_LoreleisRoom": 0x76636, + "Trainersanity_EVENT_BEAT_BRUNOS_ROOM_TRAINER_0_ITEM": 0x7676b, + "Warps_BrunosRoom": 0x7678f, + "Trainersanity_EVENT_BEAT_AGATHAS_ROOM_TRAINER_0_ITEM": 0x768ca, + "Warps_AgathasRoom": 0x768ee, + "Option_Itemfinder": 0x76a41, "Text_Quiz_A": 0x88806, "Text_Quiz_B": 0x8893a, "Text_Quiz_C": 0x88a6e, diff --git a/worlds/pokemon_rb/rules.py b/worlds/pokemon_rb/rules.py index 1d68f314..ba4bfd47 100644 --- a/worlds/pokemon_rb/rules.py +++ b/worlds/pokemon_rb/rules.py @@ -3,7 +3,7 @@ from .items import item_groups from . import logic -def set_rules(multiworld, player): +def set_rules(multiworld, world, player): item_rules = { # Some items do special things when they are passed into the GiveItem function in the game, but @@ -15,54 +15,46 @@ def set_rules(multiworld, player): not in i.name) } - if multiworld.prizesanity[player]: + if world.options.prizesanity: def prize_rule(i): return i.player != player or i.name in item_groups["Unique"] item_rules["Celadon Prize Corner - Item Prize 1"] = prize_rule item_rules["Celadon Prize Corner - Item Prize 2"] = prize_rule item_rules["Celadon Prize Corner - Item Prize 3"] = prize_rule - if multiworld.accessibility[player] != "full": - multiworld.get_location("Cerulean Bicycle Shop", player).always_allow = (lambda state, item: - item.name == "Bike Voucher" - and item.player == player) - multiworld.get_location("Fuchsia Warden's House - Safari Zone Warden", player).always_allow = (lambda state, item: - item.name == "Gold Teeth" and - item.player == player) - access_rules = { "Rival's House - Rival's Sister": lambda state: state.has("Oak's Parcel", player), "Oak's Lab - Oak's Post-Route-22-Rival Gift": lambda state: state.has("Oak's Parcel", player), - "Viridian City - Sleepy Guy": lambda state: logic.can_cut(state, player) or logic.can_surf(state, player), - "Route 2 Gate - Oak's Aide": lambda state: logic.oaks_aide(state, state.multiworld.oaks_aide_rt_2[player].value + 5, player), + "Viridian City - Sleepy Guy": lambda state: logic.can_cut(state, world, player) or logic.can_surf(state, world, player), + "Route 2 Gate - Oak's Aide": lambda state: logic.oaks_aide(state, world, world.options.oaks_aide_rt_2.value + 5, player), "Cerulean Bicycle Shop": lambda state: state.has("Bike Voucher", player) or location_item_name(state, "Cerulean Bicycle Shop", player) == ("Bike Voucher", player), "Lavender Mr. Fuji's House - Mr. Fuji": lambda state: state.has("Fuji Saved", player), - "Route 11 Gate 2F - Oak's Aide": lambda state: logic.oaks_aide(state, state.multiworld.oaks_aide_rt_11[player].value + 5, player), - "Celadon City - Stranded Man": lambda state: logic.can_surf(state, player), + "Route 11 Gate 2F - Oak's Aide": lambda state: logic.oaks_aide(state, world, world.options.oaks_aide_rt_11.value + 5, player), + "Celadon City - Stranded Man": lambda state: logic.can_surf(state, world, player), "Fuchsia Warden's House - Safari Zone Warden": lambda state: state.has("Gold Teeth", player) or location_item_name(state, "Fuchsia Warden's House - Safari Zone Warden", player) == ("Gold Teeth", player), - "Route 12 - Island Item": lambda state: logic.can_surf(state, player), - "Route 15 Gate 2F - Oak's Aide": lambda state: logic.oaks_aide(state, state.multiworld.oaks_aide_rt_15[player].value + 5, player), - "Route 25 - Item": lambda state: logic.can_cut(state, player), - "Fuchsia Warden's House - Behind Boulder Item": lambda state: logic.can_strength(state, player), - "Safari Zone Center - Island Item": lambda state: logic.can_surf(state, player), + "Route 12 - Island Item": lambda state: logic.can_surf(state, world, player), + "Route 15 Gate 2F - Oak's Aide": lambda state: logic.oaks_aide(state, world, world.options.oaks_aide_rt_15.value + 5, player), + "Route 25 - Item": lambda state: logic.can_cut(state, world, player), + "Fuchsia Warden's House - Behind Boulder Item": lambda state: logic.can_strength(state, world, player), + "Safari Zone Center - Island Item": lambda state: logic.can_surf(state, world, player), "Saffron Copycat's House 2F - Copycat": lambda state: state.has("Buy Poke Doll", player), "Celadon Game Corner - West Gambler's Gift": lambda state: state.has("Coin Case", player), "Celadon Game Corner - Center Gambler's Gift": lambda state: state.has("Coin Case", player), "Celadon Game Corner - East Gambler's Gift": lambda state: state.has("Coin Case", player), - "Celadon Game Corner - Hidden Item Northwest By Counter": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, player), - "Celadon Game Corner - Hidden Item Southwest Corner": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, player), - "Celadon Game Corner - Hidden Item Near Rumor Man": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, player), - "Celadon Game Corner - Hidden Item Near Speculating Woman": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, player), - "Celadon Game Corner - Hidden Item Near West Gifting Gambler": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, player), - "Celadon Game Corner - Hidden Item Near Wonderful Time Woman": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, player), - "Celadon Game Corner - Hidden Item Near Failing Gym Information Guy": lambda state: state.has( "Coin Case", player) and logic.can_get_hidden_items(state, player), - "Celadon Game Corner - Hidden Item Near East Gifting Gambler": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, player), - "Celadon Game Corner - Hidden Item Near Hooked Guy": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, player), - "Celadon Game Corner - Hidden Item at End of Horizontal Machine Row": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, player), - "Celadon Game Corner - Hidden Item in Front of Horizontal Machine Row": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, player), + "Celadon Game Corner - Hidden Item Northwest By Counter": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, world, player), + "Celadon Game Corner - Hidden Item Southwest Corner": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, world, player), + "Celadon Game Corner - Hidden Item Near Rumor Man": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, world, player), + "Celadon Game Corner - Hidden Item Near Speculating Woman": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, world, player), + "Celadon Game Corner - Hidden Item Near West Gifting Gambler": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, world, player), + "Celadon Game Corner - Hidden Item Near Wonderful Time Woman": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, world, player), + "Celadon Game Corner - Hidden Item Near Failing Gym Information Guy": lambda state: state.has( "Coin Case", player) and logic.can_get_hidden_items(state, world, player), + "Celadon Game Corner - Hidden Item Near East Gifting Gambler": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, world, player), + "Celadon Game Corner - Hidden Item Near Hooked Guy": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, world, player), + "Celadon Game Corner - Hidden Item at End of Horizontal Machine Row": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, world, player), + "Celadon Game Corner - Hidden Item in Front of Horizontal Machine Row": lambda state: state.has("Coin Case", player) and logic.can_get_hidden_items(state, world, player), "Celadon Prize Corner - Item Prize 1": lambda state: state.has("Coin Case", player) and state.has("Game Corner", player), "Celadon Prize Corner - Item Prize 2": lambda state: state.has("Coin Case", player) and state.has("Game Corner", player), @@ -79,9 +71,9 @@ def set_rules(multiworld, player): "Cinnabar Lab Fossil Room - Dome Fossil Pokemon": lambda state: state.has("Dome Fossil", player) and state.has("Cinnabar Island", player), "Route 12 - Sleeping Pokemon": lambda state: state.has("Poke Flute", player), "Route 16 - Sleeping Pokemon": lambda state: state.has("Poke Flute", player), - "Seafoam Islands B4F - Legendary Pokemon": lambda state: logic.can_strength(state, player) and state.has("Seafoam Boss Boulders", player), - "Vermilion Dock - Legendary Pokemon": lambda state: logic.can_surf(state, player), - "Cerulean Cave B1F - Legendary Pokemon": lambda state: logic.can_surf(state, player), + "Seafoam Islands B4F - Legendary Pokemon": lambda state: logic.can_strength(state, world, player) and state.has("Seafoam Boss Boulders", player), + "Vermilion Dock - Legendary Pokemon": lambda state: logic.can_surf(state, world, player), + "Cerulean Cave B1F - Legendary Pokemon": lambda state: logic.can_surf(state, world, player), **{f"Pokemon Tower {floor}F - Wild Pokemon - {slot}": lambda state: state.has("Silph Scope", player) for floor in range(3, 8) for slot in range(1, 11)}, "Pokemon Tower 6F - Restless Soul": lambda state: state.has("Silph Scope", player), # just for level scaling @@ -103,101 +95,101 @@ def set_rules(multiworld, player): "Route 22 - Trainer Parties": lambda state: state.has("Oak's Parcel", player), # # Rock Tunnel - "Rock Tunnel 1F - PokeManiac": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel 1F - Hiker 1": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel 1F - Hiker 2": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel 1F - Hiker 3": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel 1F - Jr. Trainer F 1": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel 1F - Jr. Trainer F 2": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel 1F - Jr. Trainer F 3": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel B1F - PokeManiac 1": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel B1F - PokeManiac 2": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel B1F - PokeManiac 3": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel B1F - Jr. Trainer F 1": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel B1F - Jr. Trainer F 2": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel B1F - Hiker 1": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel B1F - Hiker 2": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel B1F - Hiker 3": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel B1F - North Item": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel B1F - Northwest Item": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel B1F - Southwest Item": lambda state: logic.rock_tunnel(state, player), - "Rock Tunnel B1F - West Item": lambda state: logic.rock_tunnel(state, player), + "Rock Tunnel 1F - PokeManiac": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel 1F - Hiker 1": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel 1F - Hiker 2": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel 1F - Hiker 3": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel 1F - Jr. Trainer F 1": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel 1F - Jr. Trainer F 2": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel 1F - Jr. Trainer F 3": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel B1F - PokeManiac 1": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel B1F - PokeManiac 2": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel B1F - PokeManiac 3": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel B1F - Jr. Trainer F 1": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel B1F - Jr. Trainer F 2": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel B1F - Hiker 1": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel B1F - Hiker 2": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel B1F - Hiker 3": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel B1F - North Item": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel B1F - Northwest Item": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel B1F - Southwest Item": lambda state: logic.rock_tunnel(state, world, player), + "Rock Tunnel B1F - West Item": lambda state: logic.rock_tunnel(state, world, player), # Pokédex check "Oak's Lab - Oak's Parcel Reward": lambda state: state.has("Oak's Parcel", player), # Hidden items - "Viridian Forest - Hidden Item Northwest by Trainer": lambda state: logic.can_get_hidden_items(state, + "Viridian Forest - Hidden Item Northwest by Trainer": lambda state: logic.can_get_hidden_items(state, world, player), - "Viridian Forest - Hidden Item Entrance Tree": lambda state: logic.can_get_hidden_items(state, player), - "Mt Moon B2F - Hidden Item Dead End Before Fossils": lambda state: logic.can_get_hidden_items(state, + "Viridian Forest - Hidden Item Entrance Tree": lambda state: logic.can_get_hidden_items(state, world, player), + "Mt Moon B2F - Hidden Item Dead End Before Fossils": lambda state: logic.can_get_hidden_items(state, world, player), - "Route 25 - Hidden Item Fence Outside Bill's House": lambda state: logic.can_get_hidden_items(state, + "Route 25 - Hidden Item Fence Outside Bill's House": lambda state: logic.can_get_hidden_items(state, world, player), - "Route 9 - Hidden Item Bush By Grass": lambda state: logic.can_get_hidden_items(state, player), - "S.S. Anne Kitchen - Hidden Item Kitchen Trash": lambda state: logic.can_get_hidden_items(state, player), - "S.S. Anne B1F Rooms - Hidden Item Under Pillow": lambda state: logic.can_get_hidden_items(state, player), + "Route 9 - Hidden Item Bush By Grass": lambda state: logic.can_get_hidden_items(state, world, player), + "S.S. Anne Kitchen - Hidden Item Kitchen Trash": lambda state: logic.can_get_hidden_items(state, world, player), + "S.S. Anne B1F Rooms - Hidden Item Under Pillow": lambda state: logic.can_get_hidden_items(state, world, player), "Route 10 - Hidden Item Behind Rock Tunnel Entrance Cuttable Tree": lambda - state: logic.can_get_hidden_items(state, player) and logic.can_cut(state, player), - "Route 10 - Hidden Item Bush": lambda state: logic.can_get_hidden_items(state, player), - "Rocket Hideout B1F - Hidden Item Pot Plant": lambda state: logic.can_get_hidden_items(state, player), - "Rocket Hideout B3F - Hidden Item Near East Item": lambda state: logic.can_get_hidden_items(state, player), + state: logic.can_get_hidden_items(state, world, player) and logic.can_cut(state, world, player), + "Route 10 - Hidden Item Bush": lambda state: logic.can_get_hidden_items(state, world, player), + "Rocket Hideout B1F - Hidden Item Pot Plant": lambda state: logic.can_get_hidden_items(state, world, player), + "Rocket Hideout B3F - Hidden Item Near East Item": lambda state: logic.can_get_hidden_items(state, world, player), "Rocket Hideout B4F - Hidden Item Behind Giovanni": lambda state: - logic.can_get_hidden_items(state, player), - "Pokemon Tower 5F - Hidden Item Near West Staircase": lambda state: logic.can_get_hidden_items(state, + logic.can_get_hidden_items(state, world, player), + "Pokemon Tower 5F - Hidden Item Near West Staircase": lambda state: logic.can_get_hidden_items(state, world, player), - "Route 13 - Hidden Item Dead End Bush": lambda state: logic.can_get_hidden_items(state, player), - "Route 13 - Hidden Item Dead End By Water Corner": lambda state: logic.can_get_hidden_items(state, player), - "Pokemon Mansion B1F - Hidden Item Secret Key Room Corner": lambda state: logic.can_get_hidden_items(state, + "Route 13 - Hidden Item Dead End Bush": lambda state: logic.can_get_hidden_items(state, world, player), + "Route 13 - Hidden Item Dead End By Water Corner": lambda state: logic.can_get_hidden_items(state, world, player), + "Pokemon Mansion B1F - Hidden Item Secret Key Room Corner": lambda state: logic.can_get_hidden_items(state, world, player), - "Safari Zone West - Hidden Item Secret House Statue": lambda state: logic.can_get_hidden_items(state, + "Safari Zone West - Hidden Item Secret House Statue": lambda state: logic.can_get_hidden_items(state, world, player), - "Silph Co 5F - Hidden Item Pot Plant": lambda state: logic.can_get_hidden_items(state, player), - "Silph Co 9F - Hidden Item Nurse Bed": lambda state: logic.can_get_hidden_items(state, player), - "Saffron Copycat's House 2F - Hidden Item Desk": lambda state: logic.can_get_hidden_items(state, player), - "Cerulean Cave 1F - Hidden Item Center Rocks": lambda state: logic.can_get_hidden_items(state, player), - "Cerulean Cave B1F - Hidden Item Northeast Rocks": lambda state: logic.can_get_hidden_items(state, player), - "Power Plant - Hidden Item Central Dead End": lambda state: logic.can_get_hidden_items(state, player), - "Power Plant - Hidden Item Before Zapdos": lambda state: logic.can_get_hidden_items(state, player), - "Seafoam Islands B2F - Hidden Item Rock": lambda state: logic.can_get_hidden_items(state, player), - "Seafoam Islands B3F - Hidden Item Rock": lambda state: logic.can_get_hidden_items(state, player), + "Silph Co 5F - Hidden Item Pot Plant": lambda state: logic.can_get_hidden_items(state, world, player), + "Silph Co 9F - Hidden Item Nurse Bed": lambda state: logic.can_get_hidden_items(state, world, player), + "Saffron Copycat's House 2F - Hidden Item Desk": lambda state: logic.can_get_hidden_items(state, world, player), + "Cerulean Cave 1F - Hidden Item Center Rocks": lambda state: logic.can_get_hidden_items(state, world, player), + "Cerulean Cave B1F - Hidden Item Northeast Rocks": lambda state: logic.can_get_hidden_items(state, world, player), + "Power Plant - Hidden Item Central Dead End": lambda state: logic.can_get_hidden_items(state, world, player), + "Power Plant - Hidden Item Before Zapdos": lambda state: logic.can_get_hidden_items(state, world, player), + "Seafoam Islands B2F - Hidden Item Rock": lambda state: logic.can_get_hidden_items(state, world, player), + "Seafoam Islands B3F - Hidden Item Rock": lambda state: logic.can_get_hidden_items(state, world, player), # if you can reach any exit boulders, that means you can drop into the water tunnel and auto-surf - "Seafoam Islands B4F - Hidden Item Corner Island": lambda state: logic.can_get_hidden_items(state, player), + "Seafoam Islands B4F - Hidden Item Corner Island": lambda state: logic.can_get_hidden_items(state, world, player), "Pokemon Mansion 1F - Hidden Item Block Near Entrance Carpet": lambda - state: logic.can_get_hidden_items(state, player), - "Pokemon Mansion 3F - Hidden Item Behind Burglar": lambda state: logic.can_get_hidden_items(state, player), - "Route 23 - Hidden Item Rocks Before Victory Road": lambda state: logic.can_get_hidden_items(state, + state: logic.can_get_hidden_items(state, world, player), + "Pokemon Mansion 3F - Hidden Item Behind Burglar": lambda state: logic.can_get_hidden_items(state, world, player), + "Route 23 - Hidden Item Rocks Before Victory Road": lambda state: logic.can_get_hidden_items(state, world, player), - "Route 23 - Hidden Item East Bush After Water": lambda state: logic.can_get_hidden_items(state, + "Route 23 - Hidden Item East Bush After Water": lambda state: logic.can_get_hidden_items(state, world, player), - "Route 23 - Hidden Item On Island": lambda state: logic.can_get_hidden_items(state, - player) and logic.can_surf(state, player), - "Victory Road 2F - Hidden Item Rock Before Moltres": lambda state: logic.can_get_hidden_items(state, + "Route 23 - Hidden Item On Island": lambda state: logic.can_get_hidden_items(state, world, + player) and logic.can_surf(state, world, player), + "Victory Road 2F - Hidden Item Rock Before Moltres": lambda state: logic.can_get_hidden_items(state, world, player), - "Victory Road 2F - Hidden Item Rock In Final Room": lambda state: logic.can_get_hidden_items(state, player), - "Viridian City - Hidden Item Cuttable Tree": lambda state: logic.can_get_hidden_items(state, player), - "Route 11 - Hidden Item Isolated Bush Near Gate": lambda state: logic.can_get_hidden_items(state, player), - "Route 12 - Hidden Item Bush Near Gate": lambda state: logic.can_get_hidden_items(state, player), - "Route 17 - Hidden Item In Grass": lambda state: logic.can_get_hidden_items(state, player), - "Route 17 - Hidden Item Near Northernmost Sign": lambda state: logic.can_get_hidden_items(state, player), - "Route 17 - Hidden Item East Center": lambda state: logic.can_get_hidden_items(state, player), - "Route 17 - Hidden Item West Center": lambda state: logic.can_get_hidden_items(state, player), - "Route 17 - Hidden Item Before Final Bridge": lambda state: logic.can_get_hidden_items(state, player), + "Victory Road 2F - Hidden Item Rock In Final Room": lambda state: logic.can_get_hidden_items(state, world, player), + "Viridian City - Hidden Item Cuttable Tree": lambda state: logic.can_get_hidden_items(state, world, player), + "Route 11 - Hidden Item Isolated Bush Near Gate": lambda state: logic.can_get_hidden_items(state, world, player), + "Route 12 - Hidden Item Bush Near Gate": lambda state: logic.can_get_hidden_items(state, world, player), + "Route 17 - Hidden Item In Grass": lambda state: logic.can_get_hidden_items(state, world, player), + "Route 17 - Hidden Item Near Northernmost Sign": lambda state: logic.can_get_hidden_items(state, world, player), + "Route 17 - Hidden Item East Center": lambda state: logic.can_get_hidden_items(state, world, player), + "Route 17 - Hidden Item West Center": lambda state: logic.can_get_hidden_items(state, world, player), + "Route 17 - Hidden Item Before Final Bridge": lambda state: logic.can_get_hidden_items(state, world, player), "Underground Path North South - Hidden Item Near Northern Stairs": lambda - state: logic.can_get_hidden_items(state, player), + state: logic.can_get_hidden_items(state, world, player), "Underground Path North South - Hidden Item Near Southern Stairs": lambda - state: logic.can_get_hidden_items(state, player), - "Underground Path West East - Hidden Item West": lambda state: logic.can_get_hidden_items(state, player), - "Underground Path West East - Hidden Item East": lambda state: logic.can_get_hidden_items(state, player), - "Celadon City - Hidden Item Dead End Near Cuttable Tree": lambda state: logic.can_get_hidden_items(state, + state: logic.can_get_hidden_items(state, world, player), + "Underground Path West East - Hidden Item West": lambda state: logic.can_get_hidden_items(state, world, player), + "Underground Path West East - Hidden Item East": lambda state: logic.can_get_hidden_items(state, world, player), + "Celadon City - Hidden Item Dead End Near Cuttable Tree": lambda state: logic.can_get_hidden_items(state, world, player), - "Route 25 - Hidden Item Northeast Of Grass": lambda state: logic.can_get_hidden_items(state, player), - "Mt Moon B2F - Hidden Item Lone Rock": lambda state: logic.can_get_hidden_items(state, player), - "Vermilion City - Hidden Item In Water Near Fan Club": lambda state: logic.can_get_hidden_items(state, - player) and logic.can_surf(state, player), - "Cerulean City - Hidden Item Gym Badge Guy's Backyard": lambda state: logic.can_get_hidden_items(state, + "Route 25 - Hidden Item Northeast Of Grass": lambda state: logic.can_get_hidden_items(state, world, player), + "Mt Moon B2F - Hidden Item Lone Rock": lambda state: logic.can_get_hidden_items(state, world, player), + "Vermilion City - Hidden Item In Water Near Fan Club": lambda state: logic.can_get_hidden_items(state, world, + player) and logic.can_surf(state, world, player), + "Cerulean City - Hidden Item Gym Badge Guy's Backyard": lambda state: logic.can_get_hidden_items(state, world, player), - "Route 4 - Hidden Item Plateau East Of Mt Moon": lambda state: logic.can_get_hidden_items(state, player), + "Route 4 - Hidden Item Plateau East Of Mt Moon": lambda state: logic.can_get_hidden_items(state, world, player), # Evolutions "Evolution - Ivysaur": lambda state: state.has("Bulbasaur", player) and logic.evolve_level(state, 16, player), @@ -281,5 +273,4 @@ def set_rules(multiworld, player): if loc.name.startswith("Pokedex"): mon = loc.name.split(" - ")[1] add_rule(loc, lambda state, i=mon: (state.has("Pokedex", player) or not - state.multiworld.require_pokedex[player]) and (state.has(i, player) - or state.has(f"Static {i}", player))) + world.options.require_pokedex) and (state.has(i, player) or state.has(f"Static {i}", player)))