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 <alchav@jalchavware.com> Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
This commit is contained in:
parent
51a6dc150c
commit
db5d9fbf70
|
@ -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"
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -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?
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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, [])
|
||||
}
|
||||
|
|
|
@ -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()
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
break
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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 in<LINE>Vermilion City<CONT>"
|
||||
elif r == 1:
|
||||
mon = self.trade_mons["Trade_Lola"]
|
||||
mon = world.trade_mons["Trade_Lola"]
|
||||
text = "A man in<LINE>Cerulean City<CONT>"
|
||||
elif r == 2:
|
||||
mon = self.trade_mons["Trade_Marcel"]
|
||||
mon = world.trade_mons["Trade_Marcel"]
|
||||
text = "Someone on Route 2<LINE>"
|
||||
elif r == 3:
|
||||
mon = self.trade_mons["Trade_Spot"]
|
||||
mon = world.trade_mons["Trade_Spot"]
|
||||
text = "Someone on Route 5<LINE>"
|
||||
if not a:
|
||||
answers.append(0)
|
||||
|
@ -38,21 +38,30 @@ def write_quizzes(self, data, random):
|
|||
|
||||
return encode_text(f"{text}was looking for<CONT>{mon}?<DONE>")
|
||||
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 playing<LINE>in a multiworld<CONT>with other<CONT>players?<DONE>")
|
||||
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 was<LINE>found by<CONT>") + player_name + encode_text("<DONE>")
|
||||
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 was<LINE>found by<CONT>") + player_name + encode_text("?<DONE>")
|
||||
else:
|
||||
# Might not have found it yet
|
||||
if player_name == world.multiworld.player_name[world.player]:
|
||||
return encode_text(f"The Secret Key was<LINE>placed in<CONT>your own world?<DONE>")
|
||||
player_name = encode_text(player_name, force=True, safety=True)
|
||||
return (encode_text(f"The Secret Key was<LINE>placed in<CONT>") + player_name
|
||||
+ encode_text("'s<CONT>world?<DONE>"))
|
||||
elif q == 2:
|
||||
if a:
|
||||
return encode_text(f"#mon is<LINE>pronounced<CONT>Po-kay-mon?<DONE>")
|
||||
|
@ -62,8 +71,8 @@ def write_quizzes(self, data, random):
|
|||
else:
|
||||
return encode_text(f"#mon is<LINE>pronounced<CONT>Po-kuh-mon?<DONE>")
|
||||
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}<LINE>times?<DONE>")
|
||||
elif q == 7:
|
||||
entity = "Motor Carrier"
|
||||
if not a:
|
||||
entity = random.choice(["Driver", "Shipper"])
|
||||
return encode_text("Title 49 of the<LINE>U.S. Code of<CONT>Federal<CONT>Regulations part<CONT>397.67 states"
|
||||
f"<CONT>that the<CONT>{entity}<CONT>is responsible<CONT>for planning<CONT>routes when"
|
||||
"<CONT>hazardous<CONT>materials are<CONT>transported?<DONE>")
|
||||
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 the<LINE>U.S. Code of<CONT>Federal<CONT>Regulations part<CONT>397.67 "
|
||||
f"states<CONT>that the<CONT>{entity}<CONT>is responsible<CONT>for planning<CONT>"
|
||||
"routes when<CONT>hazardous<CONT>materials are<CONT>transported?<DONE>")
|
||||
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,<LINE>{state}<CONT>has a law<CONT>requiring all<CONT>front seat vehicle<CONT>occupants to use<CONT>seatbelts?<DONE>")
|
||||
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,<LINE>drivers in<CONT>{country}<CONT>drive on the<CONT>right side of<CONT>the road?<DONE>")
|
||||
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} evolves<LINE>at level {level}?<DONE>")
|
||||
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<LINE>{question_type} type?<DONE>")
|
||||
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<LINE>{question_type} type?<DONE>")
|
||||
elif q == 11:
|
||||
|
@ -147,8 +180,8 @@ def write_quizzes(self, data, random):
|
|||
return encode_text(f"{equation}<LINE>= {question_result}?<DONE>")
|
||||
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<CONT>", "no ", "not very<CONT>effective<CONT>", "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<LINE>{eff}damage to<CONT>{type2} type?<DONE>")
|
||||
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 #MON<LINE>revive at level<CONT>{fossil_level}?<DONE>")
|
||||
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 to<LINE>Monash Uni.,<CONT>{fodmap} {are_is}<CONT>considered high<CONT>in FODMAPs?<DONE>")
|
||||
|
||||
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):
|
|||
"<PARA>Oh wait there,<LINE>the road's closed.<DONE>"),
|
||||
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: <LINE>{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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)))
|
||||
|
|
Loading…
Reference in New Issue