diff --git a/PokemonClient.py b/PokemonClient.py index eb1f1243..e78e76fa 100644 --- a/PokemonClient.py +++ b/PokemonClient.py @@ -17,7 +17,7 @@ from CommonClient import CommonContext, server_loop, gui_enabled, ClientCommandP from worlds.pokemon_rb.locations import location_data from worlds.pokemon_rb.rom import RedDeltaPatch, BlueDeltaPatch -location_map = {"Rod": {}, "EventFlag": {}, "Missable": {}, "Hidden": {}, "list": {}} +location_map = {"Rod": {}, "EventFlag": {}, "Missable": {}, "Hidden": {}, "list": {}, "DexSanityFlag": {}} location_bytes_bits = {} for location in location_data: if location.ram_address is not None: @@ -40,7 +40,7 @@ CONNECTION_INITIAL_STATUS = "Connection has not been initiated" DISPLAY_MSGS = True -SCRIPT_VERSION = 1 +SCRIPT_VERSION = 3 class GBCommandProcessor(ClientCommandProcessor): @@ -70,6 +70,8 @@ class GBContext(CommonContext): self.set_deathlink = False self.client_compatibility_mode = 0 self.items_handling = 0b001 + self.sent_release = False + self.sent_collect = False async def server_auth(self, password_requested: bool = False): if password_requested and not self.password: @@ -124,7 +126,8 @@ def get_payload(ctx: GBContext): "items": [item.item for item in ctx.items_received], "messages": {f'{key[0]}:{key[1]}': value for key, value in ctx.messages.items() if key[0] > current_time - 10}, - "deathlink": ctx.deathlink_pending + "deathlink": ctx.deathlink_pending, + "options": ((ctx.permissions['release'] in ('goal', 'enabled')) * 2) + (ctx.permissions['collect'] in ('goal', 'enabled')) } ) ctx.deathlink_pending = False @@ -134,10 +137,13 @@ def get_payload(ctx: GBContext): async def parse_locations(data: List, ctx: GBContext): locations = [] flags = {"EventFlag": data[:0x140], "Missable": data[0x140:0x140 + 0x20], - "Hidden": data[0x140 + 0x20: 0x140 + 0x20 + 0x0E], "Rod": data[0x140 + 0x20 + 0x0E:]} + "Hidden": data[0x140 + 0x20: 0x140 + 0x20 + 0x0E], + "Rod": data[0x140 + 0x20 + 0x0E:0x140 + 0x20 + 0x0E + 0x01]} - if len(flags['Rod']) > 1: - return + if len(data) > 0x140 + 0x20 + 0x0E + 0x01: + flags["DexSanityFlag"] = data[0x140 + 0x20 + 0x0E + 0x01:] + else: + flags["DexSanityFlag"] = [0] * 19 for flag_type, loc_map in location_map.items(): for flag, loc_id in loc_map.items(): @@ -207,6 +213,16 @@ async def gb_sync_task(ctx: GBContext): async_start(parse_locations(data_decoded['locations'], ctx)) if 'deathLink' in data_decoded and data_decoded['deathLink'] and 'DeathLink' in ctx.tags: await ctx.send_death(ctx.auth + " is out of usable Pokémon! " + ctx.auth + " blacked out!") + if 'options' in data_decoded: + msgs = [] + if data_decoded['options'] & 4 and not ctx.sent_release: + ctx.sent_release = True + msgs.append({"cmd": "Say", "text": "!release"}) + if data_decoded['options'] & 8 and not ctx.sent_collect: + ctx.sent_collect = True + msgs.append({"cmd": "Say", "text": "!collect"}) + if msgs: + await ctx.send_msgs(msgs) if ctx.set_deathlink: await ctx.update_death_link(True) except asyncio.TimeoutError: diff --git a/data/lua/PKMN_RB/pkmn_rb.lua b/data/lua/PKMN_RB/pkmn_rb.lua index eaf75165..036f7a62 100644 --- a/data/lua/PKMN_RB/pkmn_rb.lua +++ b/data/lua/PKMN_RB/pkmn_rb.lua @@ -7,7 +7,7 @@ local STATE_TENTATIVELY_CONNECTED = "Tentatively Connected" local STATE_INITIAL_CONNECTION_MADE = "Initial Connection Made" local STATE_UNINITIALIZED = "Uninitialized" -local SCRIPT_VERSION = 1 +local SCRIPT_VERSION = 3 local APIndex = 0x1A6E local APDeathLinkAddress = 0x00FD @@ -16,7 +16,8 @@ local EventFlagAddress = 0x1735 local MissableAddress = 0x161A local HiddenItemsAddress = 0x16DE local RodAddress = 0x1716 -local InGame = 0x1A71 +local DexSanityAddress = 0x1A71 +local InGameAddress = 0x1A84 local ClientCompatibilityAddress = 0xFF00 local ItemsReceived = nil @@ -34,6 +35,7 @@ local frame = 0 local u8 = nil local wU8 = nil local u16 +local compat = nil local function defineMemoryFunctions() local memDomain = {} @@ -70,18 +72,6 @@ function slice (tbl, s, e) return new end -function processBlock(block) - if block == nil then - return - end - local itemsBlock = block["items"] - memDomain.wram() - if itemsBlock ~= nil then - ItemsReceived = itemsBlock - end - deathlink_rec = block["deathlink"] -end - function difference(a, b) local aa = {} for k,v in pairs(a) do aa[v]=true end @@ -99,6 +89,7 @@ function generateLocationsChecked() events = uRange(EventFlagAddress, 0x140) missables = uRange(MissableAddress, 0x20) hiddenitems = uRange(HiddenItemsAddress, 0x0E) + dexsanity = uRange(DexSanityAddress, 19) rod = u8(RodAddress) data = {} @@ -108,6 +99,9 @@ function generateLocationsChecked() table.foreach(hiddenitems, function(k, v) table.insert(data, v) end) table.insert(data, rod) + if compat > 1 then + table.foreach(dexsanity, function(k, v) table.insert(data, v) end) + end return data end @@ -141,7 +135,15 @@ function receive() return end if l ~= nil then - processBlock(json.decode(l)) + block = json.decode(l) + if block ~= nil then + local itemsBlock = block["items"] + if itemsBlock ~= nil then + ItemsReceived = itemsBlock + end + deathlink_rec = block["deathlink"] + + end end -- Determine Message to send back memDomain.rom() @@ -156,15 +158,31 @@ function receive() seedName = newSeedName local retTable = {} retTable["scriptVersion"] = SCRIPT_VERSION - retTable["clientCompatibilityVersion"] = u8(ClientCompatibilityAddress) + + if compat == nil then + compat = u8(ClientCompatibilityAddress) + if compat < 2 then + InGameAddress = 0x1A71 + end + end + + retTable["clientCompatibilityVersion"] = compat retTable["playerName"] = playerName retTable["seedName"] = seedName memDomain.wram() - if u8(InGame) == 0xAC then + + in_game = u8(InGameAddress) + if in_game == 0x2A or in_game == 0xAC then retTable["locations"] = generateLocationsChecked() + elseif in_game ~= 0 then + print("Game may have crashed") + curstate = STATE_UNINITIALIZED + return end + retTable["deathLink"] = deathlink_send deathlink_send = false + msg = json.encode(retTable).."\n" local ret, error = gbSocket:send(msg) if ret == nil then @@ -193,16 +211,23 @@ function main() if (curstate == STATE_OK) or (curstate == STATE_INITIAL_CONNECTION_MADE) or (curstate == STATE_TENTATIVELY_CONNECTED) then if (frame % 5 == 0) then receive() - if u8(InGame) == 0xAC and u8(APItemAddress) == 0x00 then - ItemIndex = u16(APIndex) - if deathlink_rec == true then - wU8(APDeathLinkAddress, 1) - elseif u8(APDeathLinkAddress) == 3 then - wU8(APDeathLinkAddress, 0) - deathlink_send = true - end - if ItemsReceived[ItemIndex + 1] ~= nil then - wU8(APItemAddress, ItemsReceived[ItemIndex + 1] - 172000000) + in_game = u8(InGameAddress) + if in_game == 0x2A or in_game == 0xAC then + if u8(APItemAddress) == 0x00 then + ItemIndex = u16(APIndex) + if deathlink_rec == true then + wU8(APDeathLinkAddress, 1) + elseif u8(APDeathLinkAddress) == 3 then + wU8(APDeathLinkAddress, 0) + deathlink_send = true + end + if ItemsReceived[ItemIndex + 1] ~= nil then + item_id = ItemsReceived[ItemIndex + 1] - 172000000 + if item_id > 255 then + item_id = item_id - 256 + end + wU8(APItemAddress, item_id) + end end end end diff --git a/worlds/pokemon_rb/__init__.py b/worlds/pokemon_rb/__init__.py index 88813ad9..cea26d46 100644 --- a/worlds/pokemon_rb/__init__.py +++ b/worlds/pokemon_rb/__init__.py @@ -15,7 +15,7 @@ from .options import pokemon_rb_options from .rom_addresses import rom_addresses from .text import encode_text from .rom import generate_output, get_base_rom_bytes, get_base_rom_path, process_pokemon_data, process_wild_pokemon,\ - process_static_pokemon + process_static_pokemon, process_move_data from .rules import set_rules import worlds.pokemon_rb.poke_data as poke_data @@ -40,13 +40,14 @@ class PokemonRedBlueWorld(World): game = "Pokemon Red and Blue" option_definitions = pokemon_rb_options - data_version = 5 - required_client_version = (0, 3, 7) + data_version = 7 + required_client_version = (0, 3, 9) topology_present = False item_name_to_id = {name: data.id for name, data in item_table.items()} - location_name_to_id = {location.name: location.address for location in location_data if location.type == "Item"} + location_name_to_id = {location.name: location.address for location in location_data if location.type == "Item" + and location.address is not None} item_name_groups = item_groups web = PokemonWebWorld() @@ -58,11 +59,14 @@ class PokemonRedBlueWorld(World): self.extra_badges = {} self.type_chart = None self.local_poke_data = None + self.local_move_data = None + self.local_tms = None self.learnsets = None self.trainer_name = None self.rival_name = None self.type_chart = None self.traps = None + self.trade_mons = {} @classmethod def stage_assert_generate(cls, multiworld: MultiWorld): @@ -94,6 +98,12 @@ class PokemonRedBlueWorld(World): if len(self.multiworld.player_name[self.player].encode()) > 16: raise Exception(f"Player name too long for {self.multiworld.get_player_name(self.player)}. Player name cannot exceed 16 bytes for Pokémon Red and Blue.") + if (self.multiworld.dexsanity[self.player] and self.multiworld.accessibility[self.player] == "locations" + and (self.multiworld.catch_em_all[self.player] != "all_pokemon" + or self.multiworld.randomize_wild_pokemon[self.player] == "vanilla" + or self.multiworld.randomize_legendary_pokemon[self.player] != "any")): + self.multiworld.accessibility[self.player] = self.multiworld.accessibility[self.player].from_text("items") + if self.multiworld.badges_needed_for_hm_moves[self.player].value >= 2: badges_to_add = ["Marsh Badge", "Volcano Badge", "Earth Badge"] if self.multiworld.badges_needed_for_hm_moves[self.player].value == 3: @@ -107,6 +117,7 @@ class PokemonRedBlueWorld(World): for badge in badges_to_add: self.extra_badges[hm_moves.pop()] = badge + process_move_data(self) process_pokemon_data(self) if self.multiworld.randomize_type_chart[self.player] == "vanilla": @@ -178,8 +189,13 @@ class PokemonRedBlueWorld(World): if self.multiworld.randomize_pokedex[self.player] == "start_with": start_inventory["Pokedex"] = 1 self.multiworld.push_precollected(self.create_item("Pokedex")) + locations = [location for location in location_data if location.type == "Item"] item_pool = [] + combined_traps = (self.multiworld.poison_trap_weight[self.player].value + + self.multiworld.fire_trap_weight[self.player].value + + self.multiworld.paralyze_trap_weight[self.player].value + + self.multiworld.ice_trap_weight[self.player].value) for location in locations: if not location.inclusion(self.multiworld, self.player): continue @@ -189,9 +205,18 @@ class PokemonRedBlueWorld(World): item = self.create_filler() elif location.original_item is None: item = self.create_filler() + elif location.original_item == "Pokedex": + if self.multiworld.randomize_pokedex[self.player] == "vanilla": + self.multiworld.get_location(location.name, self.player).event = True + location.event = True + item = self.create_item("Pokedex") + elif location.original_item.startswith("TM"): + if self.multiworld.randomize_tm_moves[self.player]: + item = self.create_item(location.original_item.split(" ")[0]) + else: + item = self.create_item(location.original_item) else: item = self.create_item(location.original_item) - 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 if (item.classification == ItemClassification.filler and self.multiworld.random.randint(1, 100) <= self.multiworld.trap_percentage[self.player].value and combined_traps != 0): item = self.create_item(self.select_trap()) @@ -205,9 +230,62 @@ class PokemonRedBlueWorld(World): self.multiworld.itempool += item_pool def pre_fill(self) -> None: - process_wild_pokemon(self) process_static_pokemon(self) + pokemon_locs = [location.name for location in location_data if location.type != "Item"] + for location in self.multiworld.get_locations(self.player): + if location.name in pokemon_locs: + location.show_in_spoiler = False + + def intervene(move): + accessible_slots = [loc for loc in self.multiworld.get_reachable_locations(test_state, self.player) if loc.type == "Wild Encounter"] + move_bit = pow(2, poke_data.hm_moves.index(move) + 2) + viable_mons = [mon for mon in self.local_poke_data if self.local_poke_data[mon]["tms"][6] & move_bit] + placed_mons = [slot.item.name for slot in accessible_slots] + # this sort method doesn't seem to work if you reference the same list being sorted in the lambda + placed_mons_copy = placed_mons.copy() + placed_mons.sort(key=lambda i: placed_mons_copy.count(i)) + placed_mon = placed_mons.pop() + if self.multiworld.area_1_to_1_mapping[self.player]: + zone = " - ".join(placed_mon.split(" - ")[:-1]) + replace_slots = [slot for slot in accessible_slots if slot.name.startswith(zone) and slot.item.name == + placed_mon] + else: + replace_slots = [self.multiworld.random.choice([slot for slot in accessible_slots if slot.item.name == + placed_mon])] + replace_mon = self.multiworld.random.choice(viable_mons) + for replace_slot in replace_slots: + replace_slot.item = self.create_item(replace_mon) + last_intervene = None + while True: + intervene_move = None + test_state = self.multiworld.get_all_state(False) + if not self.multiworld.badgesanity[self.player]: + for badge in ["Boulder Badge", "Cascade Badge", "Thunder Badge", "Rainbow Badge", "Soul Badge", + "Marsh Badge", "Volcano Badge", "Earth Badge"]: + test_state.collect(self.create_item(badge)) + if not test_state.pokemon_rb_can_surf(self.player): + intervene_move = "Surf" + if not test_state.pokemon_rb_can_strength(self.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 + if (self.multiworld.accessibility[self.player] != "minimal" or ((not + self.multiworld.badgesanity[self.player]) and max(self.multiworld.elite_four_condition[self.player], + self.multiworld.victory_road_condition[self.player]) > 7)): + if not test_state.pokemon_rb_can_cut(self.player): + intervene_move = "Cut" + if (self.multiworld.accessibility[self.player].current_key != "minimal" and + (self.multiworld.trainersanity[self.player] or self.multiworld.extra_key_items[self.player])): + if not test_state.pokemon_rb_can_flash(self.player): + intervene_move = "Flash" + if intervene_move: + if intervene_move == last_intervene: + raise Exception(f"Caught in infinite loop attempting to ensure {intervene_move} is available to player {self.player}") + intervene(intervene_move) + last_intervene = intervene_move + else: + break if self.multiworld.old_man[self.player].value == 1: self.multiworld.local_early_items[self.player]["Oak's Parcel"] = 1 @@ -237,17 +315,26 @@ class PokemonRedBlueWorld(World): else: raise FillError(f"Failed to place badges for player {self.player}") - locs = [self.multiworld.get_location("Fossil - Choice A", self.player), - self.multiworld.get_location("Fossil - Choice B", self.player)] - for loc in locs: - add_item_rule(loc, lambda i: i.advancement or i.name in self.item_name_groups["Unique"] - or i.name == "Master Ball") + # Place local items in some locations to prevent save-scumming. Also Oak's PC to prevent an "AP Item" from + # entering the player's inventory. + + locs = {self.multiworld.get_location("Fossil - Choice A", self.player), + self.multiworld.get_location("Fossil - Choice B", self.player)} + + if self.multiworld.dexsanity[self.player]: + for mon in ([" ".join(self.multiworld.get_location( + f"Pallet Town - Starter {i}", self.player).item.name.split(" ")[1:]) for i in range(1, 4)] + + [" ".join(self.multiworld.get_location( + f"Fighting Dojo - Gift {i}", self.player).item.name.split(" ")[1:]) for i in range(1, 3)]): + loc = self.multiworld.get_location(f"Pokedex - {mon}", self.player) + if loc.item is None: + locs.add(loc) loc = self.multiworld.get_location("Pallet Town - Player's PC", self.player) if loc.item is None: - locs.append(loc) + locs.add(loc) - for loc in locs: + for loc in sorted(locs): unplaced_items = [] if loc.name in self.multiworld.priority_locations[self.player].value: add_item_rule(loc, lambda i: i.advancement) @@ -262,21 +349,6 @@ class PokemonRedBlueWorld(World): unplaced_items.append(item) self.multiworld.itempool += unplaced_items - intervene = False - test_state = self.multiworld.get_all_state(False) - if not test_state.pokemon_rb_can_surf(self.player) or not test_state.pokemon_rb_can_strength(self.player): - intervene = True - elif self.multiworld.accessibility[self.player].current_key != "minimal": - if not test_state.pokemon_rb_can_cut(self.player) or not test_state.pokemon_rb_can_flash(self.player): - intervene = True - if intervene: - # the way this is handled will be improved significantly in the future when I add options to - # let you choose the exact weights for HM compatibility - logging.warning( - f"HM-compatible Pokémon possibly missing, placing Mew on Route 1 for player {self.player}") - loc = self.multiworld.get_location("Route 1 - Wild Pokemon - 1", self.player) - loc.item = self.create_item("Mew") - def create_regions(self): if self.multiworld.free_fly_location[self.player].value: if self.multiworld.old_man[self.player].value == 0: @@ -317,6 +389,12 @@ class PokemonRedBlueWorld(World): 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") + spoiler_handle.write(f"\n\nPokémon locations ({self.multiworld.player_name[self.player]}):\n\n") + pokemon_locs = [location.name for location in location_data if location.type != "Item"] + for location in self.multiworld.get_locations(self.player): + if location.name in pokemon_locs: + 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 @@ -336,6 +414,21 @@ class PokemonRedBlueWorld(World): self.traps += ["Ice Trap"] * self.multiworld.ice_trap_weight[self.player].value return self.multiworld.random.choice(self.traps) + def extend_hint_information(self, hint_data): + if self.multiworld.dexsanity[self.player]: + hint_data[self.player] = {} + mon_locations = {mon: set() for mon in poke_data.pokemon_data.keys()} + for loc in location_data: #self.multiworld.get_locations(self.player): + if loc.type in ["Wild Encounter", "Static Pokemon", "Legendary Pokemon", "Missable Pokemon"]: + mon = self.multiworld.get_location(loc.name, self.player).item.name + if mon.startswith("Static ") or mon.startswith("Missable "): + mon = " ".join(mon.split(" ")[1:]) + mon_locations[mon].add(loc.name.split(" -")[0]) + for mon in mon_locations: + if mon_locations[mon]: + hint_data[self.player][self.multiworld.get_location(f"Pokedex - {mon}", self.player).address] = \ + ", ".join(mon_locations[mon]) + def fill_slot_data(self) -> dict: return { "second_fossil_check_condition": self.multiworld.second_fossil_check_condition[self.player].value, @@ -358,7 +451,8 @@ class PokemonRedBlueWorld(World): "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 + "death_link": self.multiworld.death_link[self.player].value, + "prizesanity": self.multiworld.prizesanity[self.player].value } diff --git a/worlds/pokemon_rb/basepatch_blue.bsdiff4 b/worlds/pokemon_rb/basepatch_blue.bsdiff4 index 6932762f..6123d714 100644 Binary files a/worlds/pokemon_rb/basepatch_blue.bsdiff4 and b/worlds/pokemon_rb/basepatch_blue.bsdiff4 differ diff --git a/worlds/pokemon_rb/basepatch_red.bsdiff4 b/worlds/pokemon_rb/basepatch_red.bsdiff4 index cd380e1f..efe4de42 100644 Binary files a/worlds/pokemon_rb/basepatch_red.bsdiff4 and b/worlds/pokemon_rb/basepatch_red.bsdiff4 differ diff --git a/worlds/pokemon_rb/docs/en_Pokemon Red and Blue.md b/worlds/pokemon_rb/docs/en_Pokemon Red and Blue.md index b857f234..556da203 100644 --- a/worlds/pokemon_rb/docs/en_Pokemon Red and Blue.md +++ b/worlds/pokemon_rb/docs/en_Pokemon Red and Blue.md @@ -33,6 +33,8 @@ fossil scientist. This may require reviving a number of fossils, depending on yo * If the Old Man is blocking your way through Viridian City, you do not have Oak's Parcel in your inventory, and you've exhausted your money and Poké Balls, you can get a free Poké Ball from your mom. * HM moves can be overwritten if you have the HM for it in your bag. +* The NPC on the left behind the Celadon Game Corner counter will sell 1500 coins at once instead of giving information +about the Prize Corner ## What items and locations get shuffled? diff --git a/worlds/pokemon_rb/items.py b/worlds/pokemon_rb/items.py index 8afde919..b30480ed 100644 --- a/worlds/pokemon_rb/items.py +++ b/worlds/pokemon_rb/items.py @@ -65,7 +65,7 @@ item_table = { "Super Repel": ItemData(56, ItemClassification.filler, ["Consumables"]), "Max Repel": ItemData(57, ItemClassification.filler, ["Consumables"]), "Dire Hit": ItemData(58, ItemClassification.filler, ["Consumables", "Battle Items"]), - #"Coin": ItemData(59, ItemClassification.filler), + "10 Coins": ItemData(59, ItemClassification.filler, ["Coins"]), "Fresh Water": ItemData(60, ItemClassification.filler, ["Consumables", "Vending Machine Drinks"]), "Soda Pop": ItemData(61, ItemClassification.filler, ["Consumables", "Vending Machine Drinks"]), "Lemonade": ItemData(62, ItemClassification.filler, ["Consumables", "Vending Machine Drinks"]), @@ -103,6 +103,8 @@ item_table = { "Paralyze Trap": ItemData(95, ItemClassification.trap, ["Traps"]), "Ice Trap": ItemData(96, ItemClassification.trap, ["Traps"]), "Fire Trap": ItemData(97, ItemClassification.trap, ["Traps"]), + "20 Coins": ItemData(98, ItemClassification.filler, ["Coins"]), + "100 Coins": ItemData(99, ItemClassification.filler, ["Coins"]), "HM01 Cut": ItemData(196, ItemClassification.progression, ["Unique", "HMs"]), "HM02 Fly": ItemData(197, ItemClassification.progression, ["Unique", "HMs"]), "HM03 Surf": ItemData(198, ItemClassification.progression, ["Unique", "HMs"]), @@ -119,7 +121,7 @@ item_table = { "TM09 Take Down": ItemData(209, ItemClassification.useful, ["Unique", "TMs"]), "TM10 Double Edge": ItemData(210, ItemClassification.useful, ["Unique", "TMs"]), "TM11 Bubble Beam": ItemData(211, ItemClassification.useful, ["Unique", "TMs"]), - "TM12 Water Gun": ItemData(212, ItemClassification.useful, ["Unique", "TMs"]), + "TM12 Water Gun": ItemData(212, ItemClassification.filler, ["Unique", "TMs"]), "TM13 Ice Beam": ItemData(213, ItemClassification.useful, ["Unique", "TMs"]), "TM14 Blizzard": ItemData(214, ItemClassification.useful, ["Unique", "TMs"]), "TM15 Hyper Beam": ItemData(215, ItemClassification.useful, ["Unique", "TMs"]), @@ -163,6 +165,10 @@ item_table = { "Silph Co Liberated": ItemData(None, ItemClassification.progression, []), "Become Champion": ItemData(None, ItemClassification.progression, []) } + +item_table.update({f"TM{str(i).zfill(2)}": ItemData(i + 456, ItemClassification.filler, ["Unique", "TMs"]) + for i in range(1, 51)}) + item_table.update( {pokemon: ItemData(None, ItemClassification.progression, []) for pokemon in pokemon_data.keys()} ) diff --git a/worlds/pokemon_rb/locations.py b/worlds/pokemon_rb/locations.py index 418ce9a9..d3af9a88 100644 --- a/worlds/pokemon_rb/locations.py +++ b/worlds/pokemon_rb/locations.py @@ -1,6 +1,8 @@ from BaseClasses import Location from .rom_addresses import rom_addresses +from .poke_data import pokemon_data + loc_id_start = 172000000 @@ -8,6 +10,10 @@ def trainersanity(multiworld, player): return multiworld.trainersanity[player] +def dexsanity(multiworld, player): + return multiworld.dexsanity[player] + + def hidden_items(multiworld, player): return multiworld.randomize_hidden_items[player].value > 0 @@ -20,14 +26,13 @@ def extra_key_items(multiworld, player): return multiworld.extra_key_items[player] -def pokedex(multiworld, player): - return multiworld.randomize_pokedex[player].value > 0 - - def always_on(multiworld, player): return True +def prizesanity(multiworld, player): + return multiworld.prizesanity[player] + class LocationData: @@ -72,6 +77,13 @@ class Rod: self.flag = flag +class DexSanityFlag: + def __init__(self, flag): + self.byte = int(flag / 8) + self.bit = flag % 8 + self.flag = flag + + location_data = [ LocationData("Vermilion City", "Fishing Guru", "Old Rod", rom_addresses["Rod_Vermilion_City_Fishing_Guru"], Rod(3)), @@ -119,7 +131,7 @@ location_data = [ LocationData("Celadon City", "Gambling Addict", "Coin Case", rom_addresses["Event_Gambling_Addict"], EventFlag(480)), LocationData("Celadon Gym", "Erika 2", "TM21 Mega Drain", rom_addresses["Event_Celadon_Gym"], EventFlag(424)), - LocationData("Silph Co 11F", "Silph Co President", "Master Ball", rom_addresses["Event_Silph_Co_President"], + LocationData("Silph Co 11F", "Silph Co President (Card Key)", "Master Ball", rom_addresses["Event_Silph_Co_President"], EventFlag(1933)), LocationData("Silph Co 2F", "Woman", "TM36 Self-Destruct", rom_addresses["Event_Scared_Woman"], EventFlag(1791)), @@ -374,7 +386,7 @@ location_data = [ LocationData("Seafoam Islands B4F", "Hidden Item Corner Island", "Ultra Ball", rom_addresses['Hidden_Item_Seafoam_Islands_B4F'], Hidden(26), inclusion=hidden_items), LocationData("Pokemon Mansion 1F", "Hidden Item Block Near Entrance Carpet", "Moon Stone", rom_addresses['Hidden_Item_Pokemon_Mansion_1F'], Hidden(27), inclusion=hidden_items), LocationData("Pokemon Mansion 3F", "Hidden Item Behind Burglar", "Max Revive", rom_addresses['Hidden_Item_Pokemon_Mansion_3F'], Hidden(28), inclusion=hidden_items), - LocationData("Route 23", "Hidden Item Rocks Before Final Guard", "Full Restore", rom_addresses['Hidden_Item_Route_23_1'], Hidden(29), inclusion=hidden_items), + LocationData("Route 23", "Hidden Item Rocks Before Victory Road", "Full Restore", rom_addresses['Hidden_Item_Route_23_1'], Hidden(29), inclusion=hidden_items), LocationData("Route 23", "Hidden Item East Bush After Water", "Ultra Ball", rom_addresses['Hidden_Item_Route_23_2'], Hidden(30), inclusion=hidden_items), LocationData("Route 23", "Hidden Item On Island", "Max Ether", rom_addresses['Hidden_Item_Route_23_3'], Hidden(31), inclusion=hidden_items), LocationData("Victory Road 2F", "Hidden Item Rock Before Moltres", "Ultra Ball", rom_addresses['Hidden_Item_Victory_Road_2F_1'], Hidden(32), inclusion=hidden_items), @@ -400,7 +412,8 @@ location_data = [ LocationData("Cerulean City", "Hidden Item Gym Badge Guy's Backyard", "Rare Candy", rom_addresses['Hidden_Item_Cerulean_City'], Hidden(52), inclusion=hidden_items), LocationData("Route 4", "Hidden Item Plateau East Of Mt Moon", "Great Ball", rom_addresses['Hidden_Item_Route_4'], Hidden(53), inclusion=hidden_items), - LocationData("Pallet Town", "Oak's Parcel Reward", "Pokedex", rom_addresses["Event_Pokedex"], EventFlag(0x38), inclusion=pokedex), + + LocationData("Pallet Town", "Oak's Parcel Reward", "Pokedex", rom_addresses["Event_Pokedex"], EventFlag(0x38)), LocationData("Pokemon Mansion 1F", "Scientist", None, rom_addresses["Trainersanity_EVENT_BEAT_MANSION_1_TRAINER_0_ITEM"], EventFlag(376), inclusion=trainersanity), LocationData("Pokemon Mansion 2F", "Burglar", None, rom_addresses["Trainersanity_EVENT_BEAT_MANSION_2_TRAINER_0_ITEM"], EventFlag(43), inclusion=trainersanity), @@ -712,6 +725,36 @@ location_data = [ LocationData("Indigo Plateau", "Bruno", None, rom_addresses["Trainersanity_EVENT_BEAT_BRUNOS_ROOM_TRAINER_0_ITEM"], EventFlag(20), inclusion=trainersanity), LocationData("Indigo Plateau", "Agatha", None, rom_addresses["Trainersanity_EVENT_BEAT_AGATHAS_ROOM_TRAINER_0_ITEM"], EventFlag(19), inclusion=trainersanity), LocationData("Indigo Plateau", "Lance", None, rom_addresses["Trainersanity_EVENT_BEAT_LANCES_ROOM_TRAINER_0_ITEM"], EventFlag(18), inclusion=trainersanity), + LocationData("Cinnabar Gym", "Burglar 1", None, rom_addresses["Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_A_ITEM"], EventFlag(374), inclusion=trainersanity), + LocationData("Cinnabar Gym", "Super Nerd 1", None, rom_addresses["Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_B_ITEM"], EventFlag(373), inclusion=trainersanity), + LocationData("Cinnabar Gym", "Super Nerd 2", None, rom_addresses["Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_2_ITEM"], EventFlag(372), inclusion=trainersanity), + LocationData("Cinnabar Gym", "Burglar 2", None, rom_addresses["Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_3_ITEM"], EventFlag(371), inclusion=trainersanity), + LocationData("Cinnabar Gym", "Super Nerd 3", None, rom_addresses["Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_4_ITEM"], EventFlag(370), inclusion=trainersanity), + LocationData("Cinnabar Gym", "Super Nerd 4", None, rom_addresses["Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_5_ITEM"], EventFlag(369), inclusion=trainersanity), + LocationData("Cinnabar Gym", "Super Nerd 5", None, rom_addresses["Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_6_ITEM"], EventFlag(368), inclusion=trainersanity), + + LocationData("Celadon Prize Corner", "Item Prize 1", "TM23 Dragon Rage", rom_addresses["Prize_Item_A"], EventFlag(0x69a), inclusion=prizesanity), + LocationData("Celadon Prize Corner", "Item Prize 2", "TM15 Hyper Beam", rom_addresses["Prize_Item_B"], EventFlag(0x69B), inclusion=prizesanity), + LocationData("Celadon Prize Corner", "Item Prize 3", "TM50 Substitute", rom_addresses["Prize_Item_C"], EventFlag(0x69C), inclusion=prizesanity), + + LocationData("Celadon Game Corner", "West Gambler's Gift (Coin Case)", "10 Coins", rom_addresses["Event_Game_Corner_Gift_A"], EventFlag(0x1ba)), + LocationData("Celadon Game Corner", "Center Gambler's Gift (Coin Case)", "20 Coins", rom_addresses["Event_Game_Corner_Gift_C"], EventFlag(0x1bc)), + LocationData("Celadon Game Corner", "East Gambler's Gift (Coin Case)", "20 Coins", rom_addresses["Event_Game_Corner_Gift_B"], EventFlag(0x1bb)), + + LocationData("Celadon Game Corner", "Hidden Item Northwest By Counter (Coin Case)", "10 Coins", rom_addresses["Hidden_Item_Game_Corner_1"], Hidden(54), inclusion=hidden_items), + LocationData("Celadon Game Corner", "Hidden Item Southwest Corner (Coin Case)", "10 Coins", rom_addresses["Hidden_Item_Game_Corner_2"], Hidden(55), inclusion=hidden_items), + LocationData("Celadon Game Corner", "Hidden Item Near Rumor Man (Coin Case)", "20 Coins", rom_addresses["Hidden_Item_Game_Corner_3"], Hidden(56), inclusion=hidden_items), + LocationData("Celadon Game Corner", "Hidden Item Near Speculating Woman (Coin Case)", "10 Coins", rom_addresses["Hidden_Item_Game_Corner_4"], Hidden(57), inclusion=hidden_items), + LocationData("Celadon Game Corner", "Hidden Item Near West Gifting Gambler (Coin Case)", "10 Coins", rom_addresses["Hidden_Item_Game_Corner_5"], Hidden(58), inclusion=hidden_items), + LocationData("Celadon Game Corner", "Hidden Item Near Wonderful Time Woman (Coin Case)", "20 Coins", rom_addresses["Hidden_Item_Game_Corner_6"], Hidden(59), inclusion=hidden_items), + LocationData("Celadon Game Corner", "Hidden Item Near Failing Gym Information Guy (Coin Case)", "10 Coins", rom_addresses["Hidden_Item_Game_Corner_7"], Hidden(60), inclusion=hidden_items), + LocationData("Celadon Game Corner", "Hidden Item Near East Gifting Gambler (Coin Case)", "10 Coins", rom_addresses["Hidden_Item_Game_Corner_8"], Hidden(61), inclusion=hidden_items), + LocationData("Celadon Game Corner", "Hidden Item Near Hooked Guy (Coin Case)", "10 Coins", rom_addresses["Hidden_Item_Game_Corner_9"], Hidden(62), inclusion=hidden_items), + LocationData("Celadon Game Corner", "Hidden Item at End of Horizontal Machine Row (Coin Case)", "20 Coins", rom_addresses["Hidden_Item_Game_Corner_10"], Hidden(63), inclusion=hidden_items), + LocationData("Celadon Game Corner", "Hidden Item in Front of Horizontal Machine Row (Coin Case)", "100 Coins", rom_addresses["Hidden_Item_Game_Corner_11"], Hidden(64), inclusion=hidden_items), + + *[LocationData("Pokedex", mon, None, rom_addresses["Dexsanity_Items"] + i, DexSanityFlag(i), + type="Item", inclusion=dexsanity) for (mon, i) in zip(pokemon_data.keys(), range(0, 152))], LocationData("Indigo Plateau", "Become Champion", "Become Champion", event=True), LocationData("Pokemon Tower 7F", "Fuji Saved", "Fuji Saved", event=True), @@ -1965,6 +2008,25 @@ location_data = [ LocationData("Cinnabar Island", "Dome Fossil Pokemon", "Kabuto", rom_addresses["Gift_Kabuto"], None, event=True, type="Static Pokemon"), + LocationData("Route 2 East", "Marcel Trade", "Mr Mime", rom_addresses["Trade_Marcel"] + 1, None, event=True, + type="Static Pokemon"), + LocationData("Underground Tunnel North-South", "Spot Trade", "Nidoran F", rom_addresses["Trade_Spot"] + 1, None, + event=True, type="Static Pokemon"), + LocationData("Route 11", "Terry Trade", "Nidorina", rom_addresses["Trade_Terry"] + 1, None, event=True, + type="Static Pokemon"), + LocationData("Route 18", "Marc Trade", "Lickitung", rom_addresses["Trade_Marc"] + 1, None, event=True, + type="Static Pokemon"), + LocationData("Cinnabar Island", "Sailor Trade", "Seel", rom_addresses["Trade_Sailor"] + 1, None, event=True, + type="Static Pokemon"), + LocationData("Cinnabar Island", "Crinkles Trade", "Tangela", rom_addresses["Trade_Crinkles"] + 1, None, + event=True, type="Static Pokemon"), + LocationData("Cinnabar Island", "Doris Trade", "Electrode", rom_addresses["Trade_Doris"] + 1, None, + event=True, type="Static Pokemon"), + LocationData("Vermilion City", "Dux Trade", "Farfetchd", rom_addresses["Trade_Dux"] + 1, None, event=True, + type="Static Pokemon"), + LocationData("Cerulean City", "Lola Trade", "Jynx", rom_addresses["Trade_Lola"] + 1, None, event=True, + type="Static Pokemon"), + # not counted for logic currently. Could perhaps make static encounters resettable in the future? LocationData("Power Plant", "Fake Pokeball Battle 1", "Voltorb", rom_addresses["Static_Encounter_Voltorb_A"], None, event=True, type="Missable Pokemon"), @@ -2043,20 +2105,24 @@ location_data = [ ] -for i, location in enumerate(location_data): + + +i = 0 +for location in location_data: if location.event or location.rom_address is None: location.address = None else: location.address = loc_id_start + i - + i += 1 class PokemonRBLocation(Location): game = "Pokemon Red and Blue" - def __init__(self, player, name, address, rom_address): + def __init__(self, player, name, address, rom_address, type): super(PokemonRBLocation, self).__init__( player, name, address ) - self.rom_address = rom_address \ No newline at end of file + self.rom_address = rom_address + self.type = type diff --git a/worlds/pokemon_rb/logic.py b/worlds/pokemon_rb/logic.py index 70e825c2..8425bcdb 100644 --- a/worlds/pokemon_rb/logic.py +++ b/worlds/pokemon_rb/logic.py @@ -45,14 +45,13 @@ class PokemonLogic(LogicMixin): ["Boulder Badge", "Cascade Badge", "Thunder Badge", "Rainbow Badge", "Soul Badge", "Marsh Badge", "Volcano Badge", "Earth Badge", "Bicycle", "Silph Scope", "Item Finder", "Super Rod", "Good Rod", "Old Rod", "Lift Key", "Card Key", "Town Map", "Coin Case", "S.S. Ticket", "Secret Key", - "Mansion Key", "Safari Pass", "Plant Key", "Hideout Key", "HM01 Cut", "HM02 Fly", "HM03 Surf", - "HM04 Strength", "HM05 Flash"] if self.has(item, player)]) >= count + "Poke Flute", "Mansion Key", "Safari Pass", "Plant Key", "Hideout Key", "HM01 Cut", "HM02 Fly", + "HM03 Surf", "HM04 Strength", "HM05 Flash"] if self.has(item, player)]) >= count def pokemon_rb_can_pass_guards(self, player): if self.multiworld.tea[player].value: return self.has("Tea", player) else: - # this could just be "True", but you never know what weird options I might introduce later ;) return self.can_reach("Celadon City - Counter Man", "Location", player) def pokemon_rb_has_badges(self, count, player): @@ -60,13 +59,8 @@ class PokemonLogic(LogicMixin): "Soul Badge", "Volcano Badge", "Earth Badge"] if self.has(item, player)]) >= count def pokemon_rb_oaks_aide(self, count, player): - if self.multiworld.randomize_pokedex[player].value > 0: - if not self.has("Pokedex", player): - return False - else: - if not self.has("Oak's Parcel", player): - return False - return self.pokemon_rb_has_pokemon(count, player) + return ((not self.multiworld.require_pokedex[player] or self.has("Pokedex", player)) + and self.pokemon_rb_has_pokemon(count, player)) def pokemon_rb_has_pokemon(self, count, player): obtained_pokemon = set() diff --git a/worlds/pokemon_rb/options.py b/worlds/pokemon_rb/options.py index ae51c47b..b705e6f2 100644 --- a/worlds/pokemon_rb/options.py +++ b/worlds/pokemon_rb/options.py @@ -65,7 +65,7 @@ class CeruleanCaveCondition(Range): If extra_key_items is turned on, the number chosen will be increased by 4.""" display_name = "Cerulean Cave Condition" range_start = 0 - range_end = 25 + range_end = 26 default = 20 @@ -155,6 +155,12 @@ class RandomizeHiddenItems(Choice): default = 0 +class PrizeSanity(Toggle): + """Shuffles the TM prizes at the Celadon Prize Corner into the item pool.""" + display_name = "Prizesanity" + 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 @@ -163,12 +169,44 @@ class TrainerSanity(Toggle): default = 0 +class RequirePokedex(Toggle): + """Require the Pokedex to obtain items from Oak's Aides or from Dexsanity checks.""" + display_name = "Require Pokedex" + default = 1 + + +class AllPokemonSeen(Toggle): + """Start with all Pokemon "seen" in your Pokedex. This allows you to see where Pokemon can be encountered in the + wild. Pokemon found by fishing or in the Cerulean Cave are not displayed.""" + default = 0 + + +class DexSanity(Toggle): + """Adds a location check for each Pokemon flagged "Owned" on your Pokedex. If accessibility is set to `locations` + and randomize_wild_pokemon is off, catch_em_all is not `all_pokemon` or randomize_legendary_pokemon is not `any`, + accessibility will be forced to `items` instead, as not all Dexsanity locations can be guaranteed to be considered + reachable in logic. + 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.""" + display_name = "Dexsanity" + default = 0 + + class FreeFlyLocation(Toggle): """One random fly destination will be unlocked by default.""" display_name = "Free Fly Location" default = 1 +class RandomizeRockTunnel(Toggle): + """Randomize the layout of Rock Tunnel. This is highly experimental, if you encounter any issues (items or trainers + unreachable, trainers walking over walls, inability to reach end of tunnel, anything looking strange) to + Alchav#8826 in the Archipelago Discord (directly or in #pkmn-red-blue) along with the seed number found on the + signs outside the tunnel.""" + display_name = "Randomize Rock Tunnel" + default = 0 + + class OaksAidRt2(Range): """Number of Pokemon registered in the Pokedex required to receive the item from Oak's Aide on Route 2. Vanilla is 10.""" @@ -229,6 +267,12 @@ class RandomizeWildPokemon(Choice): option_completely_random = 4 +class Area1To1Mapping(Toggle): + """When randomizing wild Pokemon, for each zone, all instances of a particular Pokemon will be replaced with the + same Pokemon, resulting in fewer Pokemon in each area.""" + default = 1 + + class RandomizeStarterPokemon(Choice): """Randomize the starter Pokemon choices.""" display_name = "Randomize Starter Pokemon" @@ -334,6 +378,13 @@ class MinimumCatchRate(Range): default = 3 +class MoveBalancing(Toggle): + """All one-hit-KO moves and fixed-damage moves become normal damaging moves. + Blizzard, and moves that cause sleep have their accuracy reduced.""" + display_name = "Move Balancing" + default = 0 + + class RandomizePokemonMovesets(Choice): """Randomize the moves learned by Pokemon. prefer_types will prefer moves that match the type of the Pokemon.""" display_name = "Randomize Pokemon Movesets" @@ -343,6 +394,12 @@ class RandomizePokemonMovesets(Choice): default = 0 +class ConfineTranstormToDitto(Toggle): + """Regardless of moveset randomization, will keep Ditto's first move as Transform no others will learn it. + If an enemy Pokemon uses transform before you catch it, it will permanently change to Ditto after capture.""" + display_name = "Confine Transform to Ditto" + default = 1 + class StartWithFourMoves(Toggle): """If movesets are randomized, this will give all Pokemon 4 starting moves.""" display_name = "Start With Four Moves" @@ -356,30 +413,62 @@ class SameTypeAttackBonus(Toggle): default = 1 -class TMCompatibility(Choice): - """Randomize which Pokemon can learn each TM. prefer_types: 90% chance if Pokemon's type matches the move, - 50% chance if move is Normal type and the Pokemon is not, and 25% chance otherwise. Pokemon will retain the same - TM compatibility when they evolve if the evolved form has the same type(s). Mew will always be able to learn - every TM.""" - display_name = "TM Compatibility" - default = 0 - option_vanilla = 0 - option_prefer_types = 1 - option_completely_random = 2 - option_full_compatibility = 3 +class RandomizeTMMoves(Toggle): + """Randomize the moves taught by TMs. + All TM items will be flagged as 'filler' items regardless of how good the move they teach are.""" + display_name = "Randomize TM Moves" -class HMCompatibility(Choice): - """Randomize which Pokemon can learn each HM. prefer_types: 100% chance if Pokemon's type matches the move, - 75% chance if move is Normal type and the Pokemon is not, and 25% chance otherwise. Pokemon will retain the same - HM compatibility when they evolve if the evolved form has the same type(s). Mew will always be able to learn - every HM.""" - display_name = "HM Compatibility" - default = 0 - option_vanilla = 0 - option_prefer_types = 1 - option_completely_random = 2 - option_full_compatibility = 3 +class TMHMCompatibility(SpecialRange): + range_start = -1 + range_end = 100 + special_range_names = { + "vanilla": -1, + "none": 0, + "full": 100 + } + default = -1 + + +class TMSameTypeCompatibility(TMHMCompatibility): + """Chance of each TM being usable on each Pokemon whose type matches the move.""" + display_name = "TM Same-Type Compatibility" + + +class TMNormalTypeCompatibility(TMHMCompatibility): + """Chance of each TM being usable on each Pokemon if the move is Normal type and the Pokemon is not.""" + display_name = "TM Normal-Type Compatibility" + + +class TMOtherTypeCompatibility(TMHMCompatibility): + """Chance of each TM being usable on each Pokemon if the move a type other than Normal or one of the Pokemon's types.""" + display_name = "TM Other-Type Compatibility" + + +class HMSameTypeCompatibility(TMHMCompatibility): + """Chance of each HM being usable on each Pokemon whose type matches the move. + At least one Pokemon will always be able to learn the moves needed to meet your accessibility requirements.""" + display_name = "HM Same-Type Compatibility" + + +class HMNormalTypeCompatibility(TMHMCompatibility): + """Chance of each HM being usable on each Pokemon if the move is Normal type and the Pokemon is not. + At least one Pokemon will always be able to learn the moves needed to meet your accessibility requirements.""" + display_name = "HM Normal-Type Compatibility" + + +class HMOtherTypeCompatibility(TMHMCompatibility): + """Chance of each HM being usable on each Pokemon if the move a type other than Normal or one of the Pokemon's types. + At least one Pokemon will always be able to learn the moves needed to meet your accessibility requirements.""" + display_name = "HM Other-Type Compatibility" + + +class InheritTMHMCompatibility(Toggle): + """If on, evolved Pokemon will inherit their pre-evolved form's TM and HM compatibilities. + They will then roll the above set chances again at a 50% lower rate for all TMs and HMs their predecessor could not + learn, unless the evolved form has additional or different types, then moves of those new types will be rolled + at the full set chance.""" + display_name = "Inherit TM/HM Compatibility" class RandomizePokemonTypes(Choice): @@ -543,6 +632,17 @@ class IceTrapWeight(TrapWeight): default = 0 +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), + Completely Random will randomize all Pokemons' palettes individually""" + display_name = "Randomize Pokemon Palettes" + option_vanilla = 0 + option_primary_type = 1 + option_follow_evolutions = 2 + option_completely_random = 3 + + pokemon_rb_options = { "game_version": GameVersion, "trainer_name": TrainerName, @@ -561,16 +661,22 @@ pokemon_rb_options = { "extra_strength_boulders": ExtraStrengthBoulders, "require_item_finder": RequireItemFinder, "randomize_hidden_items": RandomizeHiddenItems, + "prizesanity": PrizeSanity, "trainersanity": TrainerSanity, - "badges_needed_for_hm_moves": BadgesNeededForHMMoves, - "free_fly_location": FreeFlyLocation, + "require_pokedex": RequirePokedex, + "all_pokemon_seen": AllPokemonSeen, + "dexsanity": DexSanity, "oaks_aide_rt_2": OaksAidRt2, "oaks_aide_rt_11": OaksAidRt11, "oaks_aide_rt_15": OaksAidRt15, + "badges_needed_for_hm_moves": BadgesNeededForHMMoves, + "free_fly_location": FreeFlyLocation, + "randomize_rock_tunnel": RandomizeRockTunnel, "blind_trainers": BlindTrainers, "minimum_steps_between_encounters": MinimumStepsBetweenEncounters, "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, @@ -580,11 +686,19 @@ pokemon_rb_options = { "minimum_catch_rate": MinimumCatchRate, "randomize_trainer_parties": RandomizeTrainerParties, "trainer_legendaries": TrainerLegendaries, + "move_balancing": MoveBalancing, "randomize_pokemon_movesets": RandomizePokemonMovesets, + "confine_transform_to_ditto": ConfineTranstormToDitto, "start_with_four_moves": StartWithFourMoves, "same_type_attack_bonus": SameTypeAttackBonus, - "tm_compatibility": TMCompatibility, - "hm_compatibility": HMCompatibility, + "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_pokemon_types": RandomizePokemonTypes, "secondary_type_chance": SecondaryTypeChance, "randomize_type_chart": RandomizeTypeChart, @@ -604,5 +718,6 @@ pokemon_rb_options = { "fire_trap_weight": FireTrapWeight, "paralyze_trap_weight": ParalyzeTrapWeight, "ice_trap_weight": IceTrapWeight, + "randomize_pokemon_palettes": RandomizePokemonPalettes, "death_link": DeathLink } diff --git a/worlds/pokemon_rb/poke_data.py b/worlds/pokemon_rb/poke_data.py index 691db1c4..6218c70a 100644 --- a/worlds/pokemon_rb/poke_data.py +++ b/worlds/pokemon_rb/poke_data.py @@ -1006,172 +1006,172 @@ learnsets = { } moves = { - 'No Move': {'id': 0, 'power': 0, 'type': 'Typeless', 'accuracy': 0, 'pp': 0}, - 'Pound': {'id': 1, 'power': 40, 'type': 'Normal', 'accuracy': 100, 'pp': 35}, - 'Karate Chop': {'id': 2, 'power': 50, 'type': 'Normal', 'accuracy': 100, 'pp': 25}, - 'Doubleslap': {'id': 3, 'power': 15, 'type': 'Normal', 'accuracy': 85, 'pp': 10}, - 'Comet Punch': {'id': 4, 'power': 18, 'type': 'Normal', 'accuracy': 85, 'pp': 15}, - 'Mega Punch': {'id': 5, 'power': 80, 'type': 'Normal', 'accuracy': 85, 'pp': 20}, - 'Pay Day': {'id': 6, 'power': 40, 'type': 'Normal', 'accuracy': 100, 'pp': 20}, - 'Fire Punch': {'id': 7, 'power': 75, 'type': 'Fire', 'accuracy': 100, 'pp': 15}, - 'Ice Punch': {'id': 8, 'power': 75, 'type': 'Ice', 'accuracy': 100, 'pp': 15}, - 'Thunderpunch': {'id': 9, 'power': 75, 'type': 'Electric', 'accuracy': 100, 'pp': 15}, - 'Scratch': {'id': 10, 'power': 40, 'type': 'Normal', 'accuracy': 100, 'pp': 35}, - 'Vicegrip': {'id': 11, 'power': 55, 'type': 'Normal', 'accuracy': 100, 'pp': 30}, - 'Guillotine': {'id': 12, 'power': 1, 'type': 'Normal', 'accuracy': 30, 'pp': 5}, - 'Razor Wind': {'id': 13, 'power': 80, 'type': 'Normal', 'accuracy': 75, 'pp': 10}, - 'Swords Dance': {'id': 14, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 30}, - 'Cut': {'id': 15, 'power': 50, 'type': 'Normal', 'accuracy': 95, 'pp': 30}, - 'Gust': {'id': 16, 'power': 40, 'type': 'Normal', 'accuracy': 100, 'pp': 35}, - 'Wing Attack': {'id': 17, 'power': 35, 'type': 'Flying', 'accuracy': 100, 'pp': 35}, - 'Whirlwind': {'id': 18, 'power': 0, 'type': 'Normal', 'accuracy': 85, 'pp': 20}, - 'Fly': {'id': 19, 'power': 70, 'type': 'Flying', 'accuracy': 95, 'pp': 15}, - 'Bind': {'id': 20, 'power': 15, 'type': 'Normal', 'accuracy': 75, 'pp': 20}, - 'Slam': {'id': 21, 'power': 80, 'type': 'Normal', 'accuracy': 75, 'pp': 20}, - 'Vine Whip': {'id': 22, 'power': 35, 'type': 'Grass', 'accuracy': 100, 'pp': 10}, - 'Stomp': {'id': 23, 'power': 65, 'type': 'Normal', 'accuracy': 100, 'pp': 20}, - 'Double Kick': {'id': 24, 'power': 30, 'type': 'Fighting', 'accuracy': 100, 'pp': 30}, - 'Mega Kick': {'id': 25, 'power': 120, 'type': 'Normal', 'accuracy': 75, 'pp': 5}, - 'Jump Kick': {'id': 26, 'power': 70, 'type': 'Fighting', 'accuracy': 95, 'pp': 25}, - 'Rolling Kick': {'id': 27, 'power': 60, 'type': 'Fighting', 'accuracy': 85, 'pp': 15}, - 'Sand Attack': {'id': 28, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 15}, - 'Headbutt': {'id': 29, 'power': 70, 'type': 'Normal', 'accuracy': 100, 'pp': 15}, - 'Horn Attack': {'id': 30, 'power': 65, 'type': 'Normal', 'accuracy': 100, 'pp': 25}, - 'Fury Attack': {'id': 31, 'power': 15, 'type': 'Normal', 'accuracy': 85, 'pp': 20}, - 'Horn Drill': {'id': 32, 'power': 1, 'type': 'Normal', 'accuracy': 30, 'pp': 5}, - 'Tackle': {'id': 33, 'power': 35, 'type': 'Normal', 'accuracy': 95, 'pp': 35}, - 'Body Slam': {'id': 34, 'power': 85, 'type': 'Normal', 'accuracy': 100, 'pp': 15}, - 'Wrap': {'id': 35, 'power': 15, 'type': 'Normal', 'accuracy': 85, 'pp': 20}, - 'Take Down': {'id': 36, 'power': 90, 'type': 'Normal', 'accuracy': 85, 'pp': 20}, - 'Thrash': {'id': 37, 'power': 90, 'type': 'Normal', 'accuracy': 100, 'pp': 20}, - 'Double Edge': {'id': 38, 'power': 100, 'type': 'Normal', 'accuracy': 100, 'pp': 15}, - 'Tail Whip': {'id': 39, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 30}, - 'Poison Sting': {'id': 40, 'power': 15, 'type': 'Poison', 'accuracy': 100, 'pp': 35}, - 'Twineedle': {'id': 41, 'power': 25, 'type': 'Bug', 'accuracy': 100, 'pp': 20}, - 'Pin Missile': {'id': 42, 'power': 14, 'type': 'Bug', 'accuracy': 85, 'pp': 20}, - 'Leer': {'id': 43, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 30}, - 'Bite': {'id': 44, 'power': 60, 'type': 'Normal', 'accuracy': 100, 'pp': 25}, - 'Growl': {'id': 45, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 40}, - 'Roar': {'id': 46, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 20}, - 'Sing': {'id': 47, 'power': 0, 'type': 'Normal', 'accuracy': 55, 'pp': 15}, - 'Supersonic': {'id': 48, 'power': 0, 'type': 'Normal', 'accuracy': 55, 'pp': 20}, - 'Sonicboom': {'id': 49, 'power': 1, 'type': 'Normal', 'accuracy': 90, 'pp': 20}, - 'Disable': {'id': 50, 'power': 0, 'type': 'Normal', 'accuracy': 55, 'pp': 20}, - 'Acid': {'id': 51, 'power': 40, 'type': 'Poison', 'accuracy': 100, 'pp': 30}, - 'Ember': {'id': 52, 'power': 40, 'type': 'Fire', 'accuracy': 100, 'pp': 25}, - 'Flamethrower': {'id': 53, 'power': 95, 'type': 'Fire', 'accuracy': 100, 'pp': 15}, - 'Mist': {'id': 54, 'power': 0, 'type': 'Ice', 'accuracy': 100, 'pp': 30}, - 'Water Gun': {'id': 55, 'power': 40, 'type': 'Water', 'accuracy': 100, 'pp': 25}, - 'Hydro Pump': {'id': 56, 'power': 120, 'type': 'Water', 'accuracy': 80, 'pp': 5}, - 'Surf': {'id': 57, 'power': 95, 'type': 'Water', 'accuracy': 100, 'pp': 15}, - 'Ice Beam': {'id': 58, 'power': 95, 'type': 'Ice', 'accuracy': 100, 'pp': 10}, - 'Blizzard': {'id': 59, 'power': 120, 'type': 'Ice', 'accuracy': 90, 'pp': 5}, - 'Psybeam': {'id': 60, 'power': 65, 'type': 'Psychic', 'accuracy': 100, 'pp': 20}, - 'Bubblebeam': {'id': 61, 'power': 65, 'type': 'Water', 'accuracy': 100, 'pp': 20}, - 'Aurora Beam': {'id': 62, 'power': 65, 'type': 'Ice', 'accuracy': 100, 'pp': 20}, - 'Hyper Beam': {'id': 63, 'power': 150, 'type': 'Normal', 'accuracy': 90, 'pp': 5}, - 'Peck': {'id': 64, 'power': 35, 'type': 'Flying', 'accuracy': 100, 'pp': 35}, - 'Drill Peck': {'id': 65, 'power': 80, 'type': 'Flying', 'accuracy': 100, 'pp': 20}, - 'Submission': {'id': 66, 'power': 80, 'type': 'Fighting', 'accuracy': 80, 'pp': 25}, - 'Low Kick': {'id': 67, 'power': 50, 'type': 'Fighting', 'accuracy': 90, 'pp': 20}, - 'Counter': {'id': 68, 'power': 1, 'type': 'Fighting', 'accuracy': 100, 'pp': 20}, - 'Seismic Toss': {'id': 69, 'power': 1, 'type': 'Fighting', 'accuracy': 100, 'pp': 20}, - 'Strength': {'id': 70, 'power': 80, 'type': 'Normal', 'accuracy': 100, 'pp': 15}, - 'Absorb': {'id': 71, 'power': 20, 'type': 'Grass', 'accuracy': 100, 'pp': 20}, - 'Mega Drain': {'id': 72, 'power': 40, 'type': 'Grass', 'accuracy': 100, 'pp': 10}, - 'Leech Seed': {'id': 73, 'power': 0, 'type': 'Grass', 'accuracy': 90, 'pp': 10}, - 'Growth': {'id': 74, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 40}, - 'Razor Leaf': {'id': 75, 'power': 55, 'type': 'Grass', 'accuracy': 95, 'pp': 25}, - 'Solarbeam': {'id': 76, 'power': 120, 'type': 'Grass', 'accuracy': 100, 'pp': 10}, - 'Poisonpowder': {'id': 77, 'power': 0, 'type': 'Poison', 'accuracy': 75, 'pp': 35}, - 'Stun Spore': {'id': 78, 'power': 0, 'type': 'Grass', 'accuracy': 75, 'pp': 30}, - 'Sleep Powder': {'id': 79, 'power': 0, 'type': 'Grass', 'accuracy': 75, 'pp': 15}, - 'Petal Dance': {'id': 80, 'power': 70, 'type': 'Grass', 'accuracy': 100, 'pp': 20}, - 'String Shot': {'id': 81, 'power': 0, 'type': 'Bug', 'accuracy': 95, 'pp': 40}, - 'Dragon Rage': {'id': 82, 'power': 1, 'type': 'Dragon', 'accuracy': 100, 'pp': 10}, - 'Fire Spin': {'id': 83, 'power': 15, 'type': 'Fire', 'accuracy': 70, 'pp': 15}, - 'Thundershock': {'id': 84, 'power': 40, 'type': 'Electric', 'accuracy': 100, 'pp': 30}, - 'Thunderbolt': {'id': 85, 'power': 95, 'type': 'Electric', 'accuracy': 100, 'pp': 15}, - 'Thunder Wave': {'id': 86, 'power': 0, 'type': 'Electric', 'accuracy': 100, 'pp': 20}, - 'Thunder': {'id': 87, 'power': 120, 'type': 'Electric', 'accuracy': 70, 'pp': 10}, - 'Rock Throw': {'id': 88, 'power': 50, 'type': 'Rock', 'accuracy': 65, 'pp': 15}, - 'Earthquake': {'id': 89, 'power': 100, 'type': 'Ground', 'accuracy': 100, 'pp': 10}, - 'Fissure': {'id': 90, 'power': 1, 'type': 'Ground', 'accuracy': 30, 'pp': 5}, - 'Dig': {'id': 91, 'power': 100, 'type': 'Ground', 'accuracy': 100, 'pp': 10}, - 'Toxic': {'id': 92, 'power': 0, 'type': 'Poison', 'accuracy': 85, 'pp': 10}, - 'Confusion': {'id': 93, 'power': 50, 'type': 'Psychic', 'accuracy': 100, 'pp': 25}, - 'Psychic': {'id': 94, 'power': 90, 'type': 'Psychic', 'accuracy': 100, 'pp': 10}, - 'Hypnosis': {'id': 95, 'power': 0, 'type': 'Psychic', 'accuracy': 60, 'pp': 20}, - 'Meditate': {'id': 96, 'power': 0, 'type': 'Psychic', 'accuracy': 100, 'pp': 40}, - 'Agility': {'id': 97, 'power': 0, 'type': 'Psychic', 'accuracy': 100, 'pp': 30}, - 'Quick Attack': {'id': 98, 'power': 40, 'type': 'Normal', 'accuracy': 100, 'pp': 30}, - 'Rage': {'id': 99, 'power': 20, 'type': 'Normal', 'accuracy': 100, 'pp': 20}, - 'Teleport': {'id': 100, 'power': 0, 'type': 'Psychic', 'accuracy': 100, 'pp': 20}, - 'Night Shade': {'id': 101, 'power': 0, 'type': 'Ghost', 'accuracy': 100, 'pp': 15}, - 'Mimic': {'id': 102, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 10}, - 'Screech': {'id': 103, 'power': 0, 'type': 'Normal', 'accuracy': 85, 'pp': 40}, - 'Double Team': {'id': 104, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 15}, - 'Recover': {'id': 105, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 20}, - 'Harden': {'id': 106, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 30}, - 'Minimize': {'id': 107, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 20}, - 'Smokescreen': {'id': 108, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 20}, - 'Confuse Ray': {'id': 109, 'power': 0, 'type': 'Ghost', 'accuracy': 100, 'pp': 10}, - 'Withdraw': {'id': 110, 'power': 0, 'type': 'Water', 'accuracy': 100, 'pp': 40}, - 'Defense Curl': {'id': 111, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 40}, - 'Barrier': {'id': 112, 'power': 0, 'type': 'Psychic', 'accuracy': 100, 'pp': 30}, - 'Light Screen': {'id': 113, 'power': 0, 'type': 'Psychic', 'accuracy': 100, 'pp': 30}, - 'Haze': {'id': 114, 'power': 0, 'type': 'Ice', 'accuracy': 100, 'pp': 30}, - 'Reflect': {'id': 115, 'power': 0, 'type': 'Psychic', 'accuracy': 100, 'pp': 20}, - 'Focus Energy': {'id': 116, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 30}, - 'Bide': {'id': 117, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 10}, - 'Metronome': {'id': 118, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 10}, - 'Mirror Move': {'id': 119, 'power': 0, 'type': 'Flying', 'accuracy': 100, 'pp': 20}, - 'Selfdestruct': {'id': 120, 'power': 130, 'type': 'Normal', 'accuracy': 100, 'pp': 5}, - 'Egg Bomb': {'id': 121, 'power': 100, 'type': 'Normal', 'accuracy': 75, 'pp': 10}, - 'Lick': {'id': 122, 'power': 20, 'type': 'Ghost', 'accuracy': 100, 'pp': 30}, - 'Smog': {'id': 123, 'power': 20, 'type': 'Poison', 'accuracy': 70, 'pp': 20}, - 'Sludge': {'id': 124, 'power': 65, 'type': 'Poison', 'accuracy': 100, 'pp': 20}, - 'Bone Club': {'id': 125, 'power': 65, 'type': 'Ground', 'accuracy': 85, 'pp': 20}, - 'Fire Blast': {'id': 126, 'power': 120, 'type': 'Fire', 'accuracy': 85, 'pp': 5}, - 'Waterfall': {'id': 127, 'power': 80, 'type': 'Water', 'accuracy': 100, 'pp': 15}, - 'Clamp': {'id': 128, 'power': 35, 'type': 'Water', 'accuracy': 75, 'pp': 10}, - 'Swift': {'id': 129, 'power': 60, 'type': 'Normal', 'accuracy': 100, 'pp': 20}, - 'Skull Bash': {'id': 130, 'power': 100, 'type': 'Normal', 'accuracy': 100, 'pp': 15}, - 'Spike Cannon': {'id': 131, 'power': 20, 'type': 'Normal', 'accuracy': 100, 'pp': 15}, - 'Constrict': {'id': 132, 'power': 10, 'type': 'Normal', 'accuracy': 100, 'pp': 35}, - 'Amnesia': {'id': 133, 'power': 0, 'type': 'Psychic', 'accuracy': 100, 'pp': 20}, - 'Kinesis': {'id': 134, 'power': 0, 'type': 'Psychic', 'accuracy': 80, 'pp': 15}, - 'Softboiled': {'id': 135, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 10}, - 'Hi Jump Kick': {'id': 136, 'power': 85, 'type': 'Fighting', 'accuracy': 90, 'pp': 20}, - 'Glare': {'id': 137, 'power': 0, 'type': 'Normal', 'accuracy': 75, 'pp': 30}, - 'Dream Eater': {'id': 138, 'power': 100, 'type': 'Psychic', 'accuracy': 100, 'pp': 15}, - 'Poison Gas': {'id': 139, 'power': 0, 'type': 'Poison', 'accuracy': 55, 'pp': 40}, - 'Barrage': {'id': 140, 'power': 15, 'type': 'Normal', 'accuracy': 85, 'pp': 20}, - 'Leech Life': {'id': 141, 'power': 20, 'type': 'Bug', 'accuracy': 100, 'pp': 15}, - 'Lovely Kiss': {'id': 142, 'power': 0, 'type': 'Normal', 'accuracy': 75, 'pp': 10}, - 'Sky Attack': {'id': 143, 'power': 140, 'type': 'Flying', 'accuracy': 90, 'pp': 5}, - 'Transform': {'id': 144, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 10}, - 'Bubble': {'id': 145, 'power': 20, 'type': 'Water', 'accuracy': 100, 'pp': 30}, - 'Dizzy Punch': {'id': 146, 'power': 70, 'type': 'Normal', 'accuracy': 100, 'pp': 10}, - 'Spore': {'id': 147, 'power': 0, 'type': 'Grass', 'accuracy': 100, 'pp': 15}, - 'Flash': {'id': 148, 'power': 0, 'type': 'Normal', 'accuracy': 70, 'pp': 20}, - 'Psywave': {'id': 149, 'power': 1, 'type': 'Psychic', 'accuracy': 80, 'pp': 15}, - 'Splash': {'id': 150, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 40}, - 'Acid Armor': {'id': 151, 'power': 0, 'type': 'Poison', 'accuracy': 100, 'pp': 40}, - 'Crabhammer': {'id': 152, 'power': 90, 'type': 'Water', 'accuracy': 85, 'pp': 10}, - 'Explosion': {'id': 153, 'power': 170, 'type': 'Normal', 'accuracy': 100, 'pp': 5}, - 'Fury Swipes': {'id': 154, 'power': 18, 'type': 'Normal', 'accuracy': 80, 'pp': 15}, - 'Bonemerang': {'id': 155, 'power': 50, 'type': 'Ground', 'accuracy': 90, 'pp': 10}, - 'Rest': {'id': 156, 'power': 0, 'type': 'Psychic', 'accuracy': 100, 'pp': 10}, - 'Rock Slide': {'id': 157, 'power': 75, 'type': 'Rock', 'accuracy': 90, 'pp': 10}, - 'Hyper Fang': {'id': 158, 'power': 80, 'type': 'Normal', 'accuracy': 90, 'pp': 15}, - 'Sharpen': {'id': 159, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 30}, - 'Conversion': {'id': 160, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 30}, - 'Tri Attack': {'id': 161, 'power': 80, 'type': 'Normal', 'accuracy': 100, 'pp': 10}, - 'Super Fang': {'id': 162, 'power': 1, 'type': 'Normal', 'accuracy': 90, 'pp': 10}, - 'Slash': {'id': 163, 'power': 70, 'type': 'Normal', 'accuracy': 100, 'pp': 20}, - 'Substitute': {'id': 164, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 10}, - #'Struggle': {'id': 165, 'power': 50, 'type': 'Struggle_Type', 'accuracy': 100, 'pp': 10} + 'No Move': {'id': 0, 'power': 0, 'type': 'Typeless', 'accuracy': 0, 'pp': 0, 'effect': 0}, + 'Pound': {'id': 1, 'power': 40, 'type': 'Normal', 'accuracy': 100, 'pp': 35, 'effect': 0}, + 'Karate Chop': {'id': 2, 'power': 50, 'type': 'Normal', 'accuracy': 100, 'pp': 25, 'effect': 0}, + 'Doubleslap': {'id': 3, 'power': 15, 'type': 'Normal', 'accuracy': 85, 'pp': 10, 'effect': 29}, + 'Comet Punch': {'id': 4, 'power': 18, 'type': 'Normal', 'accuracy': 85, 'pp': 15, 'effect': 29}, + 'Mega Punch': {'id': 5, 'power': 80, 'type': 'Normal', 'accuracy': 85, 'pp': 20, 'effect': 0}, + 'Pay Day': {'id': 6, 'power': 40, 'type': 'Normal', 'accuracy': 100, 'pp': 20, 'effect': 16}, + 'Fire Punch': {'id': 7, 'power': 75, 'type': 'Fire', 'accuracy': 100, 'pp': 15, 'effect': 4}, + 'Ice Punch': {'id': 8, 'power': 75, 'type': 'Ice', 'accuracy': 100, 'pp': 15, 'effect': 5}, + 'Thunderpunch': {'id': 9, 'power': 75, 'type': 'Electric', 'accuracy': 100, 'pp': 15, 'effect': 6}, + 'Scratch': {'id': 10, 'power': 40, 'type': 'Normal', 'accuracy': 100, 'pp': 35, 'effect': 0}, + 'Vicegrip': {'id': 11, 'power': 55, 'type': 'Normal', 'accuracy': 100, 'pp': 30, 'effect': 0}, + 'Guillotine': {'id': 12, 'power': 1, 'type': 'Normal', 'accuracy': 30, 'pp': 5, 'effect': 38}, + 'Razor Wind': {'id': 13, 'power': 80, 'type': 'Normal', 'accuracy': 75, 'pp': 10, 'effect': 39}, + 'Swords Dance': {'id': 14, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 30, 'effect': 50}, + 'Cut': {'id': 15, 'power': 50, 'type': 'Normal', 'accuracy': 95, 'pp': 30, 'effect': 0}, + 'Gust': {'id': 16, 'power': 40, 'type': 'Normal', 'accuracy': 100, 'pp': 35, 'effect': 0}, + 'Wing Attack': {'id': 17, 'power': 35, 'type': 'Flying', 'accuracy': 100, 'pp': 35, 'effect': 0}, + 'Whirlwind': {'id': 18, 'power': 0, 'type': 'Normal', 'accuracy': 85, 'pp': 20, 'effect': 28}, + 'Fly': {'id': 19, 'power': 70, 'type': 'Flying', 'accuracy': 95, 'pp': 15, 'effect': 43}, + 'Bind': {'id': 20, 'power': 15, 'type': 'Normal', 'accuracy': 75, 'pp': 20, 'effect': 42}, + 'Slam': {'id': 21, 'power': 80, 'type': 'Normal', 'accuracy': 75, 'pp': 20, 'effect': 0}, + 'Vine Whip': {'id': 22, 'power': 35, 'type': 'Grass', 'accuracy': 100, 'pp': 10, 'effect': 0}, + 'Stomp': {'id': 23, 'power': 65, 'type': 'Normal', 'accuracy': 100, 'pp': 20, 'effect': 37}, + 'Double Kick': {'id': 24, 'power': 30, 'type': 'Fighting', 'accuracy': 100, 'pp': 30, 'effect': 44}, + 'Mega Kick': {'id': 25, 'power': 120, 'type': 'Normal', 'accuracy': 75, 'pp': 5, 'effect': 0}, + 'Jump Kick': {'id': 26, 'power': 70, 'type': 'Fighting', 'accuracy': 95, 'pp': 25, 'effect': 45}, + 'Rolling Kick': {'id': 27, 'power': 60, 'type': 'Fighting', 'accuracy': 85, 'pp': 15, 'effect': 37}, + 'Sand Attack': {'id': 28, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 15, 'effect': 22}, + 'Headbutt': {'id': 29, 'power': 70, 'type': 'Normal', 'accuracy': 100, 'pp': 15, 'effect': 37}, + 'Horn Attack': {'id': 30, 'power': 65, 'type': 'Normal', 'accuracy': 100, 'pp': 25, 'effect': 0}, + 'Fury Attack': {'id': 31, 'power': 15, 'type': 'Normal', 'accuracy': 85, 'pp': 20, 'effect': 29}, + 'Horn Drill': {'id': 32, 'power': 1, 'type': 'Normal', 'accuracy': 30, 'pp': 5, 'effect': 38}, + 'Tackle': {'id': 33, 'power': 35, 'type': 'Normal', 'accuracy': 95, 'pp': 35, 'effect': 0}, + 'Body Slam': {'id': 34, 'power': 85, 'type': 'Normal', 'accuracy': 100, 'pp': 15, 'effect': 36}, + 'Wrap': {'id': 35, 'power': 15, 'type': 'Normal', 'accuracy': 85, 'pp': 20, 'effect': 42}, + 'Take Down': {'id': 36, 'power': 90, 'type': 'Normal', 'accuracy': 85, 'pp': 20, 'effect': 48}, + 'Thrash': {'id': 37, 'power': 90, 'type': 'Normal', 'accuracy': 100, 'pp': 20, 'effect': 27}, + 'Double Edge': {'id': 38, 'power': 100, 'type': 'Normal', 'accuracy': 100, 'pp': 15, 'effect': 48}, + 'Tail Whip': {'id': 39, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 30, 'effect': 19}, + 'Poison Sting': {'id': 40, 'power': 15, 'type': 'Poison', 'accuracy': 100, 'pp': 35, 'effect': 2}, + 'Twineedle': {'id': 41, 'power': 25, 'type': 'Bug', 'accuracy': 100, 'pp': 20, 'effect': 77}, + 'Pin Missile': {'id': 42, 'power': 14, 'type': 'Bug', 'accuracy': 85, 'pp': 20, 'effect': 29}, + 'Leer': {'id': 43, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 30, 'effect': 19}, + 'Bite': {'id': 44, 'power': 60, 'type': 'Normal', 'accuracy': 100, 'pp': 25, 'effect': 31}, + 'Growl': {'id': 45, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 40, 'effect': 18}, + 'Roar': {'id': 46, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 20, 'effect': 28}, + 'Sing': {'id': 47, 'power': 0, 'type': 'Normal', 'accuracy': 55, 'pp': 15, 'effect': 32}, + 'Supersonic': {'id': 48, 'power': 0, 'type': 'Normal', 'accuracy': 55, 'pp': 20, 'effect': 49}, + 'Sonicboom': {'id': 49, 'power': 1, 'type': 'Normal', 'accuracy': 90, 'pp': 20, 'effect': 41}, + 'Disable': {'id': 50, 'power': 0, 'type': 'Normal', 'accuracy': 55, 'pp': 20, 'effect': 86}, + 'Acid': {'id': 51, 'power': 40, 'type': 'Poison', 'accuracy': 100, 'pp': 30, 'effect': 69}, + 'Ember': {'id': 52, 'power': 40, 'type': 'Fire', 'accuracy': 100, 'pp': 25, 'effect': 4}, + 'Flamethrower': {'id': 53, 'power': 95, 'type': 'Fire', 'accuracy': 100, 'pp': 15, 'effect': 4}, + 'Mist': {'id': 54, 'power': 0, 'type': 'Ice', 'accuracy': 100, 'pp': 30, 'effect': 46}, + 'Water Gun': {'id': 55, 'power': 40, 'type': 'Water', 'accuracy': 100, 'pp': 25, 'effect': 0}, + 'Hydro Pump': {'id': 56, 'power': 120, 'type': 'Water', 'accuracy': 80, 'pp': 5, 'effect': 0}, + 'Surf': {'id': 57, 'power': 95, 'type': 'Water', 'accuracy': 100, 'pp': 15, 'effect': 0}, + 'Ice Beam': {'id': 58, 'power': 95, 'type': 'Ice', 'accuracy': 100, 'pp': 10, 'effect': 5}, + 'Blizzard': {'id': 59, 'power': 120, 'type': 'Ice', 'accuracy': 90, 'pp': 5, 'effect': 5}, + 'Psybeam': {'id': 60, 'power': 65, 'type': 'Psychic', 'accuracy': 100, 'pp': 20, 'effect': 76}, + 'Bubblebeam': {'id': 61, 'power': 65, 'type': 'Water', 'accuracy': 100, 'pp': 20, 'effect': 70}, + 'Aurora Beam': {'id': 62, 'power': 65, 'type': 'Ice', 'accuracy': 100, 'pp': 20, 'effect': 68}, + 'Hyper Beam': {'id': 63, 'power': 150, 'type': 'Normal', 'accuracy': 90, 'pp': 5, 'effect': 80}, + 'Peck': {'id': 64, 'power': 35, 'type': 'Flying', 'accuracy': 100, 'pp': 35, 'effect': 0}, + 'Drill Peck': {'id': 65, 'power': 80, 'type': 'Flying', 'accuracy': 100, 'pp': 20, 'effect': 0}, + 'Submission': {'id': 66, 'power': 80, 'type': 'Fighting', 'accuracy': 80, 'pp': 25, 'effect': 48}, + 'Low Kick': {'id': 67, 'power': 50, 'type': 'Fighting', 'accuracy': 90, 'pp': 20, 'effect': 37}, + 'Counter': {'id': 68, 'power': 1, 'type': 'Fighting', 'accuracy': 100, 'pp': 20, 'effect': 0}, + 'Seismic Toss': {'id': 69, 'power': 1, 'type': 'Fighting', 'accuracy': 100, 'pp': 20, 'effect': 41}, + 'Strength': {'id': 70, 'power': 80, 'type': 'Normal', 'accuracy': 100, 'pp': 15, 'effect': 0}, + 'Absorb': {'id': 71, 'power': 20, 'type': 'Grass', 'accuracy': 100, 'pp': 20, 'effect': 3}, + 'Mega Drain': {'id': 72, 'power': 40, 'type': 'Grass', 'accuracy': 100, 'pp': 10, 'effect': 3}, + 'Leech Seed': {'id': 73, 'power': 0, 'type': 'Grass', 'accuracy': 90, 'pp': 10, 'effect': 84}, + 'Growth': {'id': 74, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 40, 'effect': 13}, + 'Razor Leaf': {'id': 75, 'power': 55, 'type': 'Grass', 'accuracy': 95, 'pp': 25, 'effect': 0}, + 'Solarbeam': {'id': 76, 'power': 120, 'type': 'Grass', 'accuracy': 100, 'pp': 10, 'effect': 39}, + 'Poisonpowder': {'id': 77, 'power': 0, 'type': 'Poison', 'accuracy': 75, 'pp': 35, 'effect': 66}, + 'Stun Spore': {'id': 78, 'power': 0, 'type': 'Grass', 'accuracy': 75, 'pp': 30, 'effect': 67}, + 'Sleep Powder': {'id': 79, 'power': 0, 'type': 'Grass', 'accuracy': 75, 'pp': 15, 'effect': 32}, + 'Petal Dance': {'id': 80, 'power': 70, 'type': 'Grass', 'accuracy': 100, 'pp': 20, 'effect': 27}, + 'String Shot': {'id': 81, 'power': 0, 'type': 'Bug', 'accuracy': 95, 'pp': 40, 'effect': 20}, + 'Dragon Rage': {'id': 82, 'power': 1, 'type': 'Dragon', 'accuracy': 100, 'pp': 10, 'effect': 41}, + 'Fire Spin': {'id': 83, 'power': 15, 'type': 'Fire', 'accuracy': 70, 'pp': 15, 'effect': 42}, + 'Thundershock': {'id': 84, 'power': 40, 'type': 'Electric', 'accuracy': 100, 'pp': 30, 'effect': 6}, + 'Thunderbolt': {'id': 85, 'power': 95, 'type': 'Electric', 'accuracy': 100, 'pp': 15, 'effect': 6}, + 'Thunder Wave': {'id': 86, 'power': 0, 'type': 'Electric', 'accuracy': 100, 'pp': 20, 'effect': 67}, + 'Thunder': {'id': 87, 'power': 120, 'type': 'Electric', 'accuracy': 70, 'pp': 10, 'effect': 6}, + 'Rock Throw': {'id': 88, 'power': 50, 'type': 'Rock', 'accuracy': 65, 'pp': 15, 'effect': 0}, + 'Earthquake': {'id': 89, 'power': 100, 'type': 'Ground', 'accuracy': 100, 'pp': 10, 'effect': 0}, + 'Fissure': {'id': 90, 'power': 1, 'type': 'Ground', 'accuracy': 30, 'pp': 5, 'effect': 38}, + 'Dig': {'id': 91, 'power': 100, 'type': 'Ground', 'accuracy': 100, 'pp': 10, 'effect': 39}, + 'Toxic': {'id': 92, 'power': 0, 'type': 'Poison', 'accuracy': 85, 'pp': 10, 'effect': 66}, + 'Confusion': {'id': 93, 'power': 50, 'type': 'Psychic', 'accuracy': 100, 'pp': 25, 'effect': 76}, + 'Psychic': {'id': 94, 'power': 90, 'type': 'Psychic', 'accuracy': 100, 'pp': 10, 'effect': 71}, + 'Hypnosis': {'id': 95, 'power': 0, 'type': 'Psychic', 'accuracy': 60, 'pp': 20, 'effect': 32}, + 'Meditate': {'id': 96, 'power': 0, 'type': 'Psychic', 'accuracy': 100, 'pp': 40, 'effect': 10}, + 'Agility': {'id': 97, 'power': 0, 'type': 'Psychic', 'accuracy': 100, 'pp': 30, 'effect': 52}, + 'Quick Attack': {'id': 98, 'power': 40, 'type': 'Normal', 'accuracy': 100, 'pp': 30, 'effect': 0}, + 'Rage': {'id': 99, 'power': 20, 'type': 'Normal', 'accuracy': 100, 'pp': 20, 'effect': 81}, + 'Teleport': {'id': 100, 'power': 0, 'type': 'Psychic', 'accuracy': 100, 'pp': 20, 'effect': 28}, + 'Night Shade': {'id': 101, 'power': 0, 'type': 'Ghost', 'accuracy': 100, 'pp': 15, 'effect': 41}, + 'Mimic': {'id': 102, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 10, 'effect': 82}, + 'Screech': {'id': 103, 'power': 0, 'type': 'Normal', 'accuracy': 85, 'pp': 40, 'effect': 59}, + 'Double Team': {'id': 104, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 15, 'effect': 15}, + 'Recover': {'id': 105, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 20, 'effect': 56}, + 'Harden': {'id': 106, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 30, 'effect': 11}, + 'Minimize': {'id': 107, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 20, 'effect': 15}, + 'Smokescreen': {'id': 108, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 20, 'effect': 22}, + 'Confuse Ray': {'id': 109, 'power': 0, 'type': 'Ghost', 'accuracy': 100, 'pp': 10, 'effect': 49}, + 'Withdraw': {'id': 110, 'power': 0, 'type': 'Water', 'accuracy': 100, 'pp': 40, 'effect': 11}, + 'Defense Curl': {'id': 111, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 40, 'effect': 11}, + 'Barrier': {'id': 112, 'power': 0, 'type': 'Psychic', 'accuracy': 100, 'pp': 30, 'effect': 51}, + 'Light Screen': {'id': 113, 'power': 0, 'type': 'Psychic', 'accuracy': 100, 'pp': 30, 'effect': 64}, + 'Haze': {'id': 114, 'power': 0, 'type': 'Ice', 'accuracy': 100, 'pp': 30, 'effect': 25}, + 'Reflect': {'id': 115, 'power': 0, 'type': 'Psychic', 'accuracy': 100, 'pp': 20, 'effect': 65}, + 'Focus Energy': {'id': 116, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 30, 'effect': 47}, + 'Bide': {'id': 117, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 10, 'effect': 26}, + 'Metronome': {'id': 118, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 10, 'effect': 83}, + 'Mirror Move': {'id': 119, 'power': 0, 'type': 'Flying', 'accuracy': 100, 'pp': 20, 'effect': 9}, + 'Selfdestruct': {'id': 120, 'power': 130, 'type': 'Normal', 'accuracy': 100, 'pp': 5, 'effect': 7}, + 'Egg Bomb': {'id': 121, 'power': 100, 'type': 'Normal', 'accuracy': 75, 'pp': 10, 'effect': 0}, + 'Lick': {'id': 122, 'power': 20, 'type': 'Ghost', 'accuracy': 100, 'pp': 30, 'effect': 36}, + 'Smog': {'id': 123, 'power': 20, 'type': 'Poison', 'accuracy': 70, 'pp': 20, 'effect': 33}, + 'Sludge': {'id': 124, 'power': 65, 'type': 'Poison', 'accuracy': 100, 'pp': 20, 'effect': 33}, + 'Bone Club': {'id': 125, 'power': 65, 'type': 'Ground', 'accuracy': 85, 'pp': 20, 'effect': 31}, + 'Fire Blast': {'id': 126, 'power': 120, 'type': 'Fire', 'accuracy': 85, 'pp': 5, 'effect': 34}, + 'Waterfall': {'id': 127, 'power': 80, 'type': 'Water', 'accuracy': 100, 'pp': 15, 'effect': 0}, + 'Clamp': {'id': 128, 'power': 35, 'type': 'Water', 'accuracy': 75, 'pp': 10, 'effect': 42}, + 'Swift': {'id': 129, 'power': 60, 'type': 'Normal', 'accuracy': 100, 'pp': 20, 'effect': 17}, + 'Skull Bash': {'id': 130, 'power': 100, 'type': 'Normal', 'accuracy': 100, 'pp': 15, 'effect': 39}, + 'Spike Cannon': {'id': 131, 'power': 20, 'type': 'Normal', 'accuracy': 100, 'pp': 15, 'effect': 29}, + 'Constrict': {'id': 132, 'power': 10, 'type': 'Normal', 'accuracy': 100, 'pp': 35, 'effect': 70}, + 'Amnesia': {'id': 133, 'power': 0, 'type': 'Psychic', 'accuracy': 100, 'pp': 20, 'effect': 53}, + 'Kinesis': {'id': 134, 'power': 0, 'type': 'Psychic', 'accuracy': 80, 'pp': 15, 'effect': 22}, + 'Softboiled': {'id': 135, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 10, 'effect': 56}, + 'Hi Jump Kick': {'id': 136, 'power': 85, 'type': 'Fighting', 'accuracy': 90, 'pp': 20, 'effect': 45}, + 'Glare': {'id': 137, 'power': 0, 'type': 'Normal', 'accuracy': 75, 'pp': 30, 'effect': 67}, + 'Dream Eater': {'id': 138, 'power': 100, 'type': 'Psychic', 'accuracy': 100, 'pp': 15, 'effect': 8}, + 'Poison Gas': {'id': 139, 'power': 0, 'type': 'Poison', 'accuracy': 55, 'pp': 40, 'effect': 66}, + 'Barrage': {'id': 140, 'power': 15, 'type': 'Normal', 'accuracy': 85, 'pp': 20, 'effect': 29}, + 'Leech Life': {'id': 141, 'power': 20, 'type': 'Bug', 'accuracy': 100, 'pp': 15, 'effect': 3}, + 'Lovely Kiss': {'id': 142, 'power': 0, 'type': 'Normal', 'accuracy': 75, 'pp': 10, 'effect': 32}, + 'Sky Attack': {'id': 143, 'power': 140, 'type': 'Flying', 'accuracy': 90, 'pp': 5, 'effect': 39}, + 'Transform': {'id': 144, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 10, 'effect': 57}, + 'Bubble': {'id': 145, 'power': 20, 'type': 'Water', 'accuracy': 100, 'pp': 30, 'effect': 70}, + 'Dizzy Punch': {'id': 146, 'power': 70, 'type': 'Normal', 'accuracy': 100, 'pp': 10, 'effect': 0}, + 'Spore': {'id': 147, 'power': 0, 'type': 'Grass', 'accuracy': 100, 'pp': 15, 'effect': 32}, + 'Flash': {'id': 148, 'power': 0, 'type': 'Normal', 'accuracy': 70, 'pp': 20, 'effect': 22}, + 'Psywave': {'id': 149, 'power': 1, 'type': 'Psychic', 'accuracy': 80, 'pp': 15, 'effect': 41}, + 'Splash': {'id': 150, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 40, 'effect': 85}, + 'Acid Armor': {'id': 151, 'power': 0, 'type': 'Poison', 'accuracy': 100, 'pp': 40, 'effect': 51}, + 'Crabhammer': {'id': 152, 'power': 90, 'type': 'Water', 'accuracy': 85, 'pp': 10, 'effect': 0}, + 'Explosion': {'id': 153, 'power': 170, 'type': 'Normal', 'accuracy': 100, 'pp': 5, 'effect': 7}, + 'Fury Swipes': {'id': 154, 'power': 18, 'type': 'Normal', 'accuracy': 80, 'pp': 15, 'effect': 29}, + 'Bonemerang': {'id': 155, 'power': 50, 'type': 'Ground', 'accuracy': 90, 'pp': 10, 'effect': 44}, + 'Rest': {'id': 156, 'power': 0, 'type': 'Psychic', 'accuracy': 100, 'pp': 10, 'effect': 56}, + 'Rock Slide': {'id': 157, 'power': 75, 'type': 'Rock', 'accuracy': 90, 'pp': 10, 'effect': 0}, + 'Hyper Fang': {'id': 158, 'power': 80, 'type': 'Normal', 'accuracy': 90, 'pp': 15, 'effect': 31}, + 'Sharpen': {'id': 159, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 30, 'effect': 10}, + 'Conversion': {'id': 160, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 30, 'effect': 24}, + 'Tri Attack': {'id': 161, 'power': 80, 'type': 'Normal', 'accuracy': 100, 'pp': 10, 'effect': 0}, + 'Super Fang': {'id': 162, 'power': 1, 'type': 'Normal', 'accuracy': 90, 'pp': 10, 'effect': 40}, + 'Slash': {'id': 163, 'power': 70, 'type': 'Normal', 'accuracy': 100, 'pp': 20, 'effect': 0}, + 'Substitute': {'id': 164, 'power': 0, 'type': 'Normal', 'accuracy': 100, 'pp': 10, 'effect': 79} + #'Struggle': {'id': 165, 'power': 50, 'type': 'Struggle_Type', 'accuracy': 100, 'pp': 10, 'effect': 48} } encounter_tables = {'Wild_Super_Rod_A': 2, 'Wild_Super_Rod_B': 2, 'Wild_Super_Rod_C': 3, 'Wild_Super_Rod_D': 2, @@ -1204,6 +1204,29 @@ tm_moves = [ 'Selfdestruct', 'Egg Bomb', 'Fire Blast', 'Swift', 'Skull Bash', 'Softboiled', 'Dream Eater', 'Sky Attack', 'Rest', 'Thunder Wave', 'Psywave', 'Explosion', 'Rock Slide', 'Tri Attack', 'Substitute' ] +#['No Move', 'Pound', 'Karate Chop', 'Doubleslap', 'Comet Punch', 'Fire Punch', 'Ice Punch', 'Thunderpunch', 'Scratch', +# 'Vicegrip', 'Guillotine', 'Cut', 'Gust', 'Wing Attack', 'Fly', 'Bind', 'Slam', 'Vine Whip', 'Stomp', 'Double Kick', 'Jump Kick', +# 'Rolling Kick', 'Sand Attack', 'Headbutt', 'Horn Attack', 'Fury Attack', 'Tackle', 'Wrap', 'Thrash', 'Tail Whip', 'Poison Sting', +# 'Twineedle', 'Pin Missile', 'Leer', 'Bite', 'Growl', 'Roar', 'Sing', 'Supersonic', 'Sonicboom', 'Disable', 'Acid', 'Ember', 'Flamethrower', +# 'Mist', 'Hydro Pump', 'Surf', 'Psybeam', 'Aurora Beam', 'Peck', 'Drill Peck', 'Low Kick', 'Strength', 'Absorb', 'Leech Seed', 'Growth', +# 'Razor Leaf', 'Poisonpowder', 'Stun Spore', 'Sleep Powder', 'Petal Dance', 'String Shot', 'Fire Spin', 'Thundershock', 'Rock Throw', 'Confusion', +# 'Hypnosis', 'Meditate', 'Agility', 'Quick Attack', 'Night Shade', 'Screech', 'Recover', 'Harden', 'Minimize', 'Smokescreen', 'Confuse Ray', 'Withdraw', +# 'Defense Curl', 'Barrier', 'Light Screen', 'Haze', 'Focus Energy', 'Mirror Move', 'Lick', 'Smog', 'Sludge', 'Bone Club', 'Waterfall', 'Clamp', 'Spike Cannon', +# 'Constrict', 'Amnesia', 'Kinesis', 'Hi Jump Kick', 'Glare', 'Poison Gas', 'Barrage', 'Leech Life', 'Lovely Kiss', 'Transform', 'Bubble', 'Dizzy Punch', 'Spore', 'Flash', +# 'Splash', 'Acid Armor', 'Crabhammer', 'Fury Swipes', 'Bonemerang', 'Hyper Fang', 'Sharpen', 'Conversion', 'Super Fang', 'Slash'] + +# print([i for i in list(moves.keys()) if i not in tm_moves]) +# filler_moves = [ +# "Razor Wind", "Whirlwind", "Counter", "Teleport", "Bide", "Skull Bash", "Sky Attack", "Psywave", +# "Pound", "Karate Chop", "Doubleslap", "Comet Punch", "Scratch", "Vicegrip", "Gust", "Wing Attack", "Bind", +# "Vine Whip", "Sand Attack", "Fury Attack", "Tackle", "Wrap", "Tail Whip", "Poison Sting", "Twineedle", +# "Leer", "Growl", "Roar", "Sing", "Supersonic", "Sonicboom", "Disable", "Acid", "Ember", "Mist", "Peck", "Absorb", +# "Growth", "Poisonpowder", "String Shot", "Meditate", "Agility", "Screech", "Double Team", "Harden", "Minimize", +# "Smokescreen", "Confuse Ray", "Withdraw", "Defense Curl", "Barrier", "Light Screen", "Haze", "Reflect", +# "Focus Energy", "Lick", "Smog", "Clamp", "Spike Cannon", "Constrict" +# +# ] + first_stage_pokemon = [pokemon for pokemon in pokemon_data.keys() if pokemon not in evolves_from] legendary_pokemon = ["Articuno", "Zapdos", "Moltres", "Mewtwo", "Mew"] diff --git a/worlds/pokemon_rb/regions.py b/worlds/pokemon_rb/regions.py index 674d24d1..98dbb3af 100644 --- a/worlds/pokemon_rb/regions.py +++ b/worlds/pokemon_rb/regions.py @@ -23,11 +23,12 @@ def create_regions(multiworld: MultiWorld, player: int): locations_per_region.setdefault(location.region, []) if location.inclusion(multiworld, player): locations_per_region[location.region].append(PokemonRBLocation(player, location.name, location.address, - location.rom_address)) + location.rom_address, location.type)) regions = [ create_region(multiworld, player, "Menu", locations_per_region), create_region(multiworld, player, "Anywhere", locations_per_region), create_region(multiworld, player, "Fossil", locations_per_region), + create_region(multiworld, player, "Pokedex", locations_per_region), create_region(multiworld, player, "Pallet Town", locations_per_region), create_region(multiworld, player, "Route 1", locations_per_region), create_region(multiworld, player, "Viridian City", locations_per_region), @@ -88,6 +89,7 @@ def create_regions(multiworld: MultiWorld, player: int): create_region(multiworld, player, "Route 8", locations_per_region), create_region(multiworld, player, "Route 8 Grass", locations_per_region), create_region(multiworld, player, "Celadon City", locations_per_region), + create_region(multiworld, player, "Celadon Game Corner", locations_per_region), create_region(multiworld, player, "Celadon Prize Corner", locations_per_region), create_region(multiworld, player, "Celadon Gym", locations_per_region), create_region(multiworld, player, "Route 16", locations_per_region), @@ -148,6 +150,7 @@ def create_regions(multiworld: MultiWorld, player: int): multiworld.regions += regions connect(multiworld, player, "Menu", "Anywhere", one_way=True) connect(multiworld, player, "Menu", "Pallet Town", one_way=True) + connect(multiworld, player, "Menu", "Pokedex", one_way=True) connect(multiworld, player, "Menu", "Fossil", lambda state: state.pokemon_rb_fossil_checks( state.multiworld.second_fossil_check_condition[player].value, player), one_way=True) connect(multiworld, player, "Pallet Town", "Route 1") @@ -220,6 +223,7 @@ def create_regions(multiworld: MultiWorld, player: int): connect(multiworld, player, "Route 8", "Route 8 Grass", lambda state: state.pokemon_rb_can_cut(player), one_way=True) connect(multiworld, player, "Route 7", "Celadon City") connect(multiworld, player, "Celadon City", "Celadon Gym", lambda state: state.pokemon_rb_can_cut(player), one_way=True) + connect(multiworld, player, "Celadon City", "Celadon Game Corner") connect(multiworld, player, "Celadon City", "Celadon Prize Corner") connect(multiworld, player, "Celadon City", "Route 16") connect(multiworld, player, "Route 16", "Route 16 North", lambda state: state.pokemon_rb_can_cut(player), one_way=True) diff --git a/worlds/pokemon_rb/rock_tunnel.py b/worlds/pokemon_rb/rock_tunnel.py new file mode 100644 index 00000000..3a70709e --- /dev/null +++ b/worlds/pokemon_rb/rock_tunnel.py @@ -0,0 +1,294 @@ +from .rom_addresses import rom_addresses + +disallowed1F = [[2, 2], [3, 2], [1, 8], [2, 8], [7, 7], [8, 7], [10, 4], [11, 4], [11, 12], + [11, 13], [16, 10], [17, 10], [18, 10], [16, 12], [17, 12], [18, 12]] +disallowed2F = [[16, 2], [17, 2], [18, 2], [15, 5], [15, 6], [10, 10], [11, 10], [12, 10], [7, 14], [8, 14], [1, 15], + [13, 15], [13, 16], [1, 12], [1, 10], [3, 5], [3, 6], [5, 6], [5, 7], [5, 8], [1, 2], [1, 3], [1, 4], + [11, 1]] + + +def randomize_rock_tunnel(data, random): + + seed = random.randint(0, 999999999999999999) + random.seed(seed) + + map1f = [] + map2f = [] + + address = rom_addresses["Map_Rock_Tunnel1F"] + for y in range(0, 18): + row = [] + for x in range(0, 20): + row.append(data[address]) + address += 1 + map1f.append(row) + + address = rom_addresses["Map_Rock_TunnelB1F"] + for y in range(0, 18): + row = [] + for x in range(0, 20): + row.append(data[address]) + address += 1 + map2f.append(row) + + current_map = map1f + + def floor(x, y): + current_map[y][x] = 1 + + def wide(x, y): + current_map[y][x] = 32 + current_map[y][x + 1] = 34 + + def tall(x, y): + current_map[y][x] = 23 + current_map[y + 1][x] = 31 + + def single(x, y): + current_map[y][x] = 2 + + # 0 = top left, 1 = middle, 2 = top right, 3 = bottom right + entrance_c = random.choice([0, 1, 2]) + exit_c = [0, 1, 3] + if entrance_c == 2: + exit_c.remove(1) + else: + exit_c.remove(entrance_c) + exit_c = random.choice(exit_c) + remaining = [i for i in [0, 1, 2, 3] if i not in [entrance_c, exit_c]] + + if entrance_c == 0: + floor(6, 3) + floor(6, 4) + tall(random.randint(8, 10), 2) + wide(4, random.randint(5, 7)) + wide(1, random.choice([5, 6, 7, 9])) + elif entrance_c == 1: + if remaining == [0, 2] or random.randint(0, 1): + tall(random.randint(8, 10), 2) + floor(7, 4) + floor(8, 4) + else: + tall(random.randint(11, 12), 5) + floor(9, 5) + floor(9, 6) + elif entrance_c == 2: + floor(16, 2) + floor(16, 3) + if remaining == [1, 3]: + wide(17, 4) + else: + tall(random.randint(11, 17), random.choice([2, 5])) + + if exit_c == 0: + r = random.sample([0, 1, 2], 2) + if 0 in r: + floor(1, 11) + floor(2, 11) + if 1 in r: + floor(3, 11) + floor(4, 11) + if 2 in r: + floor(5, 11) + floor(6, 11) + elif exit_c == 1 or (exit_c == 3 and entrance_c == 0): + r = random.sample([1, 3, 5, 7], random.randint(1, 2)) + for i in r: + floor(i, 11) + floor(i + 1, 11) + if exit_c != 3: + tall(random.choice([9, 10, 12]), 12) + + # 0 = top left, 1 = middle, 2 = top right, 3 = bottom right + # [0, 1] [0, 2] [1, 2] [1, 3], [2, 3] + if remaining[0] == 1: + floor(9, 5) + floor(9, 6) + + if remaining == [0, 2]: + if random.randint(0, 1): + tall(9, 4) + floor(9, 6) + floor(9, 7) + else: + floor(10, 7) + floor(11, 7) + + if remaining == [1, 2]: + floor(16, 2) + floor(16, 3) + tall(random.randint(11, 17), random.choice([2, 5])) + if remaining in [[1, 3], [2, 3]]: + r = round(random.triangular(0, 3, 0)) + floor(12 + (r * 2), 7) + if r < 3: + floor(13 + (r * 2), 7) + if remaining == [1, 3]: + wide(10, random.choice([3, 5])) + + if remaining != [0, 1] and exit_c != 1: + wide(7, 6) + + if entrance_c != 0: + if random.randint(0, 1): + wide(4, random.randint(4, 7)) + else: + wide(1, random.choice([5, 6, 7, 9])) + + current_map = map2f + + if 3 in remaining: + c = random.choice([entrance_c, exit_c]) + else: + c = random.choice(remaining) + + # 0 = top right, 1 = middle, 2 = bottom right, 3 = top left + if c in [0, 1]: + if random.randint(0, 2): + tall(random.choice([2, 4]), 5) + r = random.choice([1, 3, 7, 9, 11]) + floor(3 if r < 11 else random.randint(1, 2), r) + floor(3 if r < 11 else random.randint(1, 2), r + 1) + if random.randint(0, 2): + tall(random.randint(6, 7), 7) + r = random.choice([1, 3, 5, 9]) + floor(6, r) + floor(6, r + 1) + if random.randint(0, 2): + wide(7, 15) + r = random.randint(0, 4) + if r == 0: + floor(9, 14) + floor(10, 14) + elif r == 1: + floor(11, 14) + floor(12, 14) + elif r == 2: + floor(13, 13) + floor(13, 14) + elif r == 3: + floor(13, 11) + floor(13, 12) + elif r == 4: + floor(13, 10) + floor(14, 10) + if c == 0: + tall(random.randint(9, 10), 5) + if random.randint(0, 1): + floor(10, 7) + floor(11, 7) + tall(random.randint(12, 17), 8) + else: + floor(12, 5) + floor(12, 6) + wide(13, random.randint(4, 5)) + wide(17, random.randint(3, 5)) + r = random.choice([1, 3]) + floor(12, r) + floor(12, + 1) + + elif c == 2: + r = random.randint(0, 6) + if r == 0: + floor(12, 1) + floor(12, 2) + elif r == 1: + floor(12, 3) + floor(12, 4) + elif r == 2: + floor(12, 5) + floor(12, 6) + elif r == 3: + floor(10, 7) + floor(11, 7) + elif r == 4: + floor(9, 7) + floor(9, 8) + elif r == 5: + floor(9, 9) + floor(9, 10) + elif r == 6: + floor(8, 11) + floor(9, 11) + if r < 2 or (r in [2, 3] and random.randint(0, 1)): + wide(7, random.randint(6, 7)) + elif r in [2, 3]: + tall(random.randint(9, 10), 5) + else: + tall(random.randint(6, 7), 7) + r = random.randint(r, 6) + if r == 0: + #early block + wide(13, random.randint(2, 5)) + tall(random.randint(14, 15), 1) + elif r == 1: + if random.randint(0, 1): + tall(16, 5) + tall(random.choice([14, 15, 17]), 1) + else: + wide(16, random.randint(6,8)) + single(18, 7) + elif r == 2: + tall(random.randint(12, 16), 8) + elif r == 3: + wide(10, 9) + single(12, 9) + elif r == 4: + wide(10, random.randint(11, 12)) + single(12, random.randint(11, 12)) + elif r == 5: + tall(random.randint(8, 10), 12) + elif r == 6: + wide(7, 15) + r = random.randint(r, 6) + if r == 6: + #late open + r2 = random.randint(0, 2) + floor(1 + (r2 * 2), 14) + floor(2 + (r2 * 2), 14) + elif r == 5: + floor(6, 12) + floor(6, 13) + elif r == 4: + if random.randint(0, 1): + floor(6, 11) + floor(7, 11) + else: + floor(8, 11) + floor(9, 11) + elif r == 3: + floor(9, 9) + floor(9, 10) + elif r < 3: + single(9, 7) + floor(9, 8) + + def check_addable_block(check_map, disallowed): + if check_map[y][x] == 1 and [x, y] not in disallowed: + i = 0 + for xx in range(x-1, x+2): + for yy in range(y-1, y+2): + if check_map[yy][xx] == 1: + i += 1 + if i >= 8: + single(x, y) + + for _ in range(100): + y = random.randint(1, 16) + x = random.randint(1, 18) + current_map = map1f + check_addable_block(map1f, disallowed1F) + current_map = map2f + check_addable_block(map2f, disallowed2F) + + address = rom_addresses["Map_Rock_Tunnel1F"] + for y in map1f: + for x in y: + data[address] = x + address += 1 + address = rom_addresses["Map_Rock_TunnelB1F"] + for y in map2f: + for x in y: + data[address] = x + address += 1 + return seed \ No newline at end of file diff --git a/worlds/pokemon_rb/rom.py b/worlds/pokemon_rb/rom.py index 9dbc3a8b..1a5f3250 100644 --- a/worlds/pokemon_rb/rom.py +++ b/worlds/pokemon_rb/rom.py @@ -8,6 +8,7 @@ from .text import encode_text from .rom_addresses import rom_addresses from .locations import location_data from .items import item_table +from .rock_tunnel import randomize_rock_tunnel import worlds.pokemon_rb.poke_data as poke_data @@ -28,15 +29,15 @@ def filter_moves(moves, type, random): return ret -def get_move(moves, chances, random, starting_move=False): +def get_move(local_move_data, moves, chances, random, starting_move=False): type = choose_forced_type(chances, random) filtered_moves = filter_moves(moves, type, random) for move in filtered_moves: - if poke_data.moves[move]["accuracy"] > 80 and poke_data.moves[move]["power"] > 0 or not starting_move: + if local_move_data[move]["accuracy"] > 80 and local_move_data[move]["power"] > 0 or not starting_move: moves.remove(move) return move else: - return get_move(moves, [], random, starting_move) + return get_move(local_move_data, moves, [], random, starting_move) def get_encounter_slots(self): @@ -75,6 +76,42 @@ def randomize_pokemon(self, mon, mons_list, randomize_type, random): return mon +def set_mon_palettes(self, random, data): + if self.multiworld.randomize_pokemon_palettes[self.player] == "vanilla": + return + pallet_map = { + "Poison": 0x0F, + "Normal": 0x10, + "Ice": 0x11, + "Fire": 0x12, + "Water": 0x13, + "Ghost": 0x14, + "Ground": 0x15, + "Grass": 0x16, + "Psychic": 0x17, + "Electric": 0x18, + "Rock": 0x19, + "Dragon": 0x1F, + "Flying": 0x20, + "Fighting": 0x21, + "Bug": 0x22 + } + 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 + 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) + pallet = random.choice(list(pallet_map.values())) + palettes.append(pallet) + address = rom_addresses["Mon_Palettes"] + for pallet in palettes: + data[address] = pallet + address += 1 + + def process_trainer_data(self, data, random): 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] @@ -163,6 +200,7 @@ def process_static_pokemon(self): randomize_type, self.multiworld.random)) location.place_locked_item(mon) + 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 @@ -170,9 +208,13 @@ def process_static_pokemon(self): if not randomize_type: location.place_locked_item(self.create_item(slot_type + " " + slot.original_item)) else: - location.place_locked_item(self.create_item(slot_type + " " + - randomize_pokemon(self, slot.original_item, mons_list, randomize_type, - self.multiworld.random))) + mon = self.create_item(slot_type + " " + randomize_pokemon(self, slot.original_item, mons_list, + randomize_type, self.multiworld.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)) + chosen_mons.add(mon.name) + location.place_locked_item(mon) def process_wild_pokemon(self): @@ -180,27 +222,36 @@ def process_wild_pokemon(self): encounter_slots = get_encounter_slots(self) placed_mons = {pokemon: 0 for pokemon in poke_data.pokemon_data.keys()} + zone_mapping = {} if self.multiworld.randomize_wild_pokemon[self.player].value: 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) locations = [] for slot in encounter_slots: - mon = randomize_pokemon(self, slot.original_item, mons_list, - self.multiworld.randomize_wild_pokemon[self.player].value, self.multiworld.random) + location = self.multiworld.get_location(slot.name, self.player) + zone = " - ".join(location.name.split(" - ")[:-1]) + 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]: + 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) # if static Pokemon are not randomized, we make sure nothing on Pokemon Tower 6F is a Marowak # if static Pokemon are randomized we deal with that during static encounter randomization while (self.multiworld.randomize_static_pokemon[self.player].value == 0 and mon == "Marowak" and "Pokemon Tower 6F" in slot.name): # to account for the possibility that only one ground type Pokemon exists, match only stats for this fix - mon = randomize_pokemon(self, slot.original_item, mons_list, 2, self.multiworld.random) + mon = randomize_pokemon(self, original_mon, mons_list, 2, self.multiworld.random) placed_mons[mon] += 1 - location = self.multiworld.get_location(slot.name, self.player) location.item = self.create_item(mon) location.event = True location.locked = True location.item.location = location locations.append(location) + zone_mapping[zone][original_mon] = mon mons_to_add = [] remaining_pokemon = [pokemon for pokemon in poke_data.pokemon_data.keys() if placed_mons[pokemon] == 0 and @@ -223,22 +274,46 @@ def process_wild_pokemon(self): for mon in mons_to_add: stat_base = get_base_stat_total(mon) candidate_locations = get_encounter_slots(self) - if self.multiworld.randomize_wild_pokemon[self.player].value in [1, 3]: - candidate_locations = [slot for slot in candidate_locations if 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 [self.local_poke_data[mon]["type1"], - self.local_poke_data[mon]["type2"]]])] - if not candidate_locations: - candidate_locations = get_encounter_slots(self) candidate_locations = [self.multiworld.get_location(location.name, self.player) for location in candidate_locations] - candidate_locations.sort(key=lambda slot: abs(get_base_stat_total(slot.item.name) - stat_base)) + if self.multiworld.randomize_wild_pokemon[self.player].current_key in ["match_base_stats", "match_types_and_base_stats"]: + candidate_locations.sort(key=lambda slot: abs(get_base_stat_total(slot.item.name) - stat_base)) + if self.multiworld.randomize_wild_pokemon[self.player].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 + [self.local_poke_data[mon]["type1"], self.local_poke_data[mon]["type2"]]])) for location in candidate_locations: - if placed_mons[location.item.name] > 1 or location.item.name not in poke_data.first_stage_pokemon: - placed_mons[location.item.name] -= 1 - location.item = self.create_item(mon) - location.item.location = location + 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 not [self.multiworld.get_location(l.name, self.player) for l in get_encounter_slots(self) + 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 not [self.multiworld.get_location(l.name, self.player) for l in get_encounter_slots(self) + if (not l.name.startswith(zone)) and + self.multiworld.get_location(l.name, self.player).item.name == location.item.name and l.name + not in poke_data.evolves_from]: + 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]): + continue + + if self.multiworld.area_1_to_1_mapping[self.player]: + place_locations = [place_location for place_location in candidate_locations if + place_location.name.startswith(zone) and + place_location.item.name == location.item.name] + else: + place_locations = [location] + for place_location in place_locations: + placed_mons[place_location.item.name] -= 1 + place_location.item = self.create_item(mon) + place_location.item.location = place_location placed_mons[mon] += 1 - break + break + else: + raise Exception else: for slot in encounter_slots: @@ -250,10 +325,41 @@ def process_wild_pokemon(self): placed_mons[location.item.name] += 1 +def process_move_data(self): + self.local_move_data = deepcopy(poke_data.moves) + 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) + else: + self.local_tms = poke_data.tm_moves.copy() + + def process_pokemon_data(self): local_poke_data = deepcopy(poke_data.pokemon_data) learnsets = deepcopy(poke_data.learnsets) + tms_hms = self.local_tms + poke_data.hm_moves + + + compat_hms = set() for mon, mon_data in local_poke_data.items(): if self.multiworld.randomize_pokemon_stats[self.player].value == 1: @@ -265,18 +371,21 @@ def process_pokemon_data(self): mon_data["spd"] = stats[3] mon_data["spc"] = stats[4] elif self.multiworld.randomize_pokemon_stats[self.player].value == 2: - old_stats = mon_data["hp"] + mon_data["atk"] + mon_data["def"] + mon_data["spd"] + mon_data["spc"] - 5 - stats = [1, 1, 1, 1, 1] - while old_stats > 0: - stat = self.multiworld.random.randint(0, 4) - if stats[stat] < 255: - old_stats -= 1 - stats[stat] += 1 - mon_data["hp"] = stats[0] - mon_data["atk"] = stats[1] - mon_data["def"] = stats[2] - mon_data["spd"] = stats[3] - mon_data["spc"] = stats[4] + 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): + first_run = False + total_stats = mon_data["hp"] + mon_data["atk"] + mon_data["def"] + mon_data["spd"] + mon_data["spc"] - 60 + 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] + total_dist = sum(dist) + + mon_data["hp"] = int(round(dist[0] / total_dist * total_stats) + 20) + mon_data["atk"] = int(round(dist[1] / total_dist * total_stats) + 10) + mon_data["def"] = int(round(dist[2] / total_dist * total_stats) + 10) + mon_data["spd"] = int(round(dist[3] / total_dist * total_stats) + 10) + mon_data["spc"] = int(round(dist[4] / total_dist * total_stats) + 10) if self.multiworld.randomize_pokemon_types[self.player].value: if self.multiworld.randomize_pokemon_types[self.player].value == 1 and mon in poke_data.evolves_from: type1 = local_poke_data[poke_data.evolves_from[mon]]["type1"] @@ -318,46 +427,237 @@ def process_pokemon_data(self): moves = list(poke_data.moves.keys()) for move in ["No Move"] + poke_data.hm_moves: moves.remove(move) - mon_data["start move 1"] = get_move(moves, chances, self.multiworld.random, True) - for i in range(2, 5): - if mon_data[f"start move {i}"] != "No Move" or self.multiworld.start_with_four_moves[ - self.player].value == 1: - mon_data[f"start move {i}"] = get_move(moves, chances, self.multiworld.random) + if self.multiworld.confine_transform_to_ditto[self.player]: + moves.remove("Transform") + if self.multiworld.start_with_four_moves[self.player]: + num_moves = 4 + else: + num_moves = len([i for i in [mon_data["start move 1"], mon_data["start move 2"], + mon_data["start move 3"], mon_data["start move 4"]] if i != "No Move"]) if mon in learnsets: - for move_num in range(0, len(learnsets[mon])): - learnsets[mon][move_num] = get_move(moves, chances, self.multiworld.random) + num_moves += len(learnsets[mon]) + 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]: + 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) + if self.local_move_data[move]["power"] < 5: + non_power_moves.append(move) + else: + learnsets[mon].append(move) + learnsets[mon].sort(key=lambda move: self.local_move_data[move]["power"]) + if learnsets[mon]: + for move in non_power_moves: + learnsets[mon].insert(self.multiworld.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]: + mon_data[f"start move {i}"] = learnsets[mon].pop(0) + if self.multiworld.randomize_pokemon_catch_rates[self.player].value: mon_data["catch rate"] = self.multiworld.random.randint(self.multiworld.minimum_catch_rate[self.player], 255) else: mon_data["catch rate"] = max(self.multiworld.minimum_catch_rate[self.player], mon_data["catch rate"]) - if mon != "Mew": - tms_hms = poke_data.tm_moves + poke_data.hm_moves - for flag, tm_move in enumerate(tms_hms): - if ((mon in poke_data.evolves_from.keys() and mon_data["type1"] == - local_poke_data[poke_data.evolves_from[mon]]["type1"] and mon_data["type2"] == - local_poke_data[poke_data.evolves_from[mon]]["type2"]) and ( - (flag < 50 and self.multiworld.tm_compatibility[self.player].value in [1, 2]) or ( - flag >= 51 and self.multiworld.hm_compatibility[self.player].value in [1, 2]))): - bit = 1 if local_poke_data[poke_data.evolves_from[mon]]["tms"][int(flag / 8)] & 1 << (flag % 8) else 0 - elif (flag < 50 and self.multiworld.tm_compatibility[self.player].value == 1) or (flag >= 50 and self.multiworld.hm_compatibility[self.player].value == 1): - type_match = poke_data.moves[tm_move]["type"] in [mon_data["type1"], mon_data["type2"]] - bit = int(self.multiworld.random.randint(1, 100) < [[90, 50, 25], [100, 75, 25]][flag >= 50][0 if type_match else 1 if poke_data.moves[tm_move]["type"] == "Normal" else 2]) - elif (flag < 50 and self.multiworld.tm_compatibility[self.player].value == 2) or (flag >= 50 and self.multiworld.hm_compatibility[self.player].value == 2): - bit = self.multiworld.random.randint(0, 1) - elif (flag < 50 and self.multiworld.tm_compatibility[self.player].value == 3) or (flag >= 50 and self.multiworld.hm_compatibility[self.player].value == 3): + 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: + return mon_data["tms"][int(flag / 8)] + r = self.multiworld.random.randint(1, 100) <= self.multiworld.hm_same_type_compatibility[self.player].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: + return mon_data["tms"][int(flag / 8)] + return self.multiworld.random.randint(1, 100) <= self.multiworld.tm_same_type_compatibility[self.player].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: + return mon_data["tms"][int(flag / 8)] + r = self.multiworld.random.randint(1, 100) <= self.multiworld.hm_normal_type_compatibility[self.player].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: + return mon_data["tms"][int(flag / 8)] + return self.multiworld.random.randint(1, 100) <= self.multiworld.tm_normal_type_compatibility[self.player].value + else: + if roll_move in poke_data.hm_moves: + if self.multiworld.hm_other_type_compatibility[self.player].value == -1: + return mon_data["tms"][int(flag / 8)] + r = self.multiworld.random.randint(1, 100) <= self.multiworld.hm_other_type_compatibility[self.player].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: + return mon_data["tms"][int(flag / 8)] + return self.multiworld.random.randint(1, 100) <= self.multiworld.tm_other_type_compatibility[self.player].value + + + for flag, tm_move in enumerate(tms_hms): + if mon in poke_data.evolves_from.keys() and self.multiworld.inherit_tm_hm_compatibility[self.player]: + + if local_poke_data[poke_data.evolves_from[mon]]["tms"][int(flag / 8)] & 1 << (flag % 8): + # always inherit learnable tms/hms bit = 1 else: - continue - if bit: - mon_data["tms"][int(flag / 8)] |= 1 << (flag % 8) - else: - mon_data["tms"][int(flag / 8)] &= ~(1 << (flag % 8)) + if self.local_move_data[tm_move]["type"] in [mon_data["type1"], mon_data["type2"]] and \ + self.local_move_data[tm_move]["type"] not in [ + local_poke_data[poke_data.evolves_from[mon]]["type1"], + local_poke_data[poke_data.evolves_from[mon]]["type2"]]: + # the tm/hm is for a move whose type matches current mon, but not pre-evolved form + # 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): + bit = 1 + else: + bit = 0 + else: + bit = roll_tm_compat(tm_move) + if bit: + mon_data["tms"][int(flag / 8)] |= 1 << (flag % 8) + else: + 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_condition[self.player], + self.multiworld.victory_road_condition[self.player]) > 7): + hm_verify += ["Cut"] + if self.multiworld.accessibility[self.player] != "minimal" and (self.multiworld.trainersanity[self.player] or + self.multiworld.extra_key_items[self.player]): + hm_verify += ["Flash"] + + 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]) + flag = tms_hms.index(hm_move) + local_poke_data[mon]["tms"][int(flag / 8)] |= 1 << (flag % 8) self.local_poke_data = local_poke_data self.learnsets = learnsets +def write_quizzes(self, data, random): + + def get_quiz(q, a): + if q == 0: + r = random.randint(0, 3) + if r == 0: + mon = self.trade_mons["Trade_Dux"] + text = "A woman inVermilion City" + elif r == 1: + mon = self.trade_mons["Trade_Lola"] + text = "A man inCerulean City" + elif r == 2: + mon = self.trade_mons["Trade_Marcel"] + text = "Someone on Route 2" + elif r == 3: + mon = self.trade_mons["Trade_Spot"] + text = "Someone on Route 5" + if not a: + answers.append(0) + old_mon = mon + while old_mon == mon: + mon = random.choice(list(poke_data.pokemon_data.keys())) + + return encode_text(f"{text}was looking for{mon}?") + elif q == 1: + for location in self.multiworld.get_filled_locations(): + if location.item.name == "Secret Key" and location.item.player == self.player: + break + if location.player == self.player: + player_name = "yourself" + else: + player_name = self.multiworld.player_names[location.player] + if not a: + if len(self.multiworld.player_name) > 1: + old_name = player_name + while old_name == player_name: + player_name = random.choice(list(self.multiworld.player_name.values())) + else: + return encode_text("You're playingin a multiworldwith otherplayers?") + return encode_text(f"The Secret Key wasfound by{player_name[:17]}?") + elif q == 2: + if a: + return encode_text(f"#mon ispronouncedPo-kay-mon?") + else: + if random.randint(0, 1): + return encode_text(f"#mon ispronouncedPo-key-mon?") + else: + return encode_text(f"#mon ispronouncedPo-kuh-mon?") + elif q == 3: + starters = [" ".join(self.multiworld.get_location( + f"Pallet Town - Starter {i}", self.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): + while mon in starters: + mon = random.choice(list(poke_data.pokemon_data.keys())) + if a: + nots += 1 + elif not a: + nots += 1 + text = f"{mon} was" + while nots > 0: + i = random.randint(1, min(4, nots)) + text += ("not " * i) + "" + nots -= i + text += "a starter choice?" + return encode_text(text) + elif q == 4: + if a: + tm_text = self.local_tms[27] + else: + if self.multiworld.randomize_tm_moves[self.player]: + wrong_tms = self.local_tms.copy() + wrong_tms.pop(27) + tm_text = random.choice(wrong_tms) + else: + tm_text = "TOMBSTONER" + return encode_text(f"TM28 contains{tm_text.upper()}?") + elif q == 5: + i = 8 + while not a and i in [1, 8]: + i = random.randint(0, 99999999) + return encode_text(f"There are {i}certified #MONLEAGUE BADGEs?") + elif q == 6: + i = 2 + while not a and i in [1, 2]: + i = random.randint(0, 99) + return encode_text(f"POLIWAG evolves {i}times?") + elif q == 7: + entity = "Motor Carrier" + if not a: + entity = random.choice(["Driver", "Shipper"]) + return encode_text("Title 49 of theU.S. Code ofFederalRegulations part397.67 states" + f"that the{entity}is responsiblefor planningroutes when" + "hazardousmaterials aretransported?") + + answers = [random.randint(0, 1), random.randint(0, 1), random.randint(0, 1), + random.randint(0, 1), random.randint(0, 1), random.randint(0, 1)] + + questions = random.sample((range(0, 8)), 6) + question_texts = [] + for i, question in enumerate(questions): + question_texts.append(get_quiz(question, answers[i])) + + for i, quiz in enumerate(["A", "B", "C", "D", "E", "F"]): + data[rom_addresses[f"Quiz_Answer_{quiz}"]] = int(not answers[i]) << 4 | (i + 1) + 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 @@ -384,10 +684,33 @@ 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: - data[address] = self.item_name_to_id[location.item.name] - 172000000 + item_id = self.item_name_to_id[location.item.name] - 172000000 + if item_id > 255: + item_id -= 256 + data[address] = item_id else: data[location.rom_address] = 0x2C # AP Item + + def set_trade_mon(address, loc): + mon = self.multiworld.get_location(loc, self.player).item.name + data[rom_addresses[address]] = poke_data.pokemon_data[mon]["id"] + self.trade_mons[address] = mon + + if game_version == "red": + set_trade_mon("Trade_Terry", "Safari Zone Center - Wild Pokemon - 5") + set_trade_mon("Trade_Spot", "Safari Zone East - Wild Pokemon - 1") + else: + set_trade_mon("Trade_Terry", "Safari Zone Center - Wild Pokemon - 7") + set_trade_mon("Trade_Spot", "Safari Zone East - Wild Pokemon - 7") + set_trade_mon("Trade_Marcel", "Route 24 - Wild Pokemon - 6") + set_trade_mon("Trade_Sailor", "Pokemon Mansion 1F - Wild Pokemon - 3") + set_trade_mon("Trade_Dux", "Route 3 - Wild Pokemon - 2") + set_trade_mon("Trade_Marc", "Route 23 - Super Rod Pokemon - 1") + set_trade_mon("Trade_Lola", "Route 10 - Super Rod Pokemon - 1") + 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 if self.multiworld.tea[self.player].value: @@ -421,6 +744,14 @@ def generate_output(self, output_directory: str): if self.multiworld.old_man[self.player].value == 2: data[rom_addresses['Option_Old_Man']] = 0x11 data[rom_addresses['Option_Old_Man_Lying']] = 0x15 + if self.multiworld.require_pokedex[self.player]: + data[rom_addresses["Require_Pokedex_A"]] = 1 + data[rom_addresses["Require_Pokedex_B"]] = 1 + if self.multiworld.dexsanity[self.player]: + data[rom_addresses["Option_Dexsanity_A"]] = 1 + data[rom_addresses["Option_Dexsanity_B"]] = 1 + if self.multiworld.all_pokemon_seen[self.player]: + data[rom_addresses["Option_Pokedex_Seen"]] = 1 money = str(self.multiworld.starting_money[self.player].value).zfill(6) data[rom_addresses["Starting_Money_High"]] = int(money[:2], 16) data[rom_addresses["Starting_Money_Middle"]] = int(money[2:4], 16) @@ -433,6 +764,7 @@ def generate_output(self, output_directory: str): write_bytes(data, encode_text( " ".join(self.multiworld.get_location("Route 3 - Pokemon For Sale", self.player).item.name.upper().split()[1:])), rom_addresses["Text_Magikarp_Salesman"]) + write_quizzes(self, data, random) if self.multiworld.badges_needed_for_hm_moves[self.player].value == 0: for hm_move in poke_data.hm_moves: @@ -492,10 +824,10 @@ def generate_output(self, output_directory: str): 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: - address = rom_addresses["Learnset_" + mon.replace(" ", "")] - for i, move in enumerate(self.learnsets[mon]): - data[(address + 1) + i * 2] = poke_data.moves[move]["id"] + if mon in self.learnsets and self.learnsets[mon]: + address = rom_addresses["Learnset_" + mon.replace(" ", "")] + for i, move in enumerate(self.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 @@ -507,8 +839,8 @@ def generate_output(self, output_directory: str): if self.multiworld.reusable_tms[self.player].value: data[rom_addresses["Option_Reusable_TMs"]] = 0xC9 - data[rom_addresses["Option_Trainersanity"]] = self.multiworld.trainersanity[self.player].value - data[rom_addresses["Option_Trainersanity2"]] = self.multiworld.trainersanity[self.player].value + 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 self.multiworld.same_type_attack_bonus[self.player].value) @@ -532,8 +864,23 @@ def generate_output(self, output_directory: str): 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) process_trainer_data(self, data, random) + for move_data in self.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]) + write_bytes(data, TM_IDs, rom_addresses["TM_Moves"]) + + if self.multiworld.randomize_rock_tunnel[self.player]: + seed = randomize_rock_tunnel(data, random) + write_bytes(data, encode_text(f"SEED: {seed}"), rom_addresses["Text_Rock_Tunnel_Sign"]) + mons = [mon["id"] for mon in poke_data.pokemon_data.values()] random.shuffle(mons) data[rom_addresses['Title_Mon_First']] = mons.pop() @@ -564,7 +911,7 @@ def generate_output(self, output_directory: str): else: write_bytes(data, self.rival_name, rom_addresses['Rival_Name']) - data[0xFF00] = 1 # client compatibility version + data[0xFF00] = 2 # client compatibility version write_bytes(data, self.multiworld.seed_name.encode(), 0xFFDB) write_bytes(data, self.multiworld.player_name[self.player].encode(), 0xFFF0) diff --git a/worlds/pokemon_rb/rom_addresses.py b/worlds/pokemon_rb/rom_addresses.py index 30c38fa2..11b6e146 100644 --- a/worlds/pokemon_rb/rom_addresses.py +++ b/worlds/pokemon_rb/rom_addresses.py @@ -1,7 +1,7 @@ rom_addresses = { "Option_Encounter_Minimum_Steps": 0x3c3, - "Option_Blind_Trainers": 0x30fc, - "Option_Trainersanity": 0x318c, + "Option_Blind_Trainers": 0x30e2, + "Option_Trainersanity1": 0x3172, "Option_Lose_Money": 0x40d4, "Base_Stats_Mew": 0x4260, "Title_Mon_First": 0x4373, @@ -9,94 +9,95 @@ rom_addresses = { "Player_Name": 0x456e, "Rival_Name": 0x4576, "Price_Master_Ball": 0x45d0, - "Title_Seed": 0x5e3a, - "Title_Slot_Name": 0x5e5a, - "PC_Item": 0x6228, - "PC_Item_Quantity": 0x622d, - "Options": 0x623d, - "Fly_Location": 0x6242, - "Skip_Player_Name": 0x625b, - "Skip_Rival_Name": 0x6269, - "Option_Old_Man": 0xcafc, - "Option_Old_Man_Lying": 0xcaff, - "Option_Boulders": 0xcda5, - "Option_Rock_Tunnel_Extra_Items": 0xcdae, - "Wild_Route1": 0xd108, - "Wild_Route2": 0xd11e, - "Wild_Route22": 0xd134, - "Wild_ViridianForest": 0xd14a, - "Wild_Route3": 0xd160, - "Wild_MtMoon1F": 0xd176, - "Wild_MtMoonB1F": 0xd18c, - "Wild_MtMoonB2F": 0xd1a2, - "Wild_Route4": 0xd1b8, - "Wild_Route24": 0xd1ce, - "Wild_Route25": 0xd1e4, - "Wild_Route9": 0xd1fa, - "Wild_Route5": 0xd210, - "Wild_Route6": 0xd226, - "Wild_Route11": 0xd23c, - "Wild_RockTunnel1F": 0xd252, - "Wild_RockTunnelB1F": 0xd268, - "Wild_Route10": 0xd27e, - "Wild_Route12": 0xd294, - "Wild_Route8": 0xd2aa, - "Wild_Route7": 0xd2c0, - "Wild_PokemonTower3F": 0xd2da, - "Wild_PokemonTower4F": 0xd2f0, - "Wild_PokemonTower5F": 0xd306, - "Wild_PokemonTower6F": 0xd31c, - "Wild_PokemonTower7F": 0xd332, - "Wild_Route13": 0xd348, - "Wild_Route14": 0xd35e, - "Wild_Route15": 0xd374, - "Wild_Route16": 0xd38a, - "Wild_Route17": 0xd3a0, - "Wild_Route18": 0xd3b6, - "Wild_SafariZoneCenter": 0xd3cc, - "Wild_SafariZoneEast": 0xd3e2, - "Wild_SafariZoneNorth": 0xd3f8, - "Wild_SafariZoneWest": 0xd40e, - "Wild_SeaRoutes": 0xd425, - "Wild_SeafoamIslands1F": 0xd43a, - "Wild_SeafoamIslandsB1F": 0xd450, - "Wild_SeafoamIslandsB2F": 0xd466, - "Wild_SeafoamIslandsB3F": 0xd47c, - "Wild_SeafoamIslandsB4F": 0xd492, - "Wild_PokemonMansion1F": 0xd4a8, - "Wild_PokemonMansion2F": 0xd4be, - "Wild_PokemonMansion3F": 0xd4d4, - "Wild_PokemonMansionB1F": 0xd4ea, - "Wild_Route21": 0xd500, - "Wild_Surf_Route21": 0xd515, - "Wild_CeruleanCave1F": 0xd52a, - "Wild_CeruleanCave2F": 0xd540, - "Wild_CeruleanCaveB1F": 0xd556, - "Wild_PowerPlant": 0xd56c, - "Wild_Route23": 0xd582, - "Wild_VictoryRoad2F": 0xd598, - "Wild_VictoryRoad3F": 0xd5ae, - "Wild_VictoryRoad1F": 0xd5c4, - "Wild_DiglettsCave": 0xd5da, - "Ghost_Battle5": 0xd730, - "HM_Surf_Badge_a": 0xda1e, - "HM_Surf_Badge_b": 0xda23, - "Wild_Old_Rod": 0xe320, - "Wild_Good_Rod": 0xe34d, - "Option_Reusable_TMs": 0xe619, - "Wild_Super_Rod_A": 0xea4e, - "Wild_Super_Rod_B": 0xea53, - "Wild_Super_Rod_C": 0xea58, - "Wild_Super_Rod_D": 0xea5f, - "Wild_Super_Rod_E": 0xea64, - "Wild_Super_Rod_F": 0xea69, - "Wild_Super_Rod_G": 0xea72, - "Wild_Super_Rod_H": 0xea7b, - "Wild_Super_Rod_I": 0xea84, - "Wild_Super_Rod_J": 0xea8d, - "Starting_Money_High": 0xf957, - "Starting_Money_Middle": 0xf95a, - "Starting_Money_Low": 0xf95d, + "Title_Seed": 0x5e57, + "Title_Slot_Name": 0x5e77, + "PC_Item": 0x6245, + "PC_Item_Quantity": 0x624a, + "Options": 0x625a, + "Fly_Location": 0x625f, + "Skip_Player_Name": 0x6278, + "Skip_Rival_Name": 0x6286, + "Option_Old_Man": 0xcb05, + "Option_Old_Man_Lying": 0xcb08, + "Option_Boulders": 0xcdae, + "Option_Rock_Tunnel_Extra_Items": 0xcdb7, + "Wild_Route1": 0xd111, + "Wild_Route2": 0xd127, + "Wild_Route22": 0xd13d, + "Wild_ViridianForest": 0xd153, + "Wild_Route3": 0xd169, + "Wild_MtMoon1F": 0xd17f, + "Wild_MtMoonB1F": 0xd195, + "Wild_MtMoonB2F": 0xd1ab, + "Wild_Route4": 0xd1c1, + "Wild_Route24": 0xd1d7, + "Wild_Route25": 0xd1ed, + "Wild_Route9": 0xd203, + "Wild_Route5": 0xd219, + "Wild_Route6": 0xd22f, + "Wild_Route11": 0xd245, + "Wild_RockTunnel1F": 0xd25b, + "Wild_RockTunnelB1F": 0xd271, + "Wild_Route10": 0xd287, + "Wild_Route12": 0xd29d, + "Wild_Route8": 0xd2b3, + "Wild_Route7": 0xd2c9, + "Wild_PokemonTower3F": 0xd2e3, + "Wild_PokemonTower4F": 0xd2f9, + "Wild_PokemonTower5F": 0xd30f, + "Wild_PokemonTower6F": 0xd325, + "Wild_PokemonTower7F": 0xd33b, + "Wild_Route13": 0xd351, + "Wild_Route14": 0xd367, + "Wild_Route15": 0xd37d, + "Wild_Route16": 0xd393, + "Wild_Route17": 0xd3a9, + "Wild_Route18": 0xd3bf, + "Wild_SafariZoneCenter": 0xd3d5, + "Wild_SafariZoneEast": 0xd3eb, + "Wild_SafariZoneNorth": 0xd401, + "Wild_SafariZoneWest": 0xd417, + "Wild_SeaRoutes": 0xd42e, + "Wild_SeafoamIslands1F": 0xd443, + "Wild_SeafoamIslandsB1F": 0xd459, + "Wild_SeafoamIslandsB2F": 0xd46f, + "Wild_SeafoamIslandsB3F": 0xd485, + "Wild_SeafoamIslandsB4F": 0xd49b, + "Wild_PokemonMansion1F": 0xd4b1, + "Wild_PokemonMansion2F": 0xd4c7, + "Wild_PokemonMansion3F": 0xd4dd, + "Wild_PokemonMansionB1F": 0xd4f3, + "Wild_Route21": 0xd509, + "Wild_Surf_Route21": 0xd51e, + "Wild_CeruleanCave1F": 0xd533, + "Wild_CeruleanCave2F": 0xd549, + "Wild_CeruleanCaveB1F": 0xd55f, + "Wild_PowerPlant": 0xd575, + "Wild_Route23": 0xd58b, + "Wild_VictoryRoad2F": 0xd5a1, + "Wild_VictoryRoad3F": 0xd5b7, + "Wild_VictoryRoad1F": 0xd5cd, + "Wild_DiglettsCave": 0xd5e3, + "Ghost_Battle5": 0xd739, + "HM_Surf_Badge_a": 0xda2f, + "HM_Surf_Badge_b": 0xda34, + "Wild_Old_Rod": 0xe331, + "Wild_Good_Rod": 0xe35e, + "Option_Reusable_TMs": 0xe62a, + "Wild_Super_Rod_A": 0xea5f, + "Wild_Super_Rod_B": 0xea64, + "Wild_Super_Rod_C": 0xea69, + "Wild_Super_Rod_D": 0xea70, + "Wild_Super_Rod_E": 0xea75, + "Wild_Super_Rod_F": 0xea7a, + "Wild_Super_Rod_G": 0xea83, + "Wild_Super_Rod_H": 0xea8c, + "Wild_Super_Rod_I": 0xea95, + "Wild_Super_Rod_J": 0xea9e, + "Starting_Money_High": 0xf968, + "Starting_Money_Middle": 0xf96b, + "Starting_Money_Low": 0xf96e, + "Option_Pokedex_Seen": 0xf989, "HM_Fly_Badge_a": 0x1318e, "HM_Fly_Badge_b": 0x13193, "HM_Cut_Badge_a": 0x131c4, @@ -105,35 +106,36 @@ rom_addresses = { "HM_Strength_Badge_b": 0x131f9, "HM_Flash_Badge_a": 0x13208, "HM_Flash_Badge_b": 0x1320d, + "TM_Moves": 0x1376c, "Encounter_Chances": 0x13911, "Option_Viridian_Gym_Badges": 0x1901d, "Event_Sleepy_Guy": 0x191bc, "Starter2_K": 0x195a8, "Starter3_K": 0x195b0, "Event_Rocket_Thief": 0x196cc, - "Option_Cerulean_Cave_Condition": 0x1986c, - "Event_Stranded_Man": 0x19b1f, - "Event_Rivals_Sister": 0x19cf2, - "Option_Pokemon_League_Badges": 0x19e0f, - "Shop10": 0x19ee6, - "Trainersanity_EVENT_BEAT_SILPH_CO_4F_TRAINER_0_ITEM": 0x1a03a, - "Trainersanity_EVENT_BEAT_SILPH_CO_4F_TRAINER_1_ITEM": 0x1a048, - "Trainersanity_EVENT_BEAT_SILPH_CO_4F_TRAINER_2_ITEM": 0x1a056, - "Missable_Silph_Co_4F_Item_1": 0x1a0fe, - "Missable_Silph_Co_4F_Item_2": 0x1a105, - "Missable_Silph_Co_4F_Item_3": 0x1a10c, - "Trainersanity_EVENT_BEAT_SILPH_CO_5F_TRAINER_0_ITEM": 0x1a264, - "Trainersanity_EVENT_BEAT_SILPH_CO_5F_TRAINER_1_ITEM": 0x1a272, - "Trainersanity_EVENT_BEAT_SILPH_CO_5F_TRAINER_2_ITEM": 0x1a280, - "Trainersanity_EVENT_BEAT_SILPH_CO_5F_TRAINER_3_ITEM": 0x1a28e, - "Missable_Silph_Co_5F_Item_1": 0x1a366, - "Missable_Silph_Co_5F_Item_2": 0x1a36d, - "Missable_Silph_Co_5F_Item_3": 0x1a374, - "Trainersanity_EVENT_BEAT_SILPH_CO_6F_TRAINER_0_ITEM": 0x1a4a4, - "Trainersanity_EVENT_BEAT_SILPH_CO_6F_TRAINER_1_ITEM": 0x1a4b2, - "Trainersanity_EVENT_BEAT_SILPH_CO_6F_TRAINER_2_ITEM": 0x1a4c0, - "Missable_Silph_Co_6F_Item_1": 0x1a5e2, - "Missable_Silph_Co_6F_Item_2": 0x1a5e9, + "Option_Cerulean_Cave_Condition": 0x19875, + "Event_Stranded_Man": 0x19b28, + "Event_Rivals_Sister": 0x19cfb, + "Option_Pokemon_League_Badges": 0x19e18, + "Shop10": 0x19eef, + "Trainersanity_EVENT_BEAT_SILPH_CO_4F_TRAINER_0_ITEM": 0x1a043, + "Trainersanity_EVENT_BEAT_SILPH_CO_4F_TRAINER_1_ITEM": 0x1a051, + "Trainersanity_EVENT_BEAT_SILPH_CO_4F_TRAINER_2_ITEM": 0x1a05f, + "Missable_Silph_Co_4F_Item_1": 0x1a107, + "Missable_Silph_Co_4F_Item_2": 0x1a10e, + "Missable_Silph_Co_4F_Item_3": 0x1a115, + "Trainersanity_EVENT_BEAT_SILPH_CO_5F_TRAINER_0_ITEM": 0x1a26d, + "Trainersanity_EVENT_BEAT_SILPH_CO_5F_TRAINER_1_ITEM": 0x1a27b, + "Trainersanity_EVENT_BEAT_SILPH_CO_5F_TRAINER_2_ITEM": 0x1a289, + "Trainersanity_EVENT_BEAT_SILPH_CO_5F_TRAINER_3_ITEM": 0x1a297, + "Missable_Silph_Co_5F_Item_1": 0x1a36f, + "Missable_Silph_Co_5F_Item_2": 0x1a376, + "Missable_Silph_Co_5F_Item_3": 0x1a37d, + "Trainersanity_EVENT_BEAT_SILPH_CO_6F_TRAINER_0_ITEM": 0x1a4ad, + "Trainersanity_EVENT_BEAT_SILPH_CO_6F_TRAINER_1_ITEM": 0x1a4bb, + "Trainersanity_EVENT_BEAT_SILPH_CO_6F_TRAINER_2_ITEM": 0x1a4c9, + "Missable_Silph_Co_6F_Item_1": 0x1a5eb, + "Missable_Silph_Co_6F_Item_2": 0x1a5f2, "Event_Free_Sample": 0x1cad6, "Starter1_F": 0x1cca2, "Starter2_F": 0x1cca6, @@ -145,49 +147,50 @@ rom_addresses = { "Starter2_I": 0x1d0fa, "Starter1_D": 0x1d101, "Starter3_D": 0x1d10b, - "Starter2_E": 0x1d2e5, - "Starter3_E": 0x1d2ed, - "Event_Pokedex": 0x1d351, - "Event_Oaks_Gift": 0x1d381, - "Event_Pokemart_Quest": 0x1d579, - "Shop1": 0x1d5a3, - "Event_Bicycle_Shop": 0x1d83d, - "Text_Bicycle": 0x1d8d0, - "Event_Fuji": 0x1da05, - "Trainersanity_EVENT_BEAT_MEW_ITEM": 0x1dc58, - "Static_Encounter_Mew": 0x1dc88, - "Gift_Eevee": 0x1dd01, - "Shop7": 0x1dd53, - "Event_Mr_Psychic": 0x1de30, - "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_0_ITEM": 0x1e32b, - "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_1_ITEM": 0x1e339, - "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_2_ITEM": 0x1e347, - "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_3_ITEM": 0x1e355, - "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_4_ITEM": 0x1e363, - "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_5_ITEM": 0x1e371, - "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_6_ITEM": 0x1e37f, - "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_7_ITEM": 0x1e38d, - "Trainersanity_EVENT_BEAT_ZAPDOS_ITEM": 0x1e39b, - "Static_Encounter_Voltorb_A": 0x1e40a, - "Static_Encounter_Voltorb_B": 0x1e412, - "Static_Encounter_Voltorb_C": 0x1e41a, - "Static_Encounter_Electrode_A": 0x1e422, - "Static_Encounter_Voltorb_D": 0x1e42a, - "Static_Encounter_Voltorb_E": 0x1e432, - "Static_Encounter_Electrode_B": 0x1e43a, - "Static_Encounter_Voltorb_F": 0x1e442, - "Static_Encounter_Zapdos": 0x1e44a, - "Missable_Power_Plant_Item_1": 0x1e452, - "Missable_Power_Plant_Item_2": 0x1e459, - "Missable_Power_Plant_Item_3": 0x1e460, - "Missable_Power_Plant_Item_4": 0x1e467, - "Missable_Power_Plant_Item_5": 0x1e46e, - "Event_Rt16_House_Woman": 0x1e647, - "Option_Victory_Road_Badges": 0x1e718, - "Event_Bill": 0x1e949, + "Starter2_E": 0x1d300, + "Starter3_E": 0x1d308, + "Event_Pokedex": 0x1d36c, + "Event_Oaks_Gift": 0x1d39c, + "Event_Pokemart_Quest": 0x1d594, + "Shop1": 0x1d5be, + "Event_Bicycle_Shop": 0x1d858, + "Text_Bicycle": 0x1d8eb, + "Event_Fuji": 0x1da20, + "Trainersanity_EVENT_BEAT_MEW_ITEM": 0x1dc73, + "Static_Encounter_Mew": 0x1dca3, + "Gift_Eevee": 0x1dd1c, + "Shop7": 0x1dd6e, + "Event_Mr_Psychic": 0x1de4b, + "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_0_ITEM": 0x1e346, + "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_1_ITEM": 0x1e354, + "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_2_ITEM": 0x1e362, + "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_3_ITEM": 0x1e370, + "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_4_ITEM": 0x1e37e, + "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_5_ITEM": 0x1e38c, + "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_6_ITEM": 0x1e39a, + "Trainersanity_EVENT_BEAT_POWER_PLANT_VOLTORB_7_ITEM": 0x1e3a8, + "Trainersanity_EVENT_BEAT_ZAPDOS_ITEM": 0x1e3b6, + "Static_Encounter_Voltorb_A": 0x1e425, + "Static_Encounter_Voltorb_B": 0x1e42d, + "Static_Encounter_Voltorb_C": 0x1e435, + "Static_Encounter_Electrode_A": 0x1e43d, + "Static_Encounter_Voltorb_D": 0x1e445, + "Static_Encounter_Voltorb_E": 0x1e44d, + "Static_Encounter_Electrode_B": 0x1e455, + "Static_Encounter_Voltorb_F": 0x1e45d, + "Static_Encounter_Zapdos": 0x1e465, + "Missable_Power_Plant_Item_1": 0x1e46d, + "Missable_Power_Plant_Item_2": 0x1e474, + "Missable_Power_Plant_Item_3": 0x1e47b, + "Missable_Power_Plant_Item_4": 0x1e482, + "Missable_Power_Plant_Item_5": 0x1e489, + "Event_Rt16_House_Woman": 0x1e662, + "Option_Victory_Road_Badges": 0x1e733, + "Event_Bill": 0x1e964, "Starter1_O": 0x372b0, "Starter2_O": 0x372b4, "Starter3_O": 0x372b8, + "Move_Data": 0x38000, "Base_Stats": 0x383de, "Starter3_C": 0x39cf2, "Starter1_C": 0x39cf8, @@ -217,320 +220,345 @@ rom_addresses = { "Rival_Starter3_H": 0x3a4ab, "Rival_Starter1_H": 0x3a4b9, "Trainer_Data_End": 0x3a52e, - "Learnset_Rhydon": 0x3b1d9, - "Learnset_Kangaskhan": 0x3b1e7, - "Learnset_NidoranM": 0x3b1f6, - "Learnset_Clefairy": 0x3b208, - "Learnset_Spearow": 0x3b219, - "Learnset_Voltorb": 0x3b228, - "Learnset_Nidoking": 0x3b234, - "Learnset_Slowbro": 0x3b23c, - "Learnset_Ivysaur": 0x3b24f, - "Learnset_Exeggutor": 0x3b25f, - "Learnset_Lickitung": 0x3b263, - "Learnset_Exeggcute": 0x3b273, - "Learnset_Grimer": 0x3b284, - "Learnset_Gengar": 0x3b292, - "Learnset_NidoranF": 0x3b29b, - "Learnset_Nidoqueen": 0x3b2a9, - "Learnset_Cubone": 0x3b2b4, - "Learnset_Rhyhorn": 0x3b2c3, - "Learnset_Lapras": 0x3b2d1, - "Learnset_Mew": 0x3b2e1, - "Learnset_Gyarados": 0x3b2eb, - "Learnset_Shellder": 0x3b2fb, - "Learnset_Tentacool": 0x3b30a, - "Learnset_Gastly": 0x3b31f, - "Learnset_Scyther": 0x3b325, - "Learnset_Staryu": 0x3b337, - "Learnset_Blastoise": 0x3b347, - "Learnset_Pinsir": 0x3b355, - "Learnset_Tangela": 0x3b363, - "Learnset_Growlithe": 0x3b379, - "Learnset_Onix": 0x3b385, - "Learnset_Fearow": 0x3b391, - "Learnset_Pidgey": 0x3b3a0, - "Learnset_Slowpoke": 0x3b3b1, - "Learnset_Kadabra": 0x3b3c9, - "Learnset_Graveler": 0x3b3e1, - "Learnset_Chansey": 0x3b3ef, - "Learnset_Machoke": 0x3b407, - "Learnset_MrMime": 0x3b413, - "Learnset_Hitmonlee": 0x3b41f, - "Learnset_Hitmonchan": 0x3b42b, - "Learnset_Arbok": 0x3b437, - "Learnset_Parasect": 0x3b443, - "Learnset_Psyduck": 0x3b452, - "Learnset_Drowzee": 0x3b461, - "Learnset_Golem": 0x3b46f, - "Learnset_Magmar": 0x3b47f, - "Learnset_Electabuzz": 0x3b48f, - "Learnset_Magneton": 0x3b49b, - "Learnset_Koffing": 0x3b4ac, - "Learnset_Mankey": 0x3b4bd, - "Learnset_Seel": 0x3b4cc, - "Learnset_Diglett": 0x3b4db, - "Learnset_Tauros": 0x3b4e7, - "Learnset_Farfetchd": 0x3b4f9, - "Learnset_Venonat": 0x3b508, - "Learnset_Dragonite": 0x3b516, - "Learnset_Doduo": 0x3b52b, - "Learnset_Poliwag": 0x3b53c, - "Learnset_Jynx": 0x3b54a, - "Learnset_Moltres": 0x3b558, - "Learnset_Articuno": 0x3b560, - "Learnset_Zapdos": 0x3b568, - "Learnset_Meowth": 0x3b575, - "Learnset_Krabby": 0x3b584, - "Learnset_Vulpix": 0x3b59a, - "Learnset_Pikachu": 0x3b5ac, - "Learnset_Dratini": 0x3b5c1, - "Learnset_Dragonair": 0x3b5d0, - "Learnset_Kabuto": 0x3b5df, - "Learnset_Kabutops": 0x3b5e9, - "Learnset_Horsea": 0x3b5f6, - "Learnset_Seadra": 0x3b602, - "Learnset_Sandshrew": 0x3b615, - "Learnset_Sandslash": 0x3b621, - "Learnset_Omanyte": 0x3b630, - "Learnset_Omastar": 0x3b63a, - "Learnset_Jigglypuff": 0x3b648, - "Learnset_Eevee": 0x3b666, - "Learnset_Flareon": 0x3b670, - "Learnset_Jolteon": 0x3b682, - "Learnset_Vaporeon": 0x3b694, - "Learnset_Machop": 0x3b6a9, - "Learnset_Zubat": 0x3b6b8, - "Learnset_Ekans": 0x3b6c7, - "Learnset_Paras": 0x3b6d6, - "Learnset_Poliwhirl": 0x3b6e6, - "Learnset_Poliwrath": 0x3b6f4, - "Learnset_Beedrill": 0x3b704, - "Learnset_Dodrio": 0x3b714, - "Learnset_Primeape": 0x3b722, - "Learnset_Dugtrio": 0x3b72e, - "Learnset_Venomoth": 0x3b73a, - "Learnset_Dewgong": 0x3b748, - "Learnset_Butterfree": 0x3b762, - "Learnset_Machamp": 0x3b772, - "Learnset_Golduck": 0x3b780, - "Learnset_Hypno": 0x3b78c, - "Learnset_Golbat": 0x3b79a, - "Learnset_Mewtwo": 0x3b7a6, - "Learnset_Snorlax": 0x3b7b2, - "Learnset_Magikarp": 0x3b7bf, - "Learnset_Muk": 0x3b7c7, - "Learnset_Kingler": 0x3b7d7, - "Learnset_Cloyster": 0x3b7e3, - "Learnset_Electrode": 0x3b7e9, - "Learnset_Weezing": 0x3b7f7, - "Learnset_Persian": 0x3b803, - "Learnset_Marowak": 0x3b80f, - "Learnset_Haunter": 0x3b827, - "Learnset_Alakazam": 0x3b832, - "Learnset_Pidgeotto": 0x3b843, - "Learnset_Pidgeot": 0x3b851, - "Learnset_Bulbasaur": 0x3b864, - "Learnset_Venusaur": 0x3b874, - "Learnset_Tentacruel": 0x3b884, - "Learnset_Goldeen": 0x3b89b, - "Learnset_Seaking": 0x3b8a9, - "Learnset_Ponyta": 0x3b8c2, - "Learnset_Rapidash": 0x3b8d0, - "Learnset_Rattata": 0x3b8e1, - "Learnset_Raticate": 0x3b8eb, - "Learnset_Nidorino": 0x3b8f9, - "Learnset_Nidorina": 0x3b90b, - "Learnset_Geodude": 0x3b91c, - "Learnset_Porygon": 0x3b92a, - "Learnset_Aerodactyl": 0x3b934, - "Learnset_Magnemite": 0x3b942, - "Learnset_Charmander": 0x3b957, - "Learnset_Squirtle": 0x3b968, - "Learnset_Charmeleon": 0x3b979, - "Learnset_Wartortle": 0x3b98a, - "Learnset_Charizard": 0x3b998, - "Learnset_Oddish": 0x3b9b1, - "Learnset_Gloom": 0x3b9c3, - "Learnset_Vileplume": 0x3b9d1, - "Learnset_Bellsprout": 0x3b9dc, - "Learnset_Weepinbell": 0x3b9f0, - "Learnset_Victreebel": 0x3ba00, + "Learnset_Rhydon": 0x3b1e1, + "Learnset_Kangaskhan": 0x3b1ef, + "Learnset_NidoranM": 0x3b1fe, + "Learnset_Clefairy": 0x3b210, + "Learnset_Spearow": 0x3b221, + "Learnset_Voltorb": 0x3b230, + "Learnset_Nidoking": 0x3b23c, + "Learnset_Slowbro": 0x3b244, + "Learnset_Ivysaur": 0x3b257, + "Learnset_Exeggutor": 0x3b267, + "Learnset_Lickitung": 0x3b26b, + "Learnset_Exeggcute": 0x3b27b, + "Learnset_Grimer": 0x3b28c, + "Learnset_Gengar": 0x3b29a, + "Learnset_NidoranF": 0x3b2a3, + "Learnset_Nidoqueen": 0x3b2b1, + "Learnset_Cubone": 0x3b2bc, + "Learnset_Rhyhorn": 0x3b2cb, + "Learnset_Lapras": 0x3b2d9, + "Learnset_Mew": 0x3b2e9, + "Learnset_Gyarados": 0x3b2f3, + "Learnset_Shellder": 0x3b303, + "Learnset_Tentacool": 0x3b312, + "Learnset_Gastly": 0x3b327, + "Learnset_Scyther": 0x3b32d, + "Learnset_Staryu": 0x3b33f, + "Learnset_Blastoise": 0x3b34f, + "Learnset_Pinsir": 0x3b35d, + "Learnset_Tangela": 0x3b36b, + "Learnset_Growlithe": 0x3b381, + "Learnset_Onix": 0x3b38d, + "Learnset_Fearow": 0x3b399, + "Learnset_Pidgey": 0x3b3a8, + "Learnset_Slowpoke": 0x3b3b9, + "Learnset_Kadabra": 0x3b3d1, + "Learnset_Graveler": 0x3b3e9, + "Learnset_Chansey": 0x3b3f7, + "Learnset_Machoke": 0x3b40f, + "Learnset_MrMime": 0x3b41b, + "Learnset_Hitmonlee": 0x3b427, + "Learnset_Hitmonchan": 0x3b433, + "Learnset_Arbok": 0x3b43f, + "Learnset_Parasect": 0x3b44b, + "Learnset_Psyduck": 0x3b45a, + "Learnset_Drowzee": 0x3b469, + "Learnset_Golem": 0x3b477, + "Learnset_Magmar": 0x3b487, + "Learnset_Electabuzz": 0x3b497, + "Learnset_Magneton": 0x3b4a3, + "Learnset_Koffing": 0x3b4b4, + "Learnset_Mankey": 0x3b4c5, + "Learnset_Seel": 0x3b4d4, + "Learnset_Diglett": 0x3b4e3, + "Learnset_Tauros": 0x3b4ef, + "Learnset_Farfetchd": 0x3b501, + "Learnset_Venonat": 0x3b510, + "Learnset_Dragonite": 0x3b51e, + "Learnset_Doduo": 0x3b533, + "Learnset_Poliwag": 0x3b544, + "Learnset_Jynx": 0x3b552, + "Learnset_Moltres": 0x3b560, + "Learnset_Articuno": 0x3b568, + "Learnset_Zapdos": 0x3b570, + "Learnset_Meowth": 0x3b57d, + "Learnset_Krabby": 0x3b58c, + "Learnset_Vulpix": 0x3b5a2, + "Learnset_Pikachu": 0x3b5b4, + "Learnset_Dratini": 0x3b5c9, + "Learnset_Dragonair": 0x3b5d8, + "Learnset_Kabuto": 0x3b5e7, + "Learnset_Kabutops": 0x3b5f1, + "Learnset_Horsea": 0x3b5fe, + "Learnset_Seadra": 0x3b60a, + "Learnset_Sandshrew": 0x3b61d, + "Learnset_Sandslash": 0x3b629, + "Learnset_Omanyte": 0x3b638, + "Learnset_Omastar": 0x3b642, + "Learnset_Jigglypuff": 0x3b650, + "Learnset_Eevee": 0x3b66e, + "Learnset_Flareon": 0x3b678, + "Learnset_Jolteon": 0x3b68a, + "Learnset_Vaporeon": 0x3b69c, + "Learnset_Machop": 0x3b6b1, + "Learnset_Zubat": 0x3b6c0, + "Learnset_Ekans": 0x3b6cf, + "Learnset_Paras": 0x3b6de, + "Learnset_Poliwhirl": 0x3b6ee, + "Learnset_Poliwrath": 0x3b6fc, + "Learnset_Beedrill": 0x3b70c, + "Learnset_Dodrio": 0x3b71c, + "Learnset_Primeape": 0x3b72a, + "Learnset_Dugtrio": 0x3b736, + "Learnset_Venomoth": 0x3b742, + "Learnset_Dewgong": 0x3b750, + "Learnset_Butterfree": 0x3b76a, + "Learnset_Machamp": 0x3b77a, + "Learnset_Golduck": 0x3b788, + "Learnset_Hypno": 0x3b794, + "Learnset_Golbat": 0x3b7a2, + "Learnset_Mewtwo": 0x3b7ae, + "Learnset_Snorlax": 0x3b7ba, + "Learnset_Magikarp": 0x3b7c7, + "Learnset_Muk": 0x3b7cf, + "Learnset_Kingler": 0x3b7df, + "Learnset_Cloyster": 0x3b7eb, + "Learnset_Electrode": 0x3b7f1, + "Learnset_Weezing": 0x3b7ff, + "Learnset_Persian": 0x3b80b, + "Learnset_Marowak": 0x3b817, + "Learnset_Haunter": 0x3b82f, + "Learnset_Alakazam": 0x3b83a, + "Learnset_Pidgeotto": 0x3b84b, + "Learnset_Pidgeot": 0x3b859, + "Learnset_Bulbasaur": 0x3b86c, + "Learnset_Venusaur": 0x3b87c, + "Learnset_Tentacruel": 0x3b88c, + "Learnset_Goldeen": 0x3b8a3, + "Learnset_Seaking": 0x3b8b1, + "Learnset_Ponyta": 0x3b8ca, + "Learnset_Rapidash": 0x3b8d8, + "Learnset_Rattata": 0x3b8e9, + "Learnset_Raticate": 0x3b8f3, + "Learnset_Nidorino": 0x3b901, + "Learnset_Nidorina": 0x3b913, + "Learnset_Geodude": 0x3b924, + "Learnset_Porygon": 0x3b932, + "Learnset_Aerodactyl": 0x3b93c, + "Learnset_Magnemite": 0x3b94b, + "Learnset_Charmander": 0x3b960, + "Learnset_Squirtle": 0x3b971, + "Learnset_Charmeleon": 0x3b982, + "Learnset_Wartortle": 0x3b993, + "Learnset_Charizard": 0x3b9a1, + "Learnset_Oddish": 0x3b9ba, + "Learnset_Gloom": 0x3b9cc, + "Learnset_Vileplume": 0x3b9da, + "Learnset_Bellsprout": 0x3b9e5, + "Learnset_Weepinbell": 0x3b9f9, + "Learnset_Victreebel": 0x3ba09, "Option_Always_Half_STAB": 0x3e3fb, "Type_Chart": 0x3e4ee, "Ghost_Battle3": 0x3f1be, - "Trainersanity_EVENT_BEAT_MANSION_1_TRAINER_0_ITEM": 0x44341, - "Missable_Pokemon_Mansion_1F_Item_1": 0x443d8, - "Missable_Pokemon_Mansion_1F_Item_2": 0x443df, - "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_1_TRAINER_0_ITEM": 0x44514, - "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_1_TRAINER_1_ITEM": 0x44522, - "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_1_TRAINER_2_ITEM": 0x44530, - "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_1_TRAINER_3_ITEM": 0x4453e, - "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_1_TRAINER_4_ITEM": 0x4454c, - "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_1_TRAINER_5_ITEM": 0x4455a, - "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_1_TRAINER_6_ITEM": 0x44568, - "Map_Rock_TunnelF": 0x44686, - "Trainersanity_EVENT_BEAT_VICTORY_ROAD_3_TRAINER_0_ITEM": 0x44a55, - "Trainersanity_EVENT_BEAT_VICTORY_ROAD_3_TRAINER_1_ITEM": 0x44a63, - "Trainersanity_EVENT_BEAT_VICTORY_ROAD_3_TRAINER_2_ITEM": 0x44a71, - "Trainersanity_EVENT_BEAT_VICTORY_ROAD_3_TRAINER_3_ITEM": 0x44a7f, - "Missable_Victory_Road_3F_Item_1": 0x44b1f, - "Missable_Victory_Road_3F_Item_2": 0x44b26, - "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_1_TRAINER_0_ITEM": 0x44c47, - "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_1_TRAINER_1_ITEM": 0x44c55, - "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_1_TRAINER_2_ITEM": 0x44c63, - "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_1_TRAINER_3_ITEM": 0x44c71, - "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_1_TRAINER_4_ITEM": 0x44c7f, - "Missable_Rocket_Hideout_B1F_Item_1": 0x44d4f, - "Missable_Rocket_Hideout_B1F_Item_2": 0x44d56, - "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_2_TRAINER_0_ITEM": 0x45100, - "Missable_Rocket_Hideout_B2F_Item_1": 0x45141, - "Missable_Rocket_Hideout_B2F_Item_2": 0x45148, - "Missable_Rocket_Hideout_B2F_Item_3": 0x4514f, - "Missable_Rocket_Hideout_B2F_Item_4": 0x45156, - "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_3_TRAINER_0_ITEM": 0x45333, - "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_3_TRAINER_1_ITEM": 0x45341, - "Missable_Rocket_Hideout_B3F_Item_1": 0x45397, - "Missable_Rocket_Hideout_B3F_Item_2": 0x4539e, - "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_4_TRAINER_0_ITEM": 0x4554a, - "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_4_TRAINER_1_ITEM": 0x45558, - "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_4_TRAINER_2_ITEM": 0x45566, - "Missable_Rocket_Hideout_B4F_Item_1": 0x45655, - "Missable_Rocket_Hideout_B4F_Item_2": 0x4565c, - "Missable_Rocket_Hideout_B4F_Item_3": 0x45663, - "Missable_Rocket_Hideout_B4F_Item_4": 0x4566a, - "Missable_Rocket_Hideout_B4F_Item_5": 0x45671, - "Missable_Safari_Zone_East_Item_1": 0x458e0, - "Missable_Safari_Zone_East_Item_2": 0x458e7, - "Missable_Safari_Zone_East_Item_3": 0x458ee, - "Missable_Safari_Zone_East_Item_4": 0x458f5, - "Missable_Safari_Zone_North_Item_1": 0x45a40, - "Missable_Safari_Zone_North_Item_2": 0x45a47, - "Missable_Safari_Zone_Center_Item": 0x45c27, - "Missable_Cerulean_Cave_2F_Item_1": 0x45e64, - "Missable_Cerulean_Cave_2F_Item_2": 0x45e6b, - "Missable_Cerulean_Cave_2F_Item_3": 0x45e72, - "Trainersanity_EVENT_BEAT_MEWTWO_ITEM": 0x45f4a, - "Static_Encounter_Mewtwo": 0x45f74, - "Missable_Cerulean_Cave_B1F_Item_1": 0x45f7c, - "Missable_Cerulean_Cave_B1F_Item_2": 0x45f83, - "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_2_TRAINER_0_ITEM": 0x46059, - "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_2_TRAINER_1_ITEM": 0x46067, - "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_2_TRAINER_2_ITEM": 0x46075, - "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_2_TRAINER_3_ITEM": 0x46083, - "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_2_TRAINER_4_ITEM": 0x46091, - "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_2_TRAINER_5_ITEM": 0x4609f, - "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_2_TRAINER_6_ITEM": 0x460ad, - "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_2_TRAINER_7_ITEM": 0x460bb, - "Missable_Rock_Tunnel_B1F_Item_1": 0x461df, - "Missable_Rock_Tunnel_B1F_Item_2": 0x461e6, - "Missable_Rock_Tunnel_B1F_Item_3": 0x461ed, - "Missable_Rock_Tunnel_B1F_Item_4": 0x461f4, - "Trainersanity_EVENT_BEAT_ARTICUNO_ITEM": 0x468f7, - "Static_Encounter_Articuno": 0x4694e, - "Hidden_Item_Viridian_Forest_1": 0x46eaf, - "Hidden_Item_Viridian_Forest_2": 0x46eb5, - "Hidden_Item_MtMoonB2F_1": 0x46ebc, - "Hidden_Item_MtMoonB2F_2": 0x46ec2, - "Hidden_Item_Route_25_1": 0x46ed6, - "Hidden_Item_Route_25_2": 0x46edc, - "Hidden_Item_Route_9": 0x46ee3, - "Hidden_Item_SS_Anne_Kitchen": 0x46ef6, - "Hidden_Item_SS_Anne_B1F": 0x46efd, - "Hidden_Item_Route_10_1": 0x46f04, - "Hidden_Item_Route_10_2": 0x46f0a, - "Hidden_Item_Rocket_Hideout_B1F": 0x46f11, - "Hidden_Item_Rocket_Hideout_B3F": 0x46f18, - "Hidden_Item_Rocket_Hideout_B4F": 0x46f1f, - "Hidden_Item_Pokemon_Tower_5F": 0x46f33, - "Hidden_Item_Route_13_1": 0x46f3a, - "Hidden_Item_Route_13_2": 0x46f40, - "Hidden_Item_Safari_Zone_West": 0x46f4e, - "Hidden_Item_Silph_Co_5F": 0x46f55, - "Hidden_Item_Silph_Co_9F": 0x46f5c, - "Hidden_Item_Copycats_House": 0x46f63, - "Hidden_Item_Cerulean_Cave_1F": 0x46f6a, - "Hidden_Item_Cerulean_Cave_B1F": 0x46f71, - "Hidden_Item_Power_Plant_1": 0x46f78, - "Hidden_Item_Power_Plant_2": 0x46f7e, - "Hidden_Item_Seafoam_Islands_B2F": 0x46f85, - "Hidden_Item_Seafoam_Islands_B4F": 0x46f8c, - "Hidden_Item_Pokemon_Mansion_1F": 0x46f93, - "Hidden_Item_Pokemon_Mansion_3F": 0x46fa7, - "Hidden_Item_Pokemon_Mansion_B1F": 0x46fb4, - "Hidden_Item_Route_23_1": 0x46fc7, - "Hidden_Item_Route_23_2": 0x46fcd, - "Hidden_Item_Route_23_3": 0x46fd3, - "Hidden_Item_Victory_Road_2F_1": 0x46fda, - "Hidden_Item_Victory_Road_2F_2": 0x46fe0, - "Hidden_Item_Unused_6F": 0x46fe7, - "Hidden_Item_Viridian_City": 0x46ff5, - "Hidden_Item_Route_11": 0x470a2, - "Hidden_Item_Route_12": 0x470a9, - "Hidden_Item_Route_17_1": 0x470b7, - "Hidden_Item_Route_17_2": 0x470bd, - "Hidden_Item_Route_17_3": 0x470c3, - "Hidden_Item_Route_17_4": 0x470c9, - "Hidden_Item_Route_17_5": 0x470cf, - "Hidden_Item_Underground_Path_NS_1": 0x470d6, - "Hidden_Item_Underground_Path_NS_2": 0x470dc, - "Hidden_Item_Underground_Path_WE_1": 0x470e3, - "Hidden_Item_Underground_Path_WE_2": 0x470e9, - "Hidden_Item_Celadon_City": 0x470f0, - "Hidden_Item_Seafoam_Islands_B3F": 0x470f7, - "Hidden_Item_Vermilion_City": 0x470fe, - "Hidden_Item_Cerulean_City": 0x47105, - "Hidden_Item_Route_4": 0x4710c, + "Dexsanity_Items": 0x44254, + "Option_Dexsanity_A": 0x44301, + "Require_Pokedex_B": 0x44305, + "Option_Dexsanity_B": 0x44362, + "Trainersanity_EVENT_BEAT_MANSION_1_TRAINER_0_ITEM": 0x44540, + "Missable_Pokemon_Mansion_1F_Item_1": 0x445d7, + "Missable_Pokemon_Mansion_1F_Item_2": 0x445de, + "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_1_TRAINER_0_ITEM": 0x44713, + "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_1_TRAINER_1_ITEM": 0x44721, + "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_1_TRAINER_2_ITEM": 0x4472f, + "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_1_TRAINER_3_ITEM": 0x4473d, + "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_1_TRAINER_4_ITEM": 0x4474b, + "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_1_TRAINER_5_ITEM": 0x44759, + "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_1_TRAINER_6_ITEM": 0x44767, + "Map_Rock_Tunnel1F": 0x44884, + "Trainersanity_EVENT_BEAT_VICTORY_ROAD_3_TRAINER_0_ITEM": 0x44c54, + "Trainersanity_EVENT_BEAT_VICTORY_ROAD_3_TRAINER_1_ITEM": 0x44c62, + "Trainersanity_EVENT_BEAT_VICTORY_ROAD_3_TRAINER_2_ITEM": 0x44c70, + "Trainersanity_EVENT_BEAT_VICTORY_ROAD_3_TRAINER_3_ITEM": 0x44c7e, + "Missable_Victory_Road_3F_Item_1": 0x44d1e, + "Missable_Victory_Road_3F_Item_2": 0x44d25, + "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_1_TRAINER_0_ITEM": 0x44e46, + "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_1_TRAINER_1_ITEM": 0x44e54, + "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_1_TRAINER_2_ITEM": 0x44e62, + "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_1_TRAINER_3_ITEM": 0x44e70, + "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_1_TRAINER_4_ITEM": 0x44e7e, + "Missable_Rocket_Hideout_B1F_Item_1": 0x44f4e, + "Missable_Rocket_Hideout_B1F_Item_2": 0x44f55, + "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_2_TRAINER_0_ITEM": 0x452ff, + "Missable_Rocket_Hideout_B2F_Item_1": 0x45340, + "Missable_Rocket_Hideout_B2F_Item_2": 0x45347, + "Missable_Rocket_Hideout_B2F_Item_3": 0x4534e, + "Missable_Rocket_Hideout_B2F_Item_4": 0x45355, + "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_3_TRAINER_0_ITEM": 0x45532, + "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_3_TRAINER_1_ITEM": 0x45540, + "Missable_Rocket_Hideout_B3F_Item_1": 0x45596, + "Missable_Rocket_Hideout_B3F_Item_2": 0x4559d, + "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_4_TRAINER_0_ITEM": 0x45749, + "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_4_TRAINER_1_ITEM": 0x45757, + "Trainersanity_EVENT_BEAT_ROCKET_HIDEOUT_4_TRAINER_2_ITEM": 0x45765, + "Missable_Rocket_Hideout_B4F_Item_1": 0x45854, + "Missable_Rocket_Hideout_B4F_Item_2": 0x4585b, + "Missable_Rocket_Hideout_B4F_Item_3": 0x45862, + "Missable_Rocket_Hideout_B4F_Item_4": 0x45869, + "Missable_Rocket_Hideout_B4F_Item_5": 0x45870, + "Missable_Safari_Zone_East_Item_1": 0x45adf, + "Missable_Safari_Zone_East_Item_2": 0x45ae6, + "Missable_Safari_Zone_East_Item_3": 0x45aed, + "Missable_Safari_Zone_East_Item_4": 0x45af4, + "Missable_Safari_Zone_North_Item_1": 0x45c3f, + "Missable_Safari_Zone_North_Item_2": 0x45c46, + "Missable_Safari_Zone_Center_Item": 0x45e26, + "Missable_Cerulean_Cave_2F_Item_1": 0x46063, + "Missable_Cerulean_Cave_2F_Item_2": 0x4606a, + "Missable_Cerulean_Cave_2F_Item_3": 0x46071, + "Trainersanity_EVENT_BEAT_MEWTWO_ITEM": 0x46149, + "Static_Encounter_Mewtwo": 0x46173, + "Missable_Cerulean_Cave_B1F_Item_1": 0x4617b, + "Missable_Cerulean_Cave_B1F_Item_2": 0x46182, + "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_2_TRAINER_0_ITEM": 0x46258, + "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_2_TRAINER_1_ITEM": 0x46266, + "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_2_TRAINER_2_ITEM": 0x46274, + "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_2_TRAINER_3_ITEM": 0x46282, + "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_2_TRAINER_4_ITEM": 0x46290, + "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_2_TRAINER_5_ITEM": 0x4629e, + "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_2_TRAINER_6_ITEM": 0x462ac, + "Trainersanity_EVENT_BEAT_ROCK_TUNNEL_2_TRAINER_7_ITEM": 0x462ba, + "Missable_Rock_Tunnel_B1F_Item_1": 0x463de, + "Missable_Rock_Tunnel_B1F_Item_2": 0x463e5, + "Missable_Rock_Tunnel_B1F_Item_3": 0x463ec, + "Missable_Rock_Tunnel_B1F_Item_4": 0x463f3, + "Map_Rock_TunnelB1F": 0x46404, + "Trainersanity_EVENT_BEAT_ARTICUNO_ITEM": 0x46af6, + "Static_Encounter_Articuno": 0x46b4d, + "Hidden_Item_Game_Corner_1": 0x46fe5, + "Hidden_Item_Game_Corner_2": 0x46feb, + "Hidden_Item_Game_Corner_3": 0x46ff1, + "Hidden_Item_Game_Corner_4": 0x46ff7, + "Hidden_Item_Game_Corner_5": 0x46ffd, + "Hidden_Item_Game_Corner_6": 0x47003, + "Hidden_Item_Game_Corner_7": 0x47009, + "Hidden_Item_Game_Corner_8": 0x4700f, + "Hidden_Item_Game_Corner_9": 0x47015, + "Hidden_Item_Game_Corner_10": 0x4701b, + "Hidden_Item_Game_Corner_11": 0x47021, + "Quiz_Answer_A": 0x47055, + "Quiz_Answer_B": 0x4705b, + "Quiz_Answer_C": 0x47061, + "Quiz_Answer_D": 0x47067, + "Quiz_Answer_E": 0x4706d, + "Quiz_Answer_F": 0x47073, + "Hidden_Item_Viridian_Forest_1": 0x470a8, + "Hidden_Item_Viridian_Forest_2": 0x470ae, + "Hidden_Item_MtMoonB2F_1": 0x470b5, + "Hidden_Item_MtMoonB2F_2": 0x470bb, + "Hidden_Item_Route_25_1": 0x470cf, + "Hidden_Item_Route_25_2": 0x470d5, + "Hidden_Item_Route_9": 0x470dc, + "Hidden_Item_SS_Anne_Kitchen": 0x470ef, + "Hidden_Item_SS_Anne_B1F": 0x470f6, + "Hidden_Item_Route_10_1": 0x470fd, + "Hidden_Item_Route_10_2": 0x47103, + "Hidden_Item_Rocket_Hideout_B1F": 0x4710a, + "Hidden_Item_Rocket_Hideout_B3F": 0x47111, + "Hidden_Item_Rocket_Hideout_B4F": 0x47118, + "Hidden_Item_Pokemon_Tower_5F": 0x4712c, + "Hidden_Item_Route_13_1": 0x47133, + "Hidden_Item_Route_13_2": 0x47139, + "Hidden_Item_Safari_Zone_West": 0x47147, + "Hidden_Item_Silph_Co_5F": 0x4714e, + "Hidden_Item_Silph_Co_9F": 0x47155, + "Hidden_Item_Copycats_House": 0x4715c, + "Hidden_Item_Cerulean_Cave_1F": 0x47163, + "Hidden_Item_Cerulean_Cave_B1F": 0x4716a, + "Hidden_Item_Power_Plant_1": 0x47171, + "Hidden_Item_Power_Plant_2": 0x47177, + "Hidden_Item_Seafoam_Islands_B2F": 0x4717e, + "Hidden_Item_Seafoam_Islands_B4F": 0x47185, + "Hidden_Item_Pokemon_Mansion_1F": 0x4718c, + "Hidden_Item_Pokemon_Mansion_3F": 0x471a0, + "Hidden_Item_Pokemon_Mansion_B1F": 0x471ad, + "Hidden_Item_Route_23_1": 0x471c0, + "Hidden_Item_Route_23_2": 0x471c6, + "Hidden_Item_Route_23_3": 0x471cc, + "Hidden_Item_Victory_Road_2F_1": 0x471d3, + "Hidden_Item_Victory_Road_2F_2": 0x471d9, + "Hidden_Item_Unused_6F": 0x471e0, + "Hidden_Item_Viridian_City": 0x471ee, + "Hidden_Item_Route_11": 0x4729b, + "Hidden_Item_Route_12": 0x472a2, + "Hidden_Item_Route_17_1": 0x472b0, + "Hidden_Item_Route_17_2": 0x472b6, + "Hidden_Item_Route_17_3": 0x472bc, + "Hidden_Item_Route_17_4": 0x472c2, + "Hidden_Item_Route_17_5": 0x472c8, + "Hidden_Item_Underground_Path_NS_1": 0x472cf, + "Hidden_Item_Underground_Path_NS_2": 0x472d5, + "Hidden_Item_Underground_Path_WE_1": 0x472dc, + "Hidden_Item_Underground_Path_WE_2": 0x472e2, + "Hidden_Item_Celadon_City": 0x472e9, + "Hidden_Item_Seafoam_Islands_B3F": 0x472f0, + "Hidden_Item_Vermilion_City": 0x472f7, + "Hidden_Item_Cerulean_City": 0x472fe, + "Hidden_Item_Route_4": 0x47305, "Event_Counter": 0x482d3, - "Event_Thirsty_Girl_Lemonade": 0x484f9, - "Event_Thirsty_Girl_Soda": 0x4851d, - "Event_Thirsty_Girl_Water": 0x48541, - "Option_Tea": 0x4871d, - "Event_Mansion_Lady": 0x4872a, - "Badge_Celadon_Gym": 0x48a1b, - "Event_Celadon_Gym": 0x48a2f, - "Trainersanity_EVENT_BEAT_CELADON_GYM_TRAINER_0_ITEM": 0x48a75, - "Trainersanity_EVENT_BEAT_CELADON_GYM_TRAINER_1_ITEM": 0x48a83, - "Trainersanity_EVENT_BEAT_CELADON_GYM_TRAINER_2_ITEM": 0x48a91, - "Trainersanity_EVENT_BEAT_CELADON_GYM_TRAINER_3_ITEM": 0x48a9f, - "Trainersanity_EVENT_BEAT_CELADON_GYM_TRAINER_4_ITEM": 0x48aad, - "Trainersanity_EVENT_BEAT_CELADON_GYM_TRAINER_5_ITEM": 0x48abb, - "Trainersanity_EVENT_BEAT_CELADON_GYM_TRAINER_6_ITEM": 0x48ac9, - "Event_Gambling_Addict": 0x492a1, - "Gift_Magikarp": 0x4943e, - "Option_Aide_Rt11": 0x4959b, - "Event_Rt11_Oaks_Aide": 0x4959f, - "Event_Mourning_Girl": 0x49699, - "Option_Aide_Rt15": 0x49784, - "Event_Rt_15_Oaks_Aide": 0x49788, - "Trainersanity_EVENT_BEAT_MT_MOON_1_TRAINER_0_ITEM": 0x49b2e, - "Trainersanity_EVENT_BEAT_MT_MOON_1_TRAINER_1_ITEM": 0x49b3c, - "Trainersanity_EVENT_BEAT_MT_MOON_1_TRAINER_2_ITEM": 0x49b4a, - "Trainersanity_EVENT_BEAT_MT_MOON_1_TRAINER_3_ITEM": 0x49b58, - "Trainersanity_EVENT_BEAT_MT_MOON_1_TRAINER_4_ITEM": 0x49b66, - "Trainersanity_EVENT_BEAT_MT_MOON_1_TRAINER_5_ITEM": 0x49b74, - "Trainersanity_EVENT_BEAT_MT_MOON_1_TRAINER_6_ITEM": 0x49b82, - "Missable_Mt_Moon_1F_Item_1": 0x49c91, - "Missable_Mt_Moon_1F_Item_2": 0x49c98, - "Missable_Mt_Moon_1F_Item_3": 0x49c9f, - "Missable_Mt_Moon_1F_Item_4": 0x49ca6, - "Missable_Mt_Moon_1F_Item_5": 0x49cad, - "Missable_Mt_Moon_1F_Item_6": 0x49cb4, - "Trainersanity_EVENT_BEAT_MT_MOON_3_TRAINER_0_ITEM": 0x49f87, - "Trainersanity_EVENT_BEAT_MT_MOON_3_TRAINER_1_ITEM": 0x49f95, - "Trainersanity_EVENT_BEAT_MT_MOON_3_TRAINER_2_ITEM": 0x49fa3, - "Trainersanity_EVENT_BEAT_MT_MOON_3_TRAINER_3_ITEM": 0x49fb1, - "Dome_Fossil_Text": 0x4a025, - "Event_Dome_Fossil": 0x4a045, - "Helix_Fossil_Text": 0x4a081, - "Event_Helix_Fossil": 0x4a0a1, - "Missable_Mt_Moon_B2F_Item_1": 0x4a18a, - "Missable_Mt_Moon_B2F_Item_2": 0x4a191, - "Missable_Safari_Zone_West_Item_1": 0x4a373, - "Missable_Safari_Zone_West_Item_2": 0x4a37a, - "Missable_Safari_Zone_West_Item_3": 0x4a381, - "Missable_Safari_Zone_West_Item_4": 0x4a388, - "Event_Safari_Zone_Secret_House": 0x4a48d, + "Event_Thirsty_Girl_Lemonade": 0x48501, + "Event_Thirsty_Girl_Soda": 0x48525, + "Event_Thirsty_Girl_Water": 0x48549, + "Option_Tea": 0x48725, + "Event_Mansion_Lady": 0x48732, + "Badge_Celadon_Gym": 0x48a23, + "Event_Celadon_Gym": 0x48a37, + "Trainersanity_EVENT_BEAT_CELADON_GYM_TRAINER_0_ITEM": 0x48a7d, + "Trainersanity_EVENT_BEAT_CELADON_GYM_TRAINER_1_ITEM": 0x48a8b, + "Trainersanity_EVENT_BEAT_CELADON_GYM_TRAINER_2_ITEM": 0x48a99, + "Trainersanity_EVENT_BEAT_CELADON_GYM_TRAINER_3_ITEM": 0x48aa7, + "Trainersanity_EVENT_BEAT_CELADON_GYM_TRAINER_4_ITEM": 0x48ab5, + "Trainersanity_EVENT_BEAT_CELADON_GYM_TRAINER_5_ITEM": 0x48ac3, + "Trainersanity_EVENT_BEAT_CELADON_GYM_TRAINER_6_ITEM": 0x48ad1, + "Event_Game_Corner_Gift_A": 0x48e98, + "Event_Game_Corner_Gift_C": 0x48f14, + "Event_Game_Corner_Gift_B": 0x48f63, + "Event_Gambling_Addict": 0x49306, + "Gift_Magikarp": 0x494a3, + "Option_Aide_Rt11": 0x49600, + "Event_Rt11_Oaks_Aide": 0x49604, + "Event_Mourning_Girl": 0x496fe, + "Option_Aide_Rt15": 0x497e9, + "Event_Rt_15_Oaks_Aide": 0x497ed, + "Trainersanity_EVENT_BEAT_MT_MOON_1_TRAINER_0_ITEM": 0x49b93, + "Trainersanity_EVENT_BEAT_MT_MOON_1_TRAINER_1_ITEM": 0x49ba1, + "Trainersanity_EVENT_BEAT_MT_MOON_1_TRAINER_2_ITEM": 0x49baf, + "Trainersanity_EVENT_BEAT_MT_MOON_1_TRAINER_3_ITEM": 0x49bbd, + "Trainersanity_EVENT_BEAT_MT_MOON_1_TRAINER_4_ITEM": 0x49bcb, + "Trainersanity_EVENT_BEAT_MT_MOON_1_TRAINER_5_ITEM": 0x49bd9, + "Trainersanity_EVENT_BEAT_MT_MOON_1_TRAINER_6_ITEM": 0x49be7, + "Missable_Mt_Moon_1F_Item_1": 0x49cf6, + "Missable_Mt_Moon_1F_Item_2": 0x49cfd, + "Missable_Mt_Moon_1F_Item_3": 0x49d04, + "Missable_Mt_Moon_1F_Item_4": 0x49d0b, + "Missable_Mt_Moon_1F_Item_5": 0x49d12, + "Missable_Mt_Moon_1F_Item_6": 0x49d19, + "Trainersanity_EVENT_BEAT_MT_MOON_3_TRAINER_0_ITEM": 0x49fec, + "Trainersanity_EVENT_BEAT_MT_MOON_3_TRAINER_1_ITEM": 0x49ffa, + "Trainersanity_EVENT_BEAT_MT_MOON_3_TRAINER_2_ITEM": 0x4a008, + "Trainersanity_EVENT_BEAT_MT_MOON_3_TRAINER_3_ITEM": 0x4a016, + "Dome_Fossil_Text": 0x4a08a, + "Event_Dome_Fossil": 0x4a0aa, + "Helix_Fossil_Text": 0x4a0e6, + "Event_Helix_Fossil": 0x4a106, + "Missable_Mt_Moon_B2F_Item_1": 0x4a1ef, + "Missable_Mt_Moon_B2F_Item_2": 0x4a1f6, + "Missable_Safari_Zone_West_Item_1": 0x4a3d8, + "Missable_Safari_Zone_West_Item_2": 0x4a3df, + "Missable_Safari_Zone_West_Item_3": 0x4a3e6, + "Missable_Safari_Zone_West_Item_4": 0x4a3ed, + "Event_Safari_Zone_Secret_House": 0x4a4f2, "Missable_Route_24_Item": 0x506e6, "Missable_Route_25_Item": 0x5080b, "Trainersanity_EVENT_BEAT_ROUTE_20_TRAINER_0_ITEM": 0x50d47, @@ -606,13 +634,16 @@ rom_addresses = { "Prize_Mon_D2": 0x5288a, "Prize_Mon_E2": 0x5288b, "Prize_Mon_F2": 0x5288c, - "Prize_Mon_A": 0x529b0, - "Prize_Mon_B": 0x529b2, - "Prize_Mon_C": 0x529b4, - "Prize_Mon_D": 0x529b6, - "Prize_Mon_E": 0x529b8, - "Prize_Mon_F": 0x529ba, - "Start_Inventory": 0x52add, + "Prize_Item_A": 0x52895, + "Prize_Item_B": 0x52896, + "Prize_Item_C": 0x52897, + "Prize_Mon_A": 0x529cc, + "Prize_Mon_B": 0x529ce, + "Prize_Mon_C": 0x529d0, + "Prize_Mon_D": 0x529d2, + "Prize_Mon_E": 0x529d4, + "Prize_Mon_F": 0x529d6, + "Start_Inventory": 0x52af9, "Missable_Route_2_Item_1": 0x5404a, "Missable_Route_2_Item_2": 0x54051, "Missable_Route_4_Item": 0x543df, @@ -696,81 +727,82 @@ rom_addresses = { "Missable_Route_12_Item_2": 0x5870b, "Missable_Route_15_Item": 0x589c7, "Ghost_Battle6": 0x58df0, - "Trainersanity_EVENT_BEAT_ROUTE_6_TRAINER_0_ITEM": 0x59106, - "Trainersanity_EVENT_BEAT_ROUTE_6_TRAINER_1_ITEM": 0x59114, - "Trainersanity_EVENT_BEAT_ROUTE_6_TRAINER_2_ITEM": 0x59122, - "Trainersanity_EVENT_BEAT_ROUTE_6_TRAINER_3_ITEM": 0x59130, - "Trainersanity_EVENT_BEAT_ROUTE_6_TRAINER_4_ITEM": 0x5913e, - "Trainersanity_EVENT_BEAT_ROUTE_6_TRAINER_5_ITEM": 0x5914c, - "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_0_ITEM": 0x5921e, - "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_1_ITEM": 0x5922c, - "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_2_ITEM": 0x5923a, - "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_3_ITEM": 0x59248, - "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_4_ITEM": 0x59256, - "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_5_ITEM": 0x59264, - "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_6_ITEM": 0x59272, - "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_7_ITEM": 0x59280, - "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_8_ITEM": 0x5928e, - "Trainersanity_EVENT_BEAT_ROUTE_10_TRAINER_0_ITEM": 0x59406, - "Trainersanity_EVENT_BEAT_ROUTE_10_TRAINER_1_ITEM": 0x59414, - "Trainersanity_EVENT_BEAT_ROUTE_10_TRAINER_2_ITEM": 0x59422, - "Trainersanity_EVENT_BEAT_ROUTE_10_TRAINER_3_ITEM": 0x59430, - "Trainersanity_EVENT_BEAT_ROUTE_10_TRAINER_4_ITEM": 0x5943e, - "Trainersanity_EVENT_BEAT_ROUTE_10_TRAINER_5_ITEM": 0x5944c, - "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_0_ITEM": 0x59533, - "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_1_ITEM": 0x59541, - "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_2_ITEM": 0x5954f, - "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_3_ITEM": 0x5955d, - "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_4_ITEM": 0x5956b, - "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_5_ITEM": 0x59579, - "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_6_ITEM": 0x59587, - "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_7_ITEM": 0x59595, - "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_8_ITEM": 0x595a3, - "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_9_ITEM": 0x595b1, - "Static_Encounter_Snorlax_A": 0x596ef, - "Trainersanity_EVENT_BEAT_ROUTE_12_TRAINER_0_ITEM": 0x5975d, - "Trainersanity_EVENT_BEAT_ROUTE_12_TRAINER_1_ITEM": 0x5976b, - "Trainersanity_EVENT_BEAT_ROUTE_12_TRAINER_2_ITEM": 0x59779, - "Trainersanity_EVENT_BEAT_ROUTE_12_TRAINER_3_ITEM": 0x59787, - "Trainersanity_EVENT_BEAT_ROUTE_12_TRAINER_4_ITEM": 0x59795, - "Trainersanity_EVENT_BEAT_ROUTE_12_TRAINER_5_ITEM": 0x597a3, - "Trainersanity_EVENT_BEAT_ROUTE_12_TRAINER_6_ITEM": 0x597b1, - "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_0_ITEM": 0x598b9, - "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_1_ITEM": 0x598c7, - "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_2_ITEM": 0x598d5, - "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_3_ITEM": 0x598e3, - "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_4_ITEM": 0x598f1, - "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_5_ITEM": 0x598ff, - "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_6_ITEM": 0x5990d, - "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_7_ITEM": 0x5991b, - "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_8_ITEM": 0x59929, - "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_9_ITEM": 0x59937, - "Static_Encounter_Snorlax_B": 0x59a51, - "Trainersanity_EVENT_BEAT_ROUTE_16_TRAINER_0_ITEM": 0x59abd, - "Trainersanity_EVENT_BEAT_ROUTE_16_TRAINER_1_ITEM": 0x59acb, - "Trainersanity_EVENT_BEAT_ROUTE_16_TRAINER_2_ITEM": 0x59ad9, - "Trainersanity_EVENT_BEAT_ROUTE_16_TRAINER_3_ITEM": 0x59ae7, - "Trainersanity_EVENT_BEAT_ROUTE_16_TRAINER_4_ITEM": 0x59af5, - "Trainersanity_EVENT_BEAT_ROUTE_16_TRAINER_5_ITEM": 0x59b03, - "Trainersanity_EVENT_BEAT_ROUTE_18_TRAINER_0_ITEM": 0x59be4, - "Trainersanity_EVENT_BEAT_ROUTE_18_TRAINER_1_ITEM": 0x59bf2, - "Trainersanity_EVENT_BEAT_ROUTE_18_TRAINER_2_ITEM": 0x59c00, - "Event_Pokemon_Fan_Club": 0x59d13, - "Trainersanity_EVENT_BEAT_SILPH_CO_2F_TRAINER_0_ITEM": 0x59e73, - "Trainersanity_EVENT_BEAT_SILPH_CO_2F_TRAINER_1_ITEM": 0x59e81, - "Trainersanity_EVENT_BEAT_SILPH_CO_2F_TRAINER_2_ITEM": 0x59e8f, - "Trainersanity_EVENT_BEAT_SILPH_CO_2F_TRAINER_3_ITEM": 0x59e9d, - "Event_Scared_Woman": 0x59eaf, - "Trainersanity_EVENT_BEAT_SILPH_CO_3F_TRAINER_0_ITEM": 0x5a0b7, - "Trainersanity_EVENT_BEAT_SILPH_CO_3F_TRAINER_1_ITEM": 0x5a0c5, - "Missable_Silph_Co_3F_Item": 0x5a15f, - "Trainersanity_EVENT_BEAT_SILPH_CO_10F_TRAINER_0_ITEM": 0x5a281, - "Trainersanity_EVENT_BEAT_SILPH_CO_10F_TRAINER_1_ITEM": 0x5a28f, - "Missable_Silph_Co_10F_Item_1": 0x5a319, - "Missable_Silph_Co_10F_Item_2": 0x5a320, - "Missable_Silph_Co_10F_Item_3": 0x5a327, - "Trainersanity_EVENT_BEAT_LANCES_ROOM_TRAINER_0_ITEM": 0x5a48a, - "Guard_Drink_List": 0x5a69f, + "Require_Pokedex_A": 0x59051, + "Trainersanity_EVENT_BEAT_ROUTE_6_TRAINER_0_ITEM": 0x5910b, + "Trainersanity_EVENT_BEAT_ROUTE_6_TRAINER_1_ITEM": 0x59119, + "Trainersanity_EVENT_BEAT_ROUTE_6_TRAINER_2_ITEM": 0x59127, + "Trainersanity_EVENT_BEAT_ROUTE_6_TRAINER_3_ITEM": 0x59135, + "Trainersanity_EVENT_BEAT_ROUTE_6_TRAINER_4_ITEM": 0x59143, + "Trainersanity_EVENT_BEAT_ROUTE_6_TRAINER_5_ITEM": 0x59151, + "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_0_ITEM": 0x59223, + "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_1_ITEM": 0x59231, + "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_2_ITEM": 0x5923f, + "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_3_ITEM": 0x5924d, + "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_4_ITEM": 0x5925b, + "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_5_ITEM": 0x59269, + "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_6_ITEM": 0x59277, + "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_7_ITEM": 0x59285, + "Trainersanity_EVENT_BEAT_ROUTE_8_TRAINER_8_ITEM": 0x59293, + "Trainersanity_EVENT_BEAT_ROUTE_10_TRAINER_0_ITEM": 0x5940d, + "Trainersanity_EVENT_BEAT_ROUTE_10_TRAINER_1_ITEM": 0x5941b, + "Trainersanity_EVENT_BEAT_ROUTE_10_TRAINER_2_ITEM": 0x59429, + "Trainersanity_EVENT_BEAT_ROUTE_10_TRAINER_3_ITEM": 0x59437, + "Trainersanity_EVENT_BEAT_ROUTE_10_TRAINER_4_ITEM": 0x59445, + "Trainersanity_EVENT_BEAT_ROUTE_10_TRAINER_5_ITEM": 0x59453, + "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_0_ITEM": 0x5953a, + "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_1_ITEM": 0x59548, + "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_2_ITEM": 0x59556, + "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_3_ITEM": 0x59564, + "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_4_ITEM": 0x59572, + "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_5_ITEM": 0x59580, + "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_6_ITEM": 0x5958e, + "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_7_ITEM": 0x5959c, + "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_8_ITEM": 0x595aa, + "Trainersanity_EVENT_BEAT_ROUTE_11_TRAINER_9_ITEM": 0x595b8, + "Static_Encounter_Snorlax_A": 0x596f6, + "Trainersanity_EVENT_BEAT_ROUTE_12_TRAINER_0_ITEM": 0x59764, + "Trainersanity_EVENT_BEAT_ROUTE_12_TRAINER_1_ITEM": 0x59772, + "Trainersanity_EVENT_BEAT_ROUTE_12_TRAINER_2_ITEM": 0x59780, + "Trainersanity_EVENT_BEAT_ROUTE_12_TRAINER_3_ITEM": 0x5978e, + "Trainersanity_EVENT_BEAT_ROUTE_12_TRAINER_4_ITEM": 0x5979c, + "Trainersanity_EVENT_BEAT_ROUTE_12_TRAINER_5_ITEM": 0x597aa, + "Trainersanity_EVENT_BEAT_ROUTE_12_TRAINER_6_ITEM": 0x597b8, + "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_0_ITEM": 0x598c0, + "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_1_ITEM": 0x598ce, + "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_2_ITEM": 0x598dc, + "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_3_ITEM": 0x598ea, + "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_4_ITEM": 0x598f8, + "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_5_ITEM": 0x59906, + "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_6_ITEM": 0x59914, + "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_7_ITEM": 0x59922, + "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_8_ITEM": 0x59930, + "Trainersanity_EVENT_BEAT_ROUTE_15_TRAINER_9_ITEM": 0x5993e, + "Static_Encounter_Snorlax_B": 0x59a58, + "Trainersanity_EVENT_BEAT_ROUTE_16_TRAINER_0_ITEM": 0x59ac4, + "Trainersanity_EVENT_BEAT_ROUTE_16_TRAINER_1_ITEM": 0x59ad2, + "Trainersanity_EVENT_BEAT_ROUTE_16_TRAINER_2_ITEM": 0x59ae0, + "Trainersanity_EVENT_BEAT_ROUTE_16_TRAINER_3_ITEM": 0x59aee, + "Trainersanity_EVENT_BEAT_ROUTE_16_TRAINER_4_ITEM": 0x59afc, + "Trainersanity_EVENT_BEAT_ROUTE_16_TRAINER_5_ITEM": 0x59b0a, + "Trainersanity_EVENT_BEAT_ROUTE_18_TRAINER_0_ITEM": 0x59beb, + "Trainersanity_EVENT_BEAT_ROUTE_18_TRAINER_1_ITEM": 0x59bf9, + "Trainersanity_EVENT_BEAT_ROUTE_18_TRAINER_2_ITEM": 0x59c07, + "Event_Pokemon_Fan_Club": 0x59d1a, + "Trainersanity_EVENT_BEAT_SILPH_CO_2F_TRAINER_0_ITEM": 0x59e7a, + "Trainersanity_EVENT_BEAT_SILPH_CO_2F_TRAINER_1_ITEM": 0x59e88, + "Trainersanity_EVENT_BEAT_SILPH_CO_2F_TRAINER_2_ITEM": 0x59e96, + "Trainersanity_EVENT_BEAT_SILPH_CO_2F_TRAINER_3_ITEM": 0x59ea4, + "Event_Scared_Woman": 0x59eb6, + "Trainersanity_EVENT_BEAT_SILPH_CO_3F_TRAINER_0_ITEM": 0x5a0be, + "Trainersanity_EVENT_BEAT_SILPH_CO_3F_TRAINER_1_ITEM": 0x5a0cc, + "Missable_Silph_Co_3F_Item": 0x5a166, + "Trainersanity_EVENT_BEAT_SILPH_CO_10F_TRAINER_0_ITEM": 0x5a288, + "Trainersanity_EVENT_BEAT_SILPH_CO_10F_TRAINER_1_ITEM": 0x5a296, + "Missable_Silph_Co_10F_Item_1": 0x5a320, + "Missable_Silph_Co_10F_Item_2": 0x5a327, + "Missable_Silph_Co_10F_Item_3": 0x5a32e, + "Trainersanity_EVENT_BEAT_LANCES_ROOM_TRAINER_0_ITEM": 0x5a491, + "Guard_Drink_List": 0x5a6a6, "Event_Museum": 0x5c266, "Badge_Pewter_Gym": 0x5c3ed, "Event_Pewter_Gym": 0x5c401, @@ -879,6 +911,16 @@ rom_addresses = { "Trainersanity_EVENT_BEAT_SILPH_CO_11F_TRAINER_1_ITEM": 0x6234a, "Event_Silph_Co_President": 0x6235d, "Ghost_Battle4": 0x708e1, + "Trade_Terry": 0x71b7b, + "Trade_Marcel": 0x71b89, + "Trade_Sailor": 0x71ba5, + "Trade_Dux": 0x71bb3, + "Trade_Marc": 0x71bc1, + "Trade_Lola": 0x71bcf, + "Trade_Doris": 0x71bdd, + "Trade_Crinkles": 0x71beb, + "Trade_Spot": 0x71bf9, + "Mon_Palettes": 0x725dd, "Badge_Viridian_Gym": 0x749f7, "Event_Viridian_Gym": 0x74a0b, "Trainersanity_EVENT_BEAT_VIRIDIAN_GYM_TRAINER_0_ITEM": 0x74a66, @@ -906,18 +948,39 @@ rom_addresses = { "Trainersanity_EVENT_BEAT_FUCHSIA_GYM_TRAINER_5_ITEM": 0x756d2, "Badge_Cinnabar_Gym": 0x75a06, "Event_Cinnabar_Gym": 0x75a1a, - "Event_Lab_Scientist": 0x75e43, - "Fossils_Needed_For_Second_Item": 0x75f10, - "Event_Dome_Fossil_B": 0x75f8d, - "Event_Helix_Fossil_B": 0x75fad, - "Shop8": 0x760cb, - "Starter2_N": 0x761fe, - "Starter3_N": 0x76206, - "Trainersanity_EVENT_BEAT_LORELEIS_ROOM_TRAINER_0_ITEM": 0x764ce, - "Trainersanity_EVENT_BEAT_BRUNOS_ROOM_TRAINER_0_ITEM": 0x76627, - "Trainersanity_EVENT_BEAT_AGATHAS_ROOM_TRAINER_0_ITEM": 0x76786, - "Option_Itemfinder": 0x768ff, - "Text_Magikarp_Salesman": 0x8a7fe, + "Option_Trainersanity4": 0x75af6, + "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_B_ITEM": 0x75b02, + "Option_Trainersanity3": 0x75b46, + "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_A_ITEM": 0x75b52, + "Option_Trainersanity5": 0x75bad, + "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_2_ITEM": 0x75bb9, + "Option_Trainersanity6": 0x75bfd, + "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_3_ITEM": 0x75c09, + "Option_Trainersanity7": 0x75c4d, + "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_4_ITEM": 0x75c59, + "Option_Trainersanity8": 0x75c9d, + "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_5_ITEM": 0x75ca9, + "Option_Trainersanity9": 0x75ced, + "Trainersanity_EVENT_BEAT_CINNABAR_GYM_TRAINER_6_ITEM": 0x75cf9, + "Event_Lab_Scientist": 0x75f17, + "Fossils_Needed_For_Second_Item": 0x75fe4, + "Event_Dome_Fossil_B": 0x76061, + "Event_Helix_Fossil_B": 0x76081, + "Shop8": 0x7619f, + "Starter2_N": 0x762d2, + "Starter3_N": 0x762da, + "Trainersanity_EVENT_BEAT_LORELEIS_ROOM_TRAINER_0_ITEM": 0x7663d, + "Trainersanity_EVENT_BEAT_BRUNOS_ROOM_TRAINER_0_ITEM": 0x76796, + "Trainersanity_EVENT_BEAT_AGATHAS_ROOM_TRAINER_0_ITEM": 0x768f5, + "Option_Itemfinder": 0x76a6e, + "Text_Quiz_A": 0x88806, + "Text_Quiz_B": 0x8893a, + "Text_Quiz_C": 0x88a6e, + "Text_Quiz_D": 0x88ba2, + "Text_Quiz_E": 0x88cd6, + "Text_Quiz_F": 0x88e0a, + "Text_Magikarp_Salesman": 0x8ae3f, + "Text_Rock_Tunnel_Sign": 0x8e82a, "Text_Badges_Needed": 0x92304, "Badge_Text_Boulder_Badge": 0x99010, "Badge_Text_Cascade_Badge": 0x99028, diff --git a/worlds/pokemon_rb/rules.py b/worlds/pokemon_rb/rules.py index 493a58e5..5d117dc5 100644 --- a/worlds/pokemon_rb/rules.py +++ b/worlds/pokemon_rb/rules.py @@ -1,26 +1,45 @@ -from ..generic.Rules import add_item_rule, add_rule +from ..generic.Rules import add_item_rule, add_rule, item_name +from .items import item_groups + def set_rules(world, player): - add_item_rule(world.get_location("Pallet Town - Player's PC", player), - lambda i: i.player == player and "Badge" not in i.name and "Trap" not in i.name and - i.name != "Pokedex") + item_rules = { + "Pallet Town - Player's PC": (lambda i: i.player == player and "Badge" not in i.name and "Trap" not in i.name + and i.name != "Pokedex" and "Coins" not in i.name) + } + + if world.prizesanity[player]: + 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 world.accessibility[player] != "locations": + world.get_location("Cerulean City - Bicycle Shop", player).always_allow = (lambda state, item: + item.name == "Bike Voucher" + and item.player == player) + world.get_location("Fuchsia City - Safari Zone Warden", player).always_allow = (lambda state, item: + item.name == "Gold Teeth" and + item.player == player) access_rules = { - "Pallet Town - Rival's Sister": lambda state: state.has("Oak's Parcel", player), "Pallet Town - Oak's Post-Route-22-Rival Gift": lambda state: state.has("Oak's Parcel", player), "Viridian City - Sleepy Guy": lambda state: state.pokemon_rb_can_cut(player) or state.pokemon_rb_can_surf(player), "Route 2 - Oak's Aide": lambda state: state.pokemon_rb_oaks_aide(state.multiworld.oaks_aide_rt_2[player].value + 5, player), "Pewter City - Museum": lambda state: state.pokemon_rb_can_cut(player), - "Cerulean City - Bicycle Shop": lambda state: state.has("Bike Voucher", player), + "Cerulean City - Bicycle Shop": lambda state: state.has("Bike Voucher", player) + or item_name(state, "Cerulean City - Bicycle Shop", player) == ("Bike Voucher", player), "Lavender Town - Mr. Fuji": lambda state: state.has("Fuji Saved", player), "Vermilion Gym - Lt. Surge 1": lambda state: state.pokemon_rb_can_cut(player or state.pokemon_rb_can_surf(player)), "Vermilion Gym - Lt. Surge 2": lambda state: state.pokemon_rb_can_cut(player or state.pokemon_rb_can_surf(player)), "Route 11 - Oak's Aide": lambda state: state.pokemon_rb_oaks_aide(state.multiworld.oaks_aide_rt_11[player].value + 5, player), "Celadon City - Stranded Man": lambda state: state.pokemon_rb_can_surf(player), - "Silph Co 11F - Silph Co President": lambda state: state.has("Card Key", player), - "Fuchsia City - Safari Zone Warden": lambda state: state.has("Gold Teeth", player), + "Silph Co 11F - Silph Co President (Card Key)": lambda state: state.has("Card Key", player), + "Fuchsia City - Safari Zone Warden": lambda state: state.has("Gold Teeth", player) + or item_name(state, "Fuchsia City - Safari Zone Warden", player) == ("Gold Teeth", player), "Route 12 - Island Item": lambda state: state.pokemon_rb_can_surf(player), "Route 12 - Item Behind Cuttable Tree": lambda state: state.pokemon_rb_can_cut(player), "Route 15 - Oak's Aide": lambda state: state.pokemon_rb_oaks_aide(state.multiworld.oaks_aide_rt_15[player].value + 5, player), @@ -38,6 +57,23 @@ def set_rules(world, player): "Silph Co 6F - Southwest Item (Card Key)": lambda state: state.has("Card Key", player), "Silph Co 7F - East Item (Card Key)": lambda state: state.has("Card Key", player), "Safari Zone Center - Island Item": lambda state: state.pokemon_rb_can_surf(player), + "Celadon Prize Corner - Item Prize 1": lambda state: state.has("Coin Case", player), + "Celadon Prize Corner - Item Prize 2": lambda state: state.has("Coin Case", player), + "Celadon Prize Corner - Item Prize 3": lambda state: state.has("Coin Case", player), + "Celadon Game Corner - West Gambler's Gift (Coin Case)": lambda state: state.has("Coin Case", player), + "Celadon Game Corner - Center Gambler's Gift (Coin Case)": lambda state: state.has("Coin Case", player), + "Celadon Game Corner - East Gambler's Gift (Coin Case)": lambda state: state.has("Coin Case", player), + "Celadon Game Corner - Hidden Item Northwest By Counter (Coin Case)": lambda state: state.has("Coin Case", player), + "Celadon Game Corner - Hidden Item Southwest Corner (Coin Case)": lambda state: state.has("Coin Case", player), + "Celadon Game Corner - Hidden Item Near Rumor Man (Coin Case)": lambda state: state.has("Coin Case", player), + "Celadon Game Corner - Hidden Item Near Speculating Woman (Coin Case)": lambda state: state.has("Coin Case", player), + "Celadon Game Corner - Hidden Item Near West Gifting Gambler (Coin Case)": lambda state: state.has("Coin Case", player), + "Celadon Game Corner - Hidden Item Near Wonderful Time Woman (Coin Case)": lambda state: state.has("Coin Case", player), + "Celadon Game Corner - Hidden Item Near Failing Gym Information Guy (Coin Case)": lambda state: state.has( "Coin Case", player), + "Celadon Game Corner - Hidden Item Near East Gifting Gambler (Coin Case)": lambda state: state.has("Coin Case", player), + "Celadon Game Corner - Hidden Item Near Hooked Guy (Coin Case)": lambda state: state.has("Coin Case", player), + "Celadon Game Corner - Hidden Item at End of Horizontal Machine Row (Coin Case)": lambda state: state.has("Coin Case", player), + "Celadon Game Corner - Hidden Item in Front of Horizontal Machine Row (Coin Case)": lambda state: state.has("Coin Case", player), "Silph Co 11F - Silph Co Liberated": lambda state: state.has("Card Key", player), @@ -89,6 +125,16 @@ def set_rules(world, player): "Seafoam Islands B4F - Legendary Pokemon": lambda state: state.pokemon_rb_can_strength(player), "Vermilion City - Legendary Pokemon": lambda state: state.pokemon_rb_can_surf(player) and state.has("S.S. Ticket", player), + "Route 2 - Marcel Trade": lambda state: state.can_reach("Route 24 - Wild Pokemon - 6", "Location", player), + "Underground Tunnel West-East - Spot Trade": lambda state: state.can_reach("Route 24 - Wild Pokemon - 6", "Location", player), + "Route 11 - Terry Trade": lambda state: state.can_reach("Safari Zone Center - Wild Pokemon - 5", "Location", player), + "Route 18 - Marc Trade": lambda state: state.can_reach("Route 23 - Super Rod Pokemon - 1", "Location", player), + "Cinnabar Island - Sailor Trade": lambda state: state.can_reach("Pokemon Mansion 1F - Wild Pokemon - 3", "Location", player), + "Cinnabar Island - Crinkles Trade": lambda state: state.can_reach("Route 12 - Wild Pokemon - 4", "Location", player), + "Cinnabar Island - Doris Trade": lambda state: state.can_reach("Cerulean Cave 1F - Wild Pokemon - 9", "Location", player), + "Vermilion City - Dux Trade": lambda state: state.can_reach("Route 3 - Wild Pokemon - 2", "Location", player), + "Cerulean City - Lola Trade": lambda state: state.can_reach("Route 10 - Super Rod Pokemon - 1", "Location", player), + # Pokédex check "Pallet Town - Oak's Parcel Reward": lambda state: state.has("Oak's Parcel", player), @@ -142,7 +188,7 @@ def set_rules(world, player): "Pokemon Mansion 1F - Hidden Item Block Near Entrance Carpet": lambda state: state.pokemon_rb_can_get_hidden_items(player), "Pokemon Mansion 3F - Hidden Item Behind Burglar": lambda state: state.pokemon_rb_can_get_hidden_items(player), - "Route 23 - Hidden Item Rocks Before Final Guard": lambda state: state.pokemon_rb_can_get_hidden_items( + "Route 23 - Hidden Item Rocks Before Victory Road": lambda state: state.pokemon_rb_can_get_hidden_items( player), "Route 23 - Hidden Item East Bush After Water": lambda state: state.pokemon_rb_can_get_hidden_items( player), @@ -178,3 +224,11 @@ def set_rules(world, player): for loc in world.get_locations(player): if loc.name in access_rules: add_rule(loc, access_rules[loc.name]) + if loc.name in item_rules: + add_item_rule(loc, item_rules[loc.name]) + 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))) + diff --git a/worlds/pokemon_rb/text.py b/worlds/pokemon_rb/text.py index e15623d4..feb54e65 100644 --- a/worlds/pokemon_rb/text.py +++ b/worlds/pokemon_rb/text.py @@ -1,5 +1,9 @@ special_chars = { "PKMN": 0x4A, + "LINE": 0x4F, + "CONT": 0x55, + "DONE": 0x57, + "PROMPT": 0x58, "'d": 0xBB, "'l": 0xBC, "'t": 0xBE, @@ -105,7 +109,7 @@ char_map = { "9": 0xFF, } -unsafe_chars = ["@", "#", "PKMN"] +unsafe_chars = ["@", "#", "PKMN", "LINE", "DONE", "CONT", "PROMPT"] def encode_text(text: str, length: int=0, whitespace=False, force=False, safety=False): diff --git a/worlds/smz3/__init__.py b/worlds/smz3/__init__.py index 93ac7fbd..5e73f5db 100644 --- a/worlds/smz3/__init__.py +++ b/worlds/smz3/__init__.py @@ -509,7 +509,7 @@ class SMZ3World(World): return self.smz3DungeonItems else: return [] - + def post_fill(self): # some small or big keys (those always_allow) can be unreachable in-game # while logic still collects some of them (probably to simulate the player collecting pot keys in the logic), some others don't @@ -524,7 +524,7 @@ class SMZ3World(World): loc.item.classification = ItemClassification.filler loc.item.item.Progression = False loc.item.location.event = False - self.unreachable.append(loc) + self.unreachable.append(loc) def get_filler_item_name(self) -> str: return self.multiworld.random.choice(self.junkItemsNames)