From 30a4bcbbbe83a6febe72765814e7d59cbece7f57 Mon Sep 17 00:00:00 2001 From: Alchav <59858495+Alchav@users.noreply.github.com> Date: Thu, 13 Oct 2022 01:45:52 -0400 Subject: [PATCH] [Pokemon Red and Blue] Initial implementation (#1016) --- .gitignore | 3 + Launcher.py | 2 + PokemonClient.py | 319 +++ README.md | 1 + Utils.py | 5 + data/lua/PKMN_RB/core.dll | Bin 0 -> 29184 bytes data/lua/PKMN_RB/json.lua | 389 ++++ data/lua/PKMN_RB/pkmn_rb.lua | 238 +++ data/lua/PKMN_RB/socket.lua | 132 ++ host.yaml | 8 + inno_setup.iss | 87 +- worlds/Files.py | 2 +- worlds/pokemon_rb/LICENSE | 21 + worlds/pokemon_rb/__init__.py | 254 +++ worlds/pokemon_rb/basepatch_blue.bsdiff4 | Bin 0 -> 29178 bytes worlds/pokemon_rb/basepatch_red.bsdiff4 | Bin 0 -> 29339 bytes .../docs/en_Pokemon Red and Blue.md | 55 + worlds/pokemon_rb/docs/setup_en.md | 84 + worlds/pokemon_rb/items.py | 176 ++ worlds/pokemon_rb/locations.py | 1719 +++++++++++++++++ worlds/pokemon_rb/logic.py | 73 + worlds/pokemon_rb/options.py | 481 +++++ worlds/pokemon_rb/poke_data.py | 1212 ++++++++++++ worlds/pokemon_rb/regions.py | 305 +++ worlds/pokemon_rb/rom.py | 614 ++++++ worlds/pokemon_rb/rom_addresses.py | 588 ++++++ worlds/pokemon_rb/rules.py | 165 ++ worlds/pokemon_rb/text.py | 147 ++ 28 files changed, 7078 insertions(+), 2 deletions(-) create mode 100644 PokemonClient.py create mode 100644 data/lua/PKMN_RB/core.dll create mode 100644 data/lua/PKMN_RB/json.lua create mode 100644 data/lua/PKMN_RB/pkmn_rb.lua create mode 100644 data/lua/PKMN_RB/socket.lua create mode 100644 worlds/pokemon_rb/LICENSE create mode 100644 worlds/pokemon_rb/__init__.py create mode 100644 worlds/pokemon_rb/basepatch_blue.bsdiff4 create mode 100644 worlds/pokemon_rb/basepatch_red.bsdiff4 create mode 100644 worlds/pokemon_rb/docs/en_Pokemon Red and Blue.md create mode 100644 worlds/pokemon_rb/docs/setup_en.md create mode 100644 worlds/pokemon_rb/items.py create mode 100644 worlds/pokemon_rb/locations.py create mode 100644 worlds/pokemon_rb/logic.py create mode 100644 worlds/pokemon_rb/options.py create mode 100644 worlds/pokemon_rb/poke_data.py create mode 100644 worlds/pokemon_rb/regions.py create mode 100644 worlds/pokemon_rb/rom.py create mode 100644 worlds/pokemon_rb/rom_addresses.py create mode 100644 worlds/pokemon_rb/rules.py create mode 100644 worlds/pokemon_rb/text.py diff --git a/.gitignore b/.gitignore index 8a724621..925a4bd0 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,9 @@ *.z64 *.n64 *.nes +*.gb +*.gbc +*.gba *.wixobj *.lck *.db3 diff --git a/Launcher.py b/Launcher.py index 9f9aaa4f..c24e0c81 100644 --- a/Launcher.py +++ b/Launcher.py @@ -145,6 +145,8 @@ components: Iterable[Component] = ( Component('OoT Adjuster', 'OoTAdjuster'), # FF1 Component('FF1 Client', 'FF1Client'), + # Pokémon + Component('Pokemon Client', 'PokemonClient', file_identifier=SuffixIdentifier('.apred', '.apblue')), # ChecksFinder Component('ChecksFinder Client', 'ChecksFinderClient'), # Starcraft 2 diff --git a/PokemonClient.py b/PokemonClient.py new file mode 100644 index 00000000..2328243d --- /dev/null +++ b/PokemonClient.py @@ -0,0 +1,319 @@ +import asyncio +import json +import time +import os +import bsdiff4 +import subprocess +import zipfile +import hashlib +from asyncio import StreamReader, StreamWriter +from typing import List + + +import Utils +from CommonClient import CommonContext, server_loop, gui_enabled, ClientCommandProcessor, logger, \ + get_base_parser + +from worlds.pokemon_rb.locations import location_data + +location_map = {"Rod": {}, "EventFlag": {}, "Missable": {}, "Hidden": {}, "list": {}} +location_bytes_bits = {} +for location in location_data: + if location.ram_address is not None: + if type(location.ram_address) == list: + location_map[type(location.ram_address).__name__][(location.ram_address[0].flag, location.ram_address[1].flag)] = location.address + location_bytes_bits[location.address] = [{'byte': location.ram_address[0].byte, 'bit': location.ram_address[0].bit}, + {'byte': location.ram_address[1].byte, 'bit': location.ram_address[1].bit}] + else: + location_map[type(location.ram_address).__name__][location.ram_address.flag] = location.address + location_bytes_bits[location.address] = {'byte': location.ram_address.byte, 'bit': location.ram_address.bit} + +SYSTEM_MESSAGE_ID = 0 + +CONNECTION_TIMING_OUT_STATUS = "Connection timing out. Please restart your emulator, then restart pkmn_rb.lua" +CONNECTION_REFUSED_STATUS = "Connection Refused. Please start your emulator and make sure pkmn_rb.lua is running" +CONNECTION_RESET_STATUS = "Connection was reset. Please restart your emulator, then restart pkmn_rb.lua" +CONNECTION_TENTATIVE_STATUS = "Initial Connection Made" +CONNECTION_CONNECTED_STATUS = "Connected" +CONNECTION_INITIAL_STATUS = "Connection has not been initiated" + +DISPLAY_MSGS = True + + +class GBCommandProcessor(ClientCommandProcessor): + def __init__(self, ctx: CommonContext): + super().__init__(ctx) + + def _cmd_gb(self): + """Check Gameboy Connection State""" + if isinstance(self.ctx, GBContext): + logger.info(f"Gameboy Status: {self.ctx.gb_status}") + + +class GBContext(CommonContext): + command_processor = GBCommandProcessor + game = 'Pokemon Red and Blue' + items_handling = 0b101 + + def __init__(self, server_address, password): + super().__init__(server_address, password) + self.gb_streams: (StreamReader, StreamWriter) = None + self.gb_sync_task = None + self.messages = {} + self.locations_array = None + self.gb_status = CONNECTION_INITIAL_STATUS + self.awaiting_rom = False + self.display_msgs = True + + async def server_auth(self, password_requested: bool = False): + if password_requested and not self.password: + await super(GBContext, self).server_auth(password_requested) + if not self.auth: + self.awaiting_rom = True + logger.info('Awaiting connection to Bizhawk to get Player information') + return + + await self.send_connect() + + def _set_message(self, msg: str, msg_id: int): + if DISPLAY_MSGS: + self.messages[(time.time(), msg_id)] = msg + + def on_package(self, cmd: str, args: dict): + if cmd == 'Connected': + self.locations_array = None + elif cmd == "RoomInfo": + self.seed_name = args['seed_name'] + elif cmd == 'Print': + msg = args['text'] + if ': !' not in msg: + self._set_message(msg, SYSTEM_MESSAGE_ID) + elif cmd == "ReceivedItems": + msg = f"Received {', '.join([self.item_names[item.item] for item in args['items']])}" + self._set_message(msg, SYSTEM_MESSAGE_ID) + + def run_gui(self): + from kvui import GameManager + + class GBManager(GameManager): + logging_pairs = [ + ("Client", "Archipelago") + ] + base_title = "Archipelago Pokémon Client" + + self.ui = GBManager(self) + self.ui_task = asyncio.create_task(self.ui.async_run(), name="UI") + + +def get_payload(ctx: GBContext): + current_time = time.time() + return json.dumps( + { + "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} + } + ) + + +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:]} + + # Check for clear problems + if len(flags['Rod']) > 1: + return + if flags["EventFlag"][1] + flags["EventFlag"][8] + flags["EventFlag"][9] + flags["EventFlag"][12] \ + + flags["EventFlag"][61] + flags["EventFlag"][62] + flags["EventFlag"][63] + flags["EventFlag"][64] \ + + flags["EventFlag"][65] + flags["EventFlag"][66] + flags["EventFlag"][67] + flags["EventFlag"][68] \ + + flags["EventFlag"][69] + flags["EventFlag"][70] != 0: + return + + for flag_type, loc_map in location_map.items(): + for flag, loc_id in loc_map.items(): + if flag_type == "list": + if (flags["EventFlag"][location_bytes_bits[loc_id][0]['byte']] & 1 << location_bytes_bits[loc_id][0]['bit'] + and flags["Missable"][location_bytes_bits[loc_id][1]['byte']] & 1 << location_bytes_bits[loc_id][1]['bit']): + locations.append(loc_id) + elif flags[flag_type][location_bytes_bits[loc_id]['byte']] & 1 << location_bytes_bits[loc_id]['bit']: + locations.append(loc_id) + if flags["EventFlag"][280] & 1 and not ctx.finished_game: + await ctx.send_msgs([ + {"cmd": "StatusUpdate", + "status": 30} + ]) + ctx.finished_game = True + if locations == ctx.locations_array: + return + ctx.locations_array = locations + if locations is not None: + await ctx.send_msgs([{"cmd": "LocationChecks", "locations": locations}]) + + +async def gb_sync_task(ctx: GBContext): + logger.info("Starting GB connector. Use /gb for status information") + while not ctx.exit_event.is_set(): + error_status = None + if ctx.gb_streams: + (reader, writer) = ctx.gb_streams + msg = get_payload(ctx).encode() + writer.write(msg) + writer.write(b'\n') + try: + await asyncio.wait_for(writer.drain(), timeout=1.5) + try: + # Data will return a dict with up to two fields: + # 1. A keepalive response of the Players Name (always) + # 2. An array representing the memory values of the locations area (if in game) + data = await asyncio.wait_for(reader.readline(), timeout=5) + data_decoded = json.loads(data.decode()) + #print(data_decoded) + + if ctx.seed_name and ctx.seed_name != bytes(data_decoded['seedName']).decode(): + msg = "The server is running a different multiworld than your client is. (invalid seed_name)" + logger.info(msg, extra={'compact_gui': True}) + ctx.gui_error('Error', msg) + error_status = CONNECTION_RESET_STATUS + ctx.seed_name = bytes(data_decoded['seedName']).decode() + if not ctx.auth: + ctx.auth = ''.join([chr(i) for i in data_decoded['playerName'] if i != 0]) + if ctx.auth == '': + logger.info("Invalid ROM detected. No player name built into the ROM.") + if ctx.awaiting_rom: + await ctx.server_auth(False) + if 'locations' in data_decoded and ctx.game and ctx.gb_status == CONNECTION_CONNECTED_STATUS \ + and not error_status and ctx.auth: + # Not just a keep alive ping, parse + asyncio.create_task(parse_locations(data_decoded['locations'], ctx)) + except asyncio.TimeoutError: + logger.debug("Read Timed Out, Reconnecting") + error_status = CONNECTION_TIMING_OUT_STATUS + writer.close() + ctx.gb_streams = None + except ConnectionResetError as e: + logger.debug("Read failed due to Connection Lost, Reconnecting") + error_status = CONNECTION_RESET_STATUS + writer.close() + ctx.gb_streams = None + except TimeoutError: + logger.debug("Connection Timed Out, Reconnecting") + error_status = CONNECTION_TIMING_OUT_STATUS + writer.close() + ctx.gb_streams = None + except ConnectionResetError: + logger.debug("Connection Lost, Reconnecting") + error_status = CONNECTION_RESET_STATUS + writer.close() + ctx.gb_streams = None + if ctx.gb_status == CONNECTION_TENTATIVE_STATUS: + if not error_status: + logger.info("Successfully Connected to Gameboy") + ctx.gb_status = CONNECTION_CONNECTED_STATUS + else: + ctx.gb_status = f"Was tentatively connected but error occured: {error_status}" + elif error_status: + ctx.gb_status = error_status + logger.info("Lost connection to Gameboy and attempting to reconnect. Use /gb for status updates") + else: + try: + logger.debug("Attempting to connect to Gameboy") + ctx.gb_streams = await asyncio.wait_for(asyncio.open_connection("localhost", 17242), timeout=10) + ctx.gb_status = CONNECTION_TENTATIVE_STATUS + except TimeoutError: + logger.debug("Connection Timed Out, Trying Again") + ctx.gb_status = CONNECTION_TIMING_OUT_STATUS + continue + except ConnectionRefusedError: + logger.debug("Connection Refused, Trying Again") + ctx.gb_status = CONNECTION_REFUSED_STATUS + continue + + +async def run_game(romfile): + auto_start = Utils.get_options()["pokemon_rb_options"].get("rom_start", True) + if auto_start is True: + import webbrowser + webbrowser.open(romfile) + elif os.path.isfile(auto_start): + subprocess.Popen([auto_start, romfile], + stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + +async def patch_and_run_game(game_version, patch_file, ctx): + base_name = os.path.splitext(patch_file)[0] + comp_path = base_name + '.gb' + with open(Utils.local_path(Utils.get_options()["pokemon_rb_options"][f"{game_version}_rom_file"]), "rb") as stream: + base_rom = bytes(stream.read()) + try: + with open(Utils.local_path('lib', 'worlds', 'pokemon_rb', f'basepatch_{game_version}.bsdiff4'), 'rb') as stream: + base_patch = bytes(stream.read()) + except FileNotFoundError: + with open(Utils.local_path('worlds', 'pokemon_rb', f'basepatch_{game_version}.bsdiff4'), 'rb') as stream: + base_patch = bytes(stream.read()) + base_patched_rom_data = bsdiff4.patch(base_rom, base_patch) + basemd5 = hashlib.md5() + basemd5.update(base_patched_rom_data) + + with zipfile.ZipFile(patch_file, 'r') as patch_archive: + with patch_archive.open('delta.bsdiff4', 'r') as stream: + patch = stream.read() + patched_rom_data = bsdiff4.patch(base_patched_rom_data, patch) + + written_hash = patched_rom_data[0xFFCC:0xFFDC] + if written_hash == basemd5.digest(): + with open(comp_path, "wb") as patched_rom_file: + patched_rom_file.write(patched_rom_data) + + asyncio.create_task(run_game(comp_path)) + else: + msg = "Patch supplied was not generated with the same base patch version as this client. Patching failed." + logger.warning(msg) + ctx.gui_error('Error', msg) + + +if __name__ == '__main__': + + Utils.init_logging("PokemonClient") + + options = Utils.get_options() + + async def main(): + parser = get_base_parser() + parser.add_argument('patch_file', default="", type=str, nargs="?", + help='Path to an APRED or APBLUE patch file') + args = parser.parse_args() + + ctx = GBContext(args.connect, args.password) + ctx.server_task = asyncio.create_task(server_loop(ctx), name="ServerLoop") + if gui_enabled: + ctx.run_gui() + ctx.run_cli() + ctx.gb_sync_task = asyncio.create_task(gb_sync_task(ctx), name="GB Sync") + + if args.patch_file: + ext = args.patch_file.split(".")[len(args.patch_file.split(".")) - 1].lower() + if ext == "apred": + logger.info("APRED file supplied, beginning patching process...") + asyncio.create_task(patch_and_run_game("red", args.patch_file, ctx)) + elif ext == "apblue": + logger.info("APBLUE file supplied, beginning patching process...") + asyncio.create_task(patch_and_run_game("blue", args.patch_file, ctx)) + else: + logger.warning(f"Unknown patch file extension {ext}") + + await ctx.exit_event.wait() + ctx.server_address = None + + await ctx.shutdown() + + if ctx.gb_sync_task: + await ctx.gb_sync_task + + + import colorama + + colorama.init() + + asyncio.run(main()) + colorama.deinit() diff --git a/README.md b/README.md index a8228203..9615b0fb 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Currently, the following games are supported: * Donkey Kong Country 3 * Dark Souls 3 * Super Mario World +* Pokémon Red and Blue For setup and instructions check out our [tutorials page](https://archipelago.gg/tutorial/). Downloads can be found at [Releases](https://github.com/ArchipelagoMW/Archipelago/releases), including compiled diff --git a/Utils.py b/Utils.py index 70741545..7df5ce59 100644 --- a/Utils.py +++ b/Utils.py @@ -295,6 +295,11 @@ def get_default_options() -> OptionsType: "sni": "SNI", "rom_start": True, }, + "pokemon_rb_options": { + "red_rom_file": "Pokemon Red (UE) [S][!].gb", + "blue_rom_file": "Pokemon Blue (UE) [S][!].gb", + "rom_start": True + } } return options diff --git a/data/lua/PKMN_RB/core.dll b/data/lua/PKMN_RB/core.dll new file mode 100644 index 0000000000000000000000000000000000000000..3e9569571ab0947dcb7bcd789dc9c06c009d072d GIT binary patch literal 29184 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 B{xARl literal 0 HcmV?d00001 diff --git a/data/lua/PKMN_RB/json.lua b/data/lua/PKMN_RB/json.lua new file mode 100644 index 00000000..a1f6e4ed --- /dev/null +++ b/data/lua/PKMN_RB/json.lua @@ -0,0 +1,389 @@ +-- +-- json.lua +-- +-- Copyright (c) 2015 rxi +-- +-- This library is free software; you can redistribute it and/or modify it +-- under the terms of the MIT license. See LICENSE for details. +-- + +local json = { _version = "0.1.0" } + +------------------------------------------------------------------------------- +-- Encode +------------------------------------------------------------------------------- + +local encode + +function error(err) + print(err) +end + +local escape_char_map = { + [ "\\" ] = "\\\\", + [ "\"" ] = "\\\"", + [ "\b" ] = "\\b", + [ "\f" ] = "\\f", + [ "\n" ] = "\\n", + [ "\r" ] = "\\r", + [ "\t" ] = "\\t", +} + +local escape_char_map_inv = { [ "\\/" ] = "/" } +for k, v in pairs(escape_char_map) do + escape_char_map_inv[v] = k +end + + +local function escape_char(c) + return escape_char_map[c] or string.format("\\u%04x", c:byte()) +end + + +local function encode_nil(val) + return "null" +end + + +local function encode_table(val, stack) + local res = {} + stack = stack or {} + + -- Circular reference? + if stack[val] then error("circular reference") end + + stack[val] = true + + if val[1] ~= nil or next(val) == nil then + -- Treat as array -- check keys are valid and it is not sparse + local n = 0 + for k in pairs(val) do + if type(k) ~= "number" then + error("invalid table: mixed or invalid key types") + end + n = n + 1 + end + if n ~= #val then + print("invalid table: sparse array") + print(n) + print("VAL:") + print(val) + print("STACK:") + print(stack) + end + -- Encode + for i, v in ipairs(val) do + table.insert(res, encode(v, stack)) + end + stack[val] = nil + return "[" .. table.concat(res, ",") .. "]" + + else + -- Treat as an object + for k, v in pairs(val) do + if type(k) ~= "string" then + error("invalid table: mixed or invalid key types") + end + table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) + end + stack[val] = nil + return "{" .. table.concat(res, ",") .. "}" + end +end + + +local function encode_string(val) + return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' +end + + +local function encode_number(val) + -- Check for NaN, -inf and inf + if val ~= val or val <= -math.huge or val >= math.huge then + error("unexpected number value '" .. tostring(val) .. "'") + end + return string.format("%.14g", val) +end + + +local type_func_map = { + [ "nil" ] = encode_nil, + [ "table" ] = encode_table, + [ "string" ] = encode_string, + [ "number" ] = encode_number, + [ "boolean" ] = tostring, +} + + +encode = function(val, stack) + local t = type(val) + local f = type_func_map[t] + if f then + return f(val, stack) + end + error("unexpected type '" .. t .. "'") +end + + +function json.encode(val) + return ( encode(val) ) +end + + +------------------------------------------------------------------------------- +-- Decode +------------------------------------------------------------------------------- + +local parse + +local function create_set(...) + local res = {} + for i = 1, select("#", ...) do + res[ select(i, ...) ] = true + end + return res +end + +local space_chars = create_set(" ", "\t", "\r", "\n") +local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",") +local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") +local literals = create_set("true", "false", "null") + +local literal_map = { + [ "true" ] = true, + [ "false" ] = false, + [ "null" ] = nil, +} + + +local function next_char(str, idx, set, negate) + for i = idx, #str do + if set[str:sub(i, i)] ~= negate then + return i + end + end + return #str + 1 +end + + +local function decode_error(str, idx, msg) + --local line_count = 1 + --local col_count = 1 + --for i = 1, idx - 1 do + -- col_count = col_count + 1 + -- if str:sub(i, i) == "\n" then + -- line_count = line_count + 1 + -- col_count = 1 + -- end + -- end + -- emu.message( string.format("%s at line %d col %d", msg, line_count, col_count) ) +end + + +local function codepoint_to_utf8(n) + -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa + local f = math.floor + if n <= 0x7f then + return string.char(n) + elseif n <= 0x7ff then + return string.char(f(n / 64) + 192, n % 64 + 128) + elseif n <= 0xffff then + return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) + elseif n <= 0x10ffff then + return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, + f(n % 4096 / 64) + 128, n % 64 + 128) + end + error( string.format("invalid unicode codepoint '%x'", n) ) +end + + +local function parse_unicode_escape(s) + local n1 = tonumber( s:sub(3, 6), 16 ) + local n2 = tonumber( s:sub(9, 12), 16 ) + -- Surrogate pair? + if n2 then + return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) + else + return codepoint_to_utf8(n1) + end +end + + +local function parse_string(str, i) + local has_unicode_escape = false + local has_surrogate_escape = false + local has_escape = false + local last + for j = i + 1, #str do + local x = str:byte(j) + + if x < 32 then + decode_error(str, j, "control character in string") + end + + if last == 92 then -- "\\" (escape char) + if x == 117 then -- "u" (unicode escape sequence) + local hex = str:sub(j + 1, j + 5) + if not hex:find("%x%x%x%x") then + decode_error(str, j, "invalid unicode escape in string") + end + if hex:find("^[dD][89aAbB]") then + has_surrogate_escape = true + else + has_unicode_escape = true + end + else + local c = string.char(x) + if not escape_chars[c] then + decode_error(str, j, "invalid escape char '" .. c .. "' in string") + end + has_escape = true + end + last = nil + + elseif x == 34 then -- '"' (end of string) + local s = str:sub(i + 1, j - 1) + if has_surrogate_escape then + s = s:gsub("\\u[dD][89aAbB]..\\u....", parse_unicode_escape) + end + if has_unicode_escape then + s = s:gsub("\\u....", parse_unicode_escape) + end + if has_escape then + s = s:gsub("\\.", escape_char_map_inv) + end + return s, j + 1 + + else + last = x + end + end + decode_error(str, i, "expected closing quote for string") +end + + +local function parse_number(str, i) + local x = next_char(str, i, delim_chars) + local s = str:sub(i, x - 1) + local n = tonumber(s) + if not n then + decode_error(str, i, "invalid number '" .. s .. "'") + end + return n, x +end + + +local function parse_literal(str, i) + local x = next_char(str, i, delim_chars) + local word = str:sub(i, x - 1) + if not literals[word] then + decode_error(str, i, "invalid literal '" .. word .. "'") + end + return literal_map[word], x +end + + +local function parse_array(str, i) + local res = {} + local n = 1 + i = i + 1 + while 1 do + local x + i = next_char(str, i, space_chars, true) + -- Empty / end of array? + if str:sub(i, i) == "]" then + i = i + 1 + break + end + -- Read token + x, i = parse(str, i) + res[n] = x + n = n + 1 + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "]" then break end + if chr ~= "," then decode_error(str, i, "expected ']' or ','") end + end + return res, i +end + + +local function parse_object(str, i) + local res = {} + i = i + 1 + while 1 do + local key, val + i = next_char(str, i, space_chars, true) + -- Empty / end of object? + if str:sub(i, i) == "}" then + i = i + 1 + break + end + -- Read key + if str:sub(i, i) ~= '"' then + decode_error(str, i, "expected string for key") + end + key, i = parse(str, i) + -- Read ':' delimiter + i = next_char(str, i, space_chars, true) + if str:sub(i, i) ~= ":" then + decode_error(str, i, "expected ':' after key") + end + i = next_char(str, i + 1, space_chars, true) + -- Read value + val, i = parse(str, i) + -- Set + res[key] = val + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "}" then break end + if chr ~= "," then decode_error(str, i, "expected '}' or ','") end + end + return res, i +end + + +local char_func_map = { + [ '"' ] = parse_string, + [ "0" ] = parse_number, + [ "1" ] = parse_number, + [ "2" ] = parse_number, + [ "3" ] = parse_number, + [ "4" ] = parse_number, + [ "5" ] = parse_number, + [ "6" ] = parse_number, + [ "7" ] = parse_number, + [ "8" ] = parse_number, + [ "9" ] = parse_number, + [ "-" ] = parse_number, + [ "t" ] = parse_literal, + [ "f" ] = parse_literal, + [ "n" ] = parse_literal, + [ "[" ] = parse_array, + [ "{" ] = parse_object, +} + + +parse = function(str, idx) + local chr = str:sub(idx, idx) + local f = char_func_map[chr] + if f then + return f(str, idx) + end + decode_error(str, idx, "unexpected character '" .. chr .. "'") +end + + +function json.decode(str) + if type(str) ~= "string" then + error("expected argument of type string, got " .. type(str)) + end + return ( parse(str, next_char(str, 1, space_chars, true)) ) +end + + +return json \ No newline at end of file diff --git a/data/lua/PKMN_RB/pkmn_rb.lua b/data/lua/PKMN_RB/pkmn_rb.lua new file mode 100644 index 00000000..7518a5f1 --- /dev/null +++ b/data/lua/PKMN_RB/pkmn_rb.lua @@ -0,0 +1,238 @@ +local socket = require("socket") +local json = require('json') +local math = require('math') + +local STATE_OK = "Ok" +local STATE_TENTATIVELY_CONNECTED = "Tentatively Connected" +local STATE_INITIAL_CONNECTION_MADE = "Initial Connection Made" +local STATE_UNINITIALIZED = "Uninitialized" + +local APIndex = 0x1A6E +local APItemAddress = 0x00FF +local EventFlagAddress = 0x1735 +local MissableAddress = 0x161A +local HiddenItemsAddress = 0x16DE +local RodAddress = 0x1716 +local InGame = 0x1A71 + +local ItemsReceived = nil +local playerName = nil +local seedName = nil + +local prevstate = "" +local curstate = STATE_UNINITIALIZED +local gbSocket = nil +local frame = 0 + +local u8 = nil +local wU8 = nil +local u16 + +--Sets correct memory access functions based on whether NesHawk or QuickNES is loaded +local function defineMemoryFunctions() + local memDomain = {} + local domains = memory.getmemorydomainlist() + --if domains[1] == "System Bus" then + -- --NesHawk + -- isNesHawk = true + -- memDomain["systembus"] = function() memory.usememorydomain("System Bus") end + -- memDomain["saveram"] = function() memory.usememorydomain("Battery RAM") end + -- memDomain["rom"] = function() memory.usememorydomain("PRG ROM") end + --elseif domains[1] == "WRAM" then + -- --QuickNES + -- memDomain["systembus"] = function() memory.usememorydomain("System Bus") end + -- memDomain["saveram"] = function() memory.usememorydomain("WRAM") end + -- memDomain["rom"] = function() memory.usememorydomain("PRG ROM") end + --end + memDomain["rom"] = function() memory.usememorydomain("ROM") end + memDomain["wram"] = function() memory.usememorydomain("WRAM") end + return memDomain +end + +local memDomain = defineMemoryFunctions() +u8 = memory.read_u8 +wU8 = memory.write_u8 +u16 = memory.read_u16_le +function uRange(address, bytes) + data = memory.readbyterange(address - 1, bytes + 1) + data[0] = nil + return data +end + + +function table.empty (self) + for _, _ in pairs(self) do + return false + end + return true +end + +function slice (tbl, s, e) + local pos, new = 1, {} + for i = s + 1, e do + new[pos] = tbl[i] + pos = pos + 1 + end + return new +end + +function processBlock(block) + if block == nil then + return + end + local itemsBlock = block["items"] + memDomain.wram() + if itemsBlock ~= nil then-- and u8(0x116B) ~= 0x00 then + -- print(itemsBlock) + ItemsReceived = itemsBlock + + end +end + +function difference(a, b) + local aa = {} + for k,v in pairs(a) do aa[v]=true end + for k,v in pairs(b) do aa[v]=nil end + local ret = {} + local n = 0 + for k,v in pairs(a) do + if aa[v] then n=n+1 ret[n]=v end + end + return ret +end + +function generateLocationsChecked() + memDomain.wram() + events = uRange(EventFlagAddress, 0x140) + missables = uRange(MissableAddress, 0x20) + hiddenitems = uRange(HiddenItemsAddress, 0x0E) + rod = u8(RodAddress) + + data = {} + + table.foreach(events, function(k, v) table.insert(data, v) end) + table.foreach(missables, function(k, v) table.insert(data, v) end) + table.foreach(hiddenitems, function(k, v) table.insert(data, v) end) + table.insert(data, rod) + + return data +end +function generateSerialData() + memDomain.wram() + status = u8(0x1A73) + if status == 0 then + return nil + end + return uRange(0x1A76, u8(0x1A74)) +end +local function arrayEqual(a1, a2) + if #a1 ~= #a2 then + return false + end + + for i, v in ipairs(a1) do + if v ~= a2[i] then + return false + end + end + + return true +end + +function receive() + l, e = gbSocket:receive() + if e == 'closed' then + if curstate == STATE_OK then + print("Connection closed") + end + curstate = STATE_UNINITIALIZED + return + elseif e == 'timeout' then + --print("timeout") -- this keeps happening for some reason? just hide it + return + elseif e ~= nil then + print(e) + curstate = STATE_UNINITIALIZED + return + end + if l ~= nil then + processBlock(json.decode(l)) + end + -- Determine Message to send back + memDomain.rom() + newPlayerName = uRange(0xFFF0, 0x10) + newSeedName = uRange(0xFFDC, 20) + if (playerName ~= nil and not arrayEqual(playerName, newPlayerName)) or (seedName ~= nil and not arrayEqual(seedName, newSeedName)) then + print("ROM changed, quitting") + curstate = STATE_UNINITIALIZED + return + end + playerName = newPlayerName + seedName = newSeedName + local retTable = {} + retTable["playerName"] = playerName + retTable["seedName"] = seedName + memDomain.wram() + if u8(InGame) == 0xAC then + retTable["locations"] = generateLocationsChecked() + serialData = generateSerialData() + if serialData ~= nil then + retTable["serial"] = serialData + end + end + msg = json.encode(retTable).."\n" + local ret, error = gbSocket:send(msg) + if ret == nil then + print(error) + elseif curstate == STATE_INITIAL_CONNECTION_MADE then + curstate = STATE_TENTATIVELY_CONNECTED + elseif curstate == STATE_TENTATIVELY_CONNECTED then + print("Connected!") + curstate = STATE_OK + end +end + +function main() + if (is23Or24Or25 or is26To28) == false then + print("Must use a version of bizhawk 2.3.1 or higher") + return + end + server, error = socket.bind('localhost', 17242) + + while true do + if not (curstate == prevstate) then + print("Current state: "..curstate) + prevstate = curstate + end + if (curstate == STATE_OK) or (curstate == STATE_INITIAL_CONNECTION_MADE) or (curstate == STATE_TENTATIVELY_CONNECTED) then + if (frame % 60 == 0) then + receive() + if u8(InGame) == 0xAC then + ItemIndex = u16(APIndex) + if ItemsReceived[ItemIndex + 1] ~= nil then + wU8(APItemAddress, ItemsReceived[ItemIndex + 1] - 172000000) + end + end + end + elseif (curstate == STATE_UNINITIALIZED) then + if (frame % 60 == 0) then + + print("Waiting for client.") + + emu.frameadvance() + server:settimeout(2) + print("Attempting to connect") + local client, timeout = server:accept() + if timeout == nil then + -- print('Initial Connection Made') + curstate = STATE_INITIAL_CONNECTION_MADE + gbSocket = client + gbSocket:settimeout(0) + end + end + end + emu.frameadvance() + end +end + +main() diff --git a/data/lua/PKMN_RB/socket.lua b/data/lua/PKMN_RB/socket.lua new file mode 100644 index 00000000..a98e9521 --- /dev/null +++ b/data/lua/PKMN_RB/socket.lua @@ -0,0 +1,132 @@ +----------------------------------------------------------------------------- +-- LuaSocket helper module +-- Author: Diego Nehab +-- RCS ID: $Id: socket.lua,v 1.22 2005/11/22 08:33:29 diego Exp $ +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +----------------------------------------------------------------------------- +local base = _G +local string = require("string") +local math = require("math") +local socket = require("socket.core") +module("socket") + +----------------------------------------------------------------------------- +-- Exported auxiliar functions +----------------------------------------------------------------------------- +function connect(address, port, laddress, lport) + local sock, err = socket.tcp() + if not sock then return nil, err end + if laddress then + local res, err = sock:bind(laddress, lport, -1) + if not res then return nil, err end + end + local res, err = sock:connect(address, port) + if not res then return nil, err end + return sock +end + +function bind(host, port, backlog) + local sock, err = socket.tcp() + if not sock then return nil, err end + sock:setoption("reuseaddr", true) + local res, err = sock:bind(host, port) + if not res then return nil, err end + res, err = sock:listen(backlog) + if not res then return nil, err end + return sock +end + +try = newtry() + +function choose(table) + return function(name, opt1, opt2) + if base.type(name) ~= "string" then + name, opt1, opt2 = "default", name, opt1 + end + local f = table[name or "nil"] + if not f then base.error("unknown key (".. base.tostring(name) ..")", 3) + else return f(opt1, opt2) end + end +end + +----------------------------------------------------------------------------- +-- Socket sources and sinks, conforming to LTN12 +----------------------------------------------------------------------------- +-- create namespaces inside LuaSocket namespace +sourcet = {} +sinkt = {} + +BLOCKSIZE = 2048 + +sinkt["close-when-done"] = function(sock) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function(self, chunk, err) + if not chunk then + sock:close() + return 1 + else return sock:send(chunk) end + end + }) +end + +sinkt["keep-open"] = function(sock) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function(self, chunk, err) + if chunk then return sock:send(chunk) + else return 1 end + end + }) +end + +sinkt["default"] = sinkt["keep-open"] + +sink = choose(sinkt) + +sourcet["by-length"] = function(sock, length) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function() + if length <= 0 then return nil end + local size = math.min(socket.BLOCKSIZE, length) + local chunk, err = sock:receive(size) + if err then return nil, err end + length = length - string.len(chunk) + return chunk + end + }) +end + +sourcet["until-closed"] = function(sock) + local done + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function() + if done then return nil end + local chunk, err, partial = sock:receive(socket.BLOCKSIZE) + if not err then return chunk + elseif err == "closed" then + sock:close() + done = 1 + return partial + else return nil, err end + end + }) +end + + +sourcet["default"] = sourcet["until-closed"] + +source = choose(sourcet) diff --git a/host.yaml b/host.yaml index b1141355..f36f014a 100644 --- a/host.yaml +++ b/host.yaml @@ -138,6 +138,14 @@ dkc3_options: # True for operating system default program # Alternatively, a path to a program to open the .sfc file with rom_start: true +pokemon_rb_options: + # File names of the Pokemon Red and Blue roms + red_rom_file: "Pokemon Red (UE) [S][!].gb" + blue_rom_file: "Pokemon Blue (UE) [S][!].gb" + # Set this to false to never autostart a rom (such as after patching) + # True for operating system default program + # Alternatively, a path to a program to open the .gb file with + rom_start: true smw_options: # File name of the SMW US rom rom_file: "Super Mario World (USA).sfc" diff --git a/inno_setup.iss b/inno_setup.iss index 9a2a4044..e097798c 100644 --- a/inno_setup.iss +++ b/inno_setup.iss @@ -59,6 +59,8 @@ Name: "generator/smw"; Description: "Super Mario World ROM Setup"; Types: ful Name: "generator/soe"; Description: "Secret of Evermore ROM Setup"; Types: full hosting; ExtraDiskSpaceRequired: 3145728; Flags: disablenouninstallwarning Name: "generator/lttp"; Description: "A Link to the Past ROM Setup and Enemizer"; Types: full hosting; ExtraDiskSpaceRequired: 5191680 Name: "generator/oot"; Description: "Ocarina of Time ROM Setup"; Types: full hosting; ExtraDiskSpaceRequired: 100663296; Flags: disablenouninstallwarning +Name: "generator/pkmn_r"; Description: "Pokemon Red ROM Setup"; Types: full hosting +Name: "generator/pkmn_b"; Description: "Pokemon Blue ROM Setup"; Types: full hosting Name: "server"; Description: "Server"; Types: full hosting Name: "client"; Description: "Clients"; Types: full playing Name: "client/sni"; Description: "SNI Client"; Types: full playing @@ -70,6 +72,9 @@ Name: "client/factorio"; Description: "Factorio"; Types: full playing Name: "client/minecraft"; Description: "Minecraft"; Types: full playing; ExtraDiskSpaceRequired: 226894278 Name: "client/oot"; Description: "Ocarina of Time"; Types: full playing Name: "client/ff1"; Description: "Final Fantasy 1"; Types: full playing +Name: "client/pkmn"; Description: "Pokemon Client" +Name: "client/pkmn/red"; Description: "Pokemon Client - Pokemon Red Setup"; Types: full playing; ExtraDiskSpaceRequired: 1048576 +Name: "client/pkmn/blue"; Description: "Pokemon Client - Pokemon Blue Setup"; Types: full playing; ExtraDiskSpaceRequired: 1048576 Name: "client/cf"; Description: "ChecksFinder"; Types: full playing Name: "client/sc2"; Description: "Starcraft 2"; Types: full playing Name: "client/text"; Description: "Text, to !command and chat"; Types: full playing @@ -84,6 +89,8 @@ Source: "{code:GetDKC3ROMPath}"; DestDir: "{app}"; DestName: "Donkey Kong Countr Source: "{code:GetSMWROMPath}"; DestDir: "{app}"; DestName: "Super Mario World (USA).sfc"; Flags: external; Components: client/sni/smw or generator/smw Source: "{code:GetSoEROMPath}"; DestDir: "{app}"; DestName: "Secret of Evermore (USA).sfc"; Flags: external; Components: generator/soe Source: "{code:GetOoTROMPath}"; DestDir: "{app}"; DestName: "The Legend of Zelda - Ocarina of Time.z64"; Flags: external; Components: client/oot or generator/oot +Source: "{code:GetRedROMPath}"; DestDir: "{app}"; DestName: "Pokemon Red (UE) [S][!].gb"; Flags: external; Components: client/pkmn/red or generator/pkmn_r +Source: "{code:GetBlueROMPath}"; DestDir: "{app}"; DestName: "Pokemon Blue (UE) [S][!].gb"; Flags: external; Components: client/pkmn/blue or generator/pkmn_b Source: "{#source_path}\*"; Excludes: "*.sfc, *.log, data\sprites\alttpr, SNI, EnemizerCLI, Archipelago*.exe"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "{#source_path}\SNI\*"; Excludes: "*.sfc, *.log"; DestDir: "{app}\SNI"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: client/sni Source: "{#source_path}\EnemizerCLI\*"; Excludes: "*.sfc, *.log"; DestDir: "{app}\EnemizerCLI"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: generator/lttp @@ -98,6 +105,7 @@ Source: "{#source_path}\ArchipelagoMinecraftClient.exe"; DestDir: "{app}"; Flags Source: "{#source_path}\ArchipelagoOoTClient.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: client/oot Source: "{#source_path}\ArchipelagoOoTAdjuster.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: client/oot Source: "{#source_path}\ArchipelagoFF1Client.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: client/ff1 +Source: "{#source_path}\ArchipelagoPokemonClient.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: client/pkmn Source: "{#source_path}\ArchipelagoChecksFinderClient.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: client/cf Source: "{#source_path}\ArchipelagoStarcraft2Client.exe"; DestDir: "{app}"; Flags: ignoreversion; Components: client/sc2 Source: "vc_redist.x64.exe"; DestDir: {tmp}; Flags: deleteafterinstall @@ -111,6 +119,7 @@ Name: "{group}\{#MyAppName} Factorio Client"; Filename: "{app}\ArchipelagoFactor Name: "{group}\{#MyAppName} Minecraft Client"; Filename: "{app}\ArchipelagoMinecraftClient.exe"; Components: client/minecraft Name: "{group}\{#MyAppName} Ocarina of Time Client"; Filename: "{app}\ArchipelagoOoTClient.exe"; Components: client/oot Name: "{group}\{#MyAppName} Final Fantasy 1 Client"; Filename: "{app}\ArchipelagoFF1Client.exe"; Components: client/ff1 +Name: "{group}\{#MyAppName} Pokemon Client"; Filename: "{app}\ArchipelagoPokemonClient.exe"; Components: client/pkmn Name: "{group}\{#MyAppName} ChecksFinder Client"; Filename: "{app}\ArchipelagoChecksFinderClient.exe"; Components: client/cf Name: "{group}\{#MyAppName} Starcraft 2 Client"; Filename: "{app}\ArchipelagoStarcraft2Client.exe"; Components: client/sc2 @@ -121,6 +130,7 @@ Name: "{commondesktop}\{#MyAppName} Factorio Client"; Filename: "{app}\Archipela Name: "{commondesktop}\{#MyAppName} Minecraft Client"; Filename: "{app}\ArchipelagoMinecraftClient.exe"; Tasks: desktopicon; Components: client/minecraft Name: "{commondesktop}\{#MyAppName} Ocarina of Time Client"; Filename: "{app}\ArchipelagoOoTClient.exe"; Tasks: desktopicon; Components: client/oot Name: "{commondesktop}\{#MyAppName} Final Fantasy 1 Client"; Filename: "{app}\ArchipelagoFF1Client.exe"; Tasks: desktopicon; Components: client/ff1 +Name: "{commondesktop}\{#MyAppName} Pokemon Client"; Filename: "{app}\ArchipelagoPokemonClient.exe"; Tasks: desktopicon; Components: client/pkmn Name: "{commondesktop}\{#MyAppName} ChecksFinder Client"; Filename: "{app}\ArchipelagoChecksFinderClient.exe"; Tasks: desktopicon; Components: client/cf Name: "{commondesktop}\{#MyAppName} Starcraft 2 Client"; Filename: "{app}\ArchipelagoStarcraft2Client.exe"; Tasks: desktopicon; Components: client/sc2 @@ -179,6 +189,16 @@ Root: HKCR; Subkey: "{#MyAppName}n64zpf"; ValueData: "Archip Root: HKCR; Subkey: "{#MyAppName}n64zpf\DefaultIcon"; ValueData: "{app}\ArchipelagoOoTClient.exe,0"; ValueType: string; ValueName: ""; Components: client/oot Root: HKCR; Subkey: "{#MyAppName}n64zpf\shell\open\command"; ValueData: """{app}\ArchipelagoOoTClient.exe"" ""%1"""; ValueType: string; ValueName: ""; Components: client/oot +Root: HKCR; Subkey: ".apred"; ValueData: "{#MyAppName}pkmnrpatch"; Flags: uninsdeletevalue; ValueType: string; ValueName: ""; Components: client/pkmn/red +Root: HKCR; Subkey: "{#MyAppName}pkmnrpatch"; ValueData: "Archipelago Pokemon Red Patch"; Flags: uninsdeletekey; ValueType: string; ValueName: ""; Components: client/pkmn/red +Root: HKCR; Subkey: "{#MyAppName}pkmnrpatch\DefaultIcon"; ValueData: "{app}\ArchipelagoPokemonClient.exe,0"; ValueType: string; ValueName: ""; Components: client/pkmn/red +Root: HKCR; Subkey: "{#MyAppName}pkmnrpatch\shell\open\command"; ValueData: """{app}\ArchipelagoPokemonClient.exe"" ""%1"""; ValueType: string; ValueName: ""; Components: client/pkmn/red + +Root: HKCR; Subkey: ".apblue"; ValueData: "{#MyAppName}pkmnbpatch"; Flags: uninsdeletevalue; ValueType: string; ValueName: ""; Components: client/pkmn/blue +Root: HKCR; Subkey: "{#MyAppName}pkmnbpatch"; ValueData: "Archipelago Pokemon Blue Patch"; Flags: uninsdeletekey; ValueType: string; ValueName: ""; Components: client/pkmn/blue +Root: HKCR; Subkey: "{#MyAppName}pkmnbpatch\DefaultIcon"; ValueData: "{app}\ArchipelagoPokemonClient.exe,0"; ValueType: string; ValueName: ""; Components: client/pkmn/blue +Root: HKCR; Subkey: "{#MyAppName}pkmnbpatch\shell\open\command"; ValueData: """{app}\ArchipelagoPokemonClient.exe"" ""%1"""; ValueType: string; ValueName: ""; Components: client/pkmn/blue + Root: HKCR; Subkey: ".archipelago"; ValueData: "{#MyAppName}multidata"; Flags: uninsdeletevalue; ValueType: string; ValueName: ""; Components: server Root: HKCR; Subkey: "{#MyAppName}multidata"; ValueData: "Archipelago Server Data"; Flags: uninsdeletekey; ValueType: string; ValueName: ""; Components: server Root: HKCR; Subkey: "{#MyAppName}multidata\DefaultIcon"; ValueData: "{app}\ArchipelagoServer.exe,0"; ValueType: string; ValueName: ""; Components: server @@ -234,6 +254,12 @@ var SoERomFilePage: TInputFileWizardPage; var ootrom: string; var OoTROMFilePage: TInputFileWizardPage; +var redrom: string; +var RedROMFilePage: TInputFileWizardPage; + +var bluerom: string; +var BlueROMFilePage: TInputFileWizardPage; + function GetSNESMD5OfFile(const rom: string): string; var data: AnsiString; begin @@ -281,6 +307,21 @@ begin '.sfc'); end; +function AddGBRomPage(name: string): TInputFileWizardPage; +begin + Result := + CreateInputFilePage( + wpSelectComponents, + 'Select ROM File', + 'Where is your ' + name + ' located?', + 'Select the file, then click Next.'); + + Result.Add( + 'Location of ROM file:', + 'GB ROM files|*.gb;*.gbc|All files|*.*', + '.gb'); +end; + procedure AddOoTRomPage(); begin ootrom := FileSearch('The Legend of Zelda - Ocarina of Time.z64', WizardDirValue()); @@ -425,6 +466,38 @@ begin Result := ''; end; +function GetRedROMPath(Param: string): string; +begin + if Length(redrom) > 0 then + Result := redrom + else if Assigned(RedRomFilePage) then + begin + R := CompareStr(GetMD5OfFile(RedROMFilePage.Values[0]), '3d45c1ee9abd5738df46d2bdda8b57dc') + if R <> 0 then + MsgBox('Pokemon Red ROM validation failed. Very likely wrong file.', mbInformation, MB_OK); + + Result := RedROMFilePage.Values[0] + end + else + Result := ''; + end; + +function GetBlueROMPath(Param: string): string; +begin + if Length(bluerom) > 0 then + Result := bluerom + else if Assigned(BlueRomFilePage) then + begin + R := CompareStr(GetMD5OfFile(BlueROMFilePage.Values[0]), '50927e843568814f7ed45ec4f944bd8b') + if R <> 0 then + MsgBox('Pokemon Blue ROM validation failed. Very likely wrong file.', mbInformation, MB_OK); + + Result := BlueROMFilePage.Values[0] + end + else + Result := ''; + end; + procedure InitializeWizard(); begin AddOoTRomPage(); @@ -448,6 +521,14 @@ begin soerom := CheckRom('Secret of Evermore (USA).sfc', '6e9c94511d04fac6e0a1e582c170be3a'); if Length(soerom) = 0 then SoEROMFilePage:= AddRomPage('Secret of Evermore (USA).sfc'); + + redrom := CheckRom('Pokemon Red (UE) [S][!].gb','3d45c1ee9abd5738df46d2bdda8b57dc'); + if Length(redrom) = 0 then + RedROMFilePage:= AddGBRomPage('Pokemon Red (UE) [S][!].gb'); + + bluerom := CheckRom('Pokemon Blue (UE) [S][!].gb','50927e843568814f7ed45ec4f944bd8b'); + if Length(redrom) = 0 then + BlueROMFilePage:= AddGBRomPage('Pokemon Blue (UE) [S][!].gb'); end; @@ -466,4 +547,8 @@ begin Result := not (WizardIsComponentSelected('generator/soe')); if (assigned(OoTROMFilePage)) and (PageID = OoTROMFilePage.ID) then Result := not (WizardIsComponentSelected('generator/oot') or WizardIsComponentSelected('client/oot')); -end; \ No newline at end of file + if (assigned(RedROMFilePage)) and (PageID = RedROMFilePage.ID) then + Result := not (WizardIsComponentSelected('generator/pkmn_r') or WizardIsComponentSelected('client/pkmn/red')); + if (assigned(BlueROMFilePage)) and (PageID = BlueROMFilePage.ID) then + Result := not (WizardIsComponentSelected('generator/pkmn_b') or WizardIsComponentSelected('client/pkmn/blue')); +end; diff --git a/worlds/Files.py b/worlds/Files.py index 6f81a0e2..ac1acbf3 100644 --- a/worlds/Files.py +++ b/worlds/Files.py @@ -99,7 +99,7 @@ class APContainer: "player_name": self.player_name, "game": self.game, # minimum version of patch system expected for patching to be successful - "compatible_version": 4, + "compatible_version": 5, "version": current_patch_version, } diff --git a/worlds/pokemon_rb/LICENSE b/worlds/pokemon_rb/LICENSE new file mode 100644 index 00000000..0dc1b2dc --- /dev/null +++ b/worlds/pokemon_rb/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Alex "Alchav" Avery + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/worlds/pokemon_rb/__init__.py b/worlds/pokemon_rb/__init__.py new file mode 100644 index 00000000..d4ca79ff --- /dev/null +++ b/worlds/pokemon_rb/__init__.py @@ -0,0 +1,254 @@ +from typing import TextIO +import os +import logging + +from BaseClasses import Item, MultiWorld, Tutorial, ItemClassification +from Fill import fill_restrictive, FillError, sweep_from_pool +from ..AutoWorld import World, WebWorld +from ..generic.Rules import add_item_rule +from .items import item_table, item_groups +from .locations import location_data, PokemonRBLocation +from .regions import create_regions +from .logic import PokemonLogic +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 +from .rules import set_rules + +import worlds.pokemon_rb.poke_data as poke_data + + +class PokemonWebWorld(WebWorld): + tutorials = [Tutorial( + "Multiworld Setup Guide", + "A guide to playing Pokemon Red and Blue with Archipelago.", + "English", + "setup_en.md", + "setup/en", + ["Alchav"] + )] + + +class PokemonRedBlueWorld(World): + """Pokémon Red and Pokémon Blue are the original monster-collecting turn-based RPGs. Explore the Kanto region with + your Pokémon, catch more than 150 unique creatures, earn badges from the region's Gym Leaders, and challenge the + Elite Four to become the champion!""" + # -MuffinJets#4559 + game = "Pokemon Red and Blue" + option_definitions = pokemon_rb_options + remote_items = False + data_version = 1 + 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"} + item_name_groups = item_groups + + web = PokemonWebWorld() + + def __init__(self, world: MultiWorld, player: int): + super().__init__(world, player) + self.fly_map = None + self.fly_map_code = None + self.extra_badges = {} + self.type_chart = None + self.local_poke_data = None + self.learnsets = None + self.trainer_name = None + self.rival_name = None + + @classmethod + def stage_assert_generate(cls, world): + versions = set() + for player in world.player_ids: + if world.worlds[player].game == "Pokemon Red and Blue": + versions.add(world.game_version[player].current_key) + for version in versions: + if not os.path.exists(get_base_rom_path(version)): + raise FileNotFoundError(get_base_rom_path(version)) + + def generate_early(self): + def encode_name(name, t): + try: + if len(encode_text(name)) > 7: + raise IndexError(f"{t} name too long for player {self.world.player_name[self.player]}. Must be 7 characters or fewer.") + return encode_text(name, length=8, whitespace="@", safety=True) + except KeyError as e: + raise KeyError(f"Invalid character(s) in {t} name for player {self.world.player_name[self.player]}") from e + self.trainer_name = encode_name(self.world.trainer_name[self.player].value, "Player") + self.rival_name = encode_name(self.world.rival_name[self.player].value, "Rival") + + if self.world.badges_needed_for_hm_moves[self.player].value >= 2: + badges_to_add = ["Marsh Badge", "Volcano Badge", "Earth Badge"] + if self.world.badges_needed_for_hm_moves[self.player].value == 3: + badges = ["Boulder Badge", "Cascade Badge", "Thunder Badge", "Rainbow Badge", "Marsh Badge", + "Soul Badge", "Volcano Badge", "Earth Badge"] + self.world.random.shuffle(badges) + badges_to_add += [badges.pop(), badges.pop()] + hm_moves = ["Cut", "Fly", "Surf", "Strength", "Flash"] + self.world.random.shuffle(hm_moves) + self.extra_badges = {} + for badge in badges_to_add: + self.extra_badges[hm_moves.pop()] = badge + + process_pokemon_data(self) + + def create_items(self) -> None: + locations = [location for location in location_data if location.type == "Item"] + item_pool = [] + for location in locations: + if "Hidden" in location.name and not self.world.randomize_hidden_items[self.player].value: + continue + if "Rock Tunnel B1F" in location.region and not self.world.extra_key_items[self.player].value: + continue + if location.name == "Celadon City - Mansion Lady" and not self.world.tea[self.player].value: + continue + item = self.create_item(location.original_item) + if location.event: + self.world.get_location(location.name, self.player).place_locked_item(item) + elif ("Badge" not in item.name or self.world.badgesanity[self.player].value) and \ + (item.name != "Oak's Parcel" or self.world.old_man[self.player].value != 1): + item_pool.append(item) + self.world.random.shuffle(item_pool) + + self.world.itempool += item_pool + + + def pre_fill(self): + + process_wild_pokemon(self) + process_static_pokemon(self) + + if self.world.old_man[self.player].value == 1: + item = self.create_item("Oak's Parcel") + locations = [] + for location in self.world.get_locations(): + if location.player == self.player and location.item is None and location.can_reach(self.world.state) \ + and location.item_rule(item): + locations.append(location) + self.world.random.choice(locations).place_locked_item(item) + + + + if not self.world.badgesanity[self.player].value: + self.world.non_local_items[self.player].value -= self.item_name_groups["Badges"] + for i in range(5): + try: + badges = [] + badgelocs = [] + for badge in ["Boulder Badge", "Cascade Badge", "Thunder Badge", "Rainbow Badge", "Soul Badge", + "Marsh Badge", "Volcano Badge", "Earth Badge"]: + badges.append(self.create_item(badge)) + for loc in ["Pewter Gym - Brock 1", "Cerulean Gym - Misty 1", "Vermilion Gym - Lt. Surge 1", + "Celadon Gym - Erika 1", "Fuchsia Gym - Koga 1", "Saffron Gym - Sabrina 1", + "Cinnabar Gym - Blaine 1", "Viridian Gym - Giovanni 1"]: + badgelocs.append(self.world.get_location(loc, self.player)) + state = self.world.get_all_state(False) + self.world.random.shuffle(badges) + self.world.random.shuffle(badgelocs) + fill_restrictive(self.world, state, badgelocs.copy(), badges, True, True) + except FillError: + for location in badgelocs: + location.item = None + continue + break + else: + raise FillError(f"Failed to place badges for player {self.player}") + + locs = [self.world.get_location("Fossil - Choice A", self.player), + self.world.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") + + loc = self.world.get_location("Pallet Town - Player's PC", self.player) + if loc.item is None: + locs.append(loc) + + for loc in locs: + unplaced_items = [] + if loc.name in self.world.priority_locations[self.player].value: + add_item_rule(loc, lambda i: i.advancement) + for item in self.world.itempool: + if item.player == self.player and loc.item_rule(item): + self.world.itempool.remove(item) + state = sweep_from_pool(self.world.state, self.world.itempool + unplaced_items) + if state.can_reach(loc, "Location", self.player): + loc.place_locked_item(item) + break + else: + unplaced_items.append(item) + self.world.itempool += unplaced_items + + intervene = False + test_state = self.world.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.world.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.world.get_location("Route 1 - Wild Pokemon - 1", self.player) + loc.item = self.create_item("Mew") + + def create_regions(self): + if self.world.free_fly_location[self.player].value: + fly_map_code = self.world.random.randint(5, 9) + if fly_map_code == 9: + fly_map_code = 10 + if fly_map_code == 5: + fly_map_code = 4 + else: + fly_map_code = 0 + self.fly_map = ["Pallet Town", "Viridian City", "Pewter City", "Cerulean City", "Lavender Town", + "Vermilion City", "Celadon City", "Fuchsia City", "Cinnabar Island", "Indigo Plateau", + "Saffron City"][fly_map_code] + self.fly_map_code = fly_map_code + create_regions(self.world, self.player) + self.world.completion_condition[self.player] = lambda state, player=self.player: state.has("Become Champion", player=player) + + def set_rules(self): + set_rules(self.world, self.player) + + def create_item(self, name: str) -> Item: + return PokemonRBItem(name, self.player) + + def generate_output(self, output_directory: str): + generate_output(self, output_directory) + + def write_spoiler_header(self, spoiler_handle: TextIO): + if self.world.free_fly_location[self.player].value: + spoiler_handle.write('Fly unlocks: %s\n' % self.fly_map) + if self.extra_badges: + for hm_move, badge in self.extra_badges.items(): + spoiler_handle.write(hm_move + " enabled by: " + (" " * 20)[:20 - len(hm_move)] + badge + "\n") + + def write_spoiler(self, spoiler_handle): + if self.world.randomize_type_matchup_types[self.player].value or \ + self.world.randomize_type_matchup_type_effectiveness[self.player].value: + spoiler_handle.write(f"\n\nType matchups ({self.world.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") + + def get_filler_item_name(self) -> str: + return self.world.random.choice([item for item in item_table if item_table[item].classification in + [ItemClassification.filler, ItemClassification.trap]]) + + +class PokemonRBItem(Item): + game = "Pokemon Red and Blue" + type = None + + def __init__(self, name, player: int = None): + item_data = item_table[name] + super(PokemonRBItem, self).__init__( + name, + item_data.classification, + item_data.id, player + ) diff --git a/worlds/pokemon_rb/basepatch_blue.bsdiff4 b/worlds/pokemon_rb/basepatch_blue.bsdiff4 new file mode 100644 index 0000000000000000000000000000000000000000..c688ebede013ea52b66bb5629fc26a5a07b05719 GIT binary patch literal 29178 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

Sc+Mkq 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 n2Qpk6J

:` on the textfield on top and press enter (if the +server uses password, type in the bottom textfield `/connect
: [password]`) + +Now you are ready to start your adventure in Kanto. diff --git a/worlds/pokemon_rb/items.py b/worlds/pokemon_rb/items.py new file mode 100644 index 00000000..53722c02 --- /dev/null +++ b/worlds/pokemon_rb/items.py @@ -0,0 +1,176 @@ +from BaseClasses import ItemClassification +from .poke_data import pokemon_data + +class ItemData: + def __init__(self, id, classification, groups): + self.groups = groups + self.classification = classification + self.id = None if id is None else id + 172000000 + +item_table = { + "Master Ball": ItemData(1, ItemClassification.useful, ["Consumables", "Poke Balls"]), + "Ultra Ball": ItemData(2, ItemClassification.filler, ["Consumables", "Poke Balls"]), + "Great Ball": ItemData(3, ItemClassification.filler, ["Consumables", "Poke Balls"]), + "Poke Ball": ItemData(4, ItemClassification.filler, ["Consumables", "Poke Balls"]), + "Town Map": ItemData(5, ItemClassification.progression_skip_balancing, ["Unique", "Key Items"]), + "Bicycle": ItemData(6, ItemClassification.progression, ["Unique", "Key Items"]), + # "Flippers": ItemData(7, ItemClassification.progression), + #"Safari Ball": ItemData(8, ItemClassification.filler), + #"Pokedex": ItemData(9, ItemClassification.filler), + "Moon Stone": ItemData(10, ItemClassification.useful, ["Unique", "Evolution Stones"]), + "Antidote": ItemData(11, ItemClassification.filler, ["Consumables"]), + "Burn Heal": ItemData(12, ItemClassification.filler, ["Consumables"]), + "Ice Heal": ItemData(13, ItemClassification.filler, ["Consumables"]), + "Awakening": ItemData(14, ItemClassification.filler, ["Consumables"]), + "Paralyze Heal": ItemData(15, ItemClassification.filler, ["Consumables"]), + "Full Restore": ItemData(16, ItemClassification.filler, ["Consumables"]), + "Max Potion": ItemData(17, ItemClassification.filler, ["Consumables"]), + "Hyper Potion": ItemData(18, ItemClassification.filler, ["Consumables"]), + "Super Potion": ItemData(19, ItemClassification.filler, ["Consumables"]), + "Potion": ItemData(20, ItemClassification.filler, ["Consumables"]), + "Boulder Badge": ItemData(21, ItemClassification.progression, ["Unique", "Key Items", "Badges"]), + "Cascade Badge": ItemData(22, ItemClassification.progression, ["Unique", "Key Items", "Badges"]), + "Thunder Badge": ItemData(23, ItemClassification.progression, ["Unique", "Key Items", "Badges"]), + "Rainbow Badge": ItemData(24, ItemClassification.progression, ["Unique", "Key Items", "Badges"]), + "Soul Badge": ItemData(25, ItemClassification.progression, ["Unique", "Key Items", "Badges"]), + "Marsh Badge": ItemData(26, ItemClassification.progression, ["Unique", "Key Items", "Badges"]), + "Volcano Badge": ItemData(27, ItemClassification.progression, ["Unique", "Key Items", "Badges"]), + "Earth Badge": ItemData(28, ItemClassification.progression, ["Unique", "Key Items", "Badges"]), + "Escape Rope": ItemData(29, ItemClassification.filler, ["Consumables"]), + "Repel": ItemData(30, ItemClassification.filler, ["Consumables"]), + "Old Amber": ItemData(31, ItemClassification.progression_skip_balancing, ["Unique", "Fossils"]), + "Fire Stone": ItemData(32, ItemClassification.useful, ["Unique", "Evolution Stones"]), + "Thunder Stone": ItemData(33, ItemClassification.useful, ["Unique", "Evolution Stones"]), + "Water Stone": ItemData(34, ItemClassification.useful, ["Unique", "Evolution Stones"]), + "HP Up": ItemData(35, ItemClassification.filler, ["Consumables", "Vitamins"]), + "Protein": ItemData(36, ItemClassification.filler, ["Consumables", "Vitamins"]), + "Iron": ItemData(37, ItemClassification.filler, ["Consumables", "Vitamins"]), + "Carbos": ItemData(38, ItemClassification.filler, ["Consumables", "Vitamins"]), + "Calcium": ItemData(39, ItemClassification.filler, ["Consumables", "Vitamins"]), + "Rare Candy": ItemData(40, ItemClassification.useful, ["Consumables"]), + "Dome Fossil": ItemData(41, ItemClassification.progression_skip_balancing, ["Unique", "Fossils"]), + "Helix Fossil": ItemData(42, ItemClassification.progression_skip_balancing, ["Unique", "Fossils"]), + "Secret Key": ItemData(43, ItemClassification.progression, ["Unique", "Key Items"]), + "Bike Voucher": ItemData(45, ItemClassification.progression, ["Unique", "Key Items"]), + "X Accuracy": ItemData(46, ItemClassification.filler, ["Consumables", "Battle Items"]), + "Leaf Stone": ItemData(47, ItemClassification.useful, ["Unique", "Evolution Stones"]), + "Card Key": ItemData(48, ItemClassification.progression, ["Unique", "Key Items"]), + "Nugget": ItemData(49, ItemClassification.filler, []), + #"Laptop": ItemData(50, ItemClassification.useful, ["Unique"]), + "Poke Doll": ItemData(51, ItemClassification.filler, ["Consumables"]), + "Full Heal": ItemData(52, ItemClassification.filler, ["Consumables"]), + "Revive": ItemData(53, ItemClassification.filler, ["Consumables"]), + "Max Revive": ItemData(54, ItemClassification.filler, ["Consumables"]), + "Guard Spec": ItemData(55, ItemClassification.filler, ["Consumables", "Battle Items"]), + "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), + "Fresh Water": ItemData(60, ItemClassification.filler, ["Consumables"]), + "Soda Pop": ItemData(61, ItemClassification.filler, ["Consumables"]), + "Lemonade": ItemData(62, ItemClassification.filler, ["Consumables"]), + "S.S. Ticket": ItemData(63, ItemClassification.progression, ["Unique", "Key Items"]), + "Gold Teeth": ItemData(64, ItemClassification.progression, ["Unique", "Key Items"]), + "X Attack": ItemData(65, ItemClassification.filler, ["Consumables", "Battle Items"]), + "X Defend": ItemData(66, ItemClassification.filler, ["Consumables", "Battle Items"]), + "X Speed": ItemData(67, ItemClassification.filler, ["Consumables", "Battle Items"]), + "X Special": ItemData(68, ItemClassification.filler, ["Consumables", "Battle Items"]), + "Coin Case": ItemData(69, ItemClassification.progression_skip_balancing, ["Unique", "Key Items"]), + "Oak's Parcel": ItemData(70, ItemClassification.progression, ["Unique", "Key Items"]), + "Item Finder": ItemData(71, ItemClassification.progression, ["Unique", "Key Items"]), + "Silph Scope": ItemData(72, ItemClassification.progression, ["Unique", "Key Items"]), + "Poke Flute": ItemData(73, ItemClassification.progression, ["Unique", "Key Items"]), + "Lift Key": ItemData(74, ItemClassification.progression, ["Unique", "Key Items"]), + "Exp. All": ItemData(75, ItemClassification.useful, ["Unique"]), + "Old Rod": ItemData(76, ItemClassification.progression_skip_balancing, ["Unique", "Key Items", "Rods"]), + "Good Rod": ItemData(77, ItemClassification.progression_skip_balancing, ["Unique", "Key Items", "Rods"]), + "Super Rod": ItemData(78, ItemClassification.progression_skip_balancing, ["Unique", "Key Items", "Rods"]), + "PP Up": ItemData(79, ItemClassification.filler, ["Consumables"]), + "Ether": ItemData(80, ItemClassification.filler, ["Consumables"]), + "Max Ether": ItemData(81, ItemClassification.filler, ["Consumables"]), + "Elixir": ItemData(82, ItemClassification.filler, ["Consumables"]), + "Max Elixir": ItemData(83, ItemClassification.filler, ["Consumables"]), + "Tea": ItemData(84, ItemClassification.progression, ["Unique", "Key Items"]), + # "Master Sword": ItemData(85, ItemClassification.progression), + # "Flute": ItemData(86, ItemClassification.progression), + # "Titan's Mitt": ItemData(87, ItemClassification.progression), + # "Lamp": ItemData(88, ItemClassification.progression), + "Plant Key": ItemData(89, ItemClassification.progression, ["Unique", "Key Items"]), + "Mansion Key": ItemData(90, ItemClassification.progression, ["Unique", "Key Items"]), + "Hideout Key": ItemData(91, ItemClassification.progression, ["Unique", "Key Items"]), + "Safari Pass": ItemData(93, ItemClassification.progression, ["Unique", "Key Items"]), + "HM01 Cut": ItemData(196, ItemClassification.progression, ["Unique", "HMs"]), + "HM02 Fly": ItemData(197, ItemClassification.progression, ["Unique", "HMs"]), + "HM03 Surf": ItemData(198, ItemClassification.progression, ["Unique", "HMs"]), + "HM04 Strength": ItemData(199, ItemClassification.progression, ["Unique", "HMs"]), + "HM05 Flash": ItemData(200, ItemClassification.progression, ["Unique", "HMs"]), + "TM01 Mega Punch": ItemData(201, ItemClassification.useful, ["Unique", "TMs"]), + "TM02 Razor Wind": ItemData(202, ItemClassification.useful, ["Unique", "TMs"]), + "TM03 Swords Dance": ItemData(203, ItemClassification.useful, ["Unique", "TMs"]), + "TM04 Whirlwind": ItemData(204, ItemClassification.filler, ["Unique", "TMs"]), + "TM05 Mega Kick": ItemData(205, ItemClassification.useful, ["Unique", "TMs"]), + "TM06 Toxic": ItemData(206, ItemClassification.useful, ["Unique", "TMs"]), + "TM07 Horn Drill": ItemData(207, ItemClassification.useful, ["Unique", "TMs"]), + "TM08 Body Slam": ItemData(208, ItemClassification.useful, ["Unique", "TMs"]), + "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"]), + "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"]), + "TM16 Pay Day": ItemData(216, ItemClassification.useful, ["Unique", "TMs"]), + "TM17 Submission": ItemData(217, ItemClassification.useful, ["Unique", "TMs"]), + "TM18 Counter": ItemData(218, ItemClassification.filler, ["Unique", "TMs"]), + "TM19 Seismic Toss": ItemData(219, ItemClassification.useful, ["Unique", "TMs"]), + "TM20 Rage": ItemData(220, ItemClassification.useful, ["Unique", "TMs"]), + "TM21 Mega Drain": ItemData(221, ItemClassification.useful, ["Unique", "TMs"]), + "TM22 Solar Beam": ItemData(222, ItemClassification.useful, ["Unique", "TMs"]), + "TM23 Dragon Rage": ItemData(223, ItemClassification.useful, ["Unique", "TMs"]), + "TM24 Thunderbolt": ItemData(224, ItemClassification.useful, ["Unique", "TMs"]), + "TM25 Thunder": ItemData(225, ItemClassification.useful, ["Unique", "TMs"]), + "TM26 Earthquake": ItemData(226, ItemClassification.useful, ["Unique", "TMs"]), + "TM27 Fissure": ItemData(227, ItemClassification.useful, ["Unique", "TMs"]), + "TM28 Dig": ItemData(228, ItemClassification.useful, ["Unique", "TMs"]), + "TM29 Psychic": ItemData(229, ItemClassification.useful, ["Unique", "TMs"]), + "TM30 Teleport": ItemData(230, ItemClassification.filler, ["Unique", "TMs"]), + "TM31 Mimic": ItemData(231, ItemClassification.useful, ["Unique", "TMs"]), + "TM32 Double Team": ItemData(232, ItemClassification.useful, ["Unique", "TMs"]), + "TM33 Reflect": ItemData(233, ItemClassification.useful, ["Unique", "TMs"]), + "TM34 Bide": ItemData(234, ItemClassification.filler, ["Unique", "TMs"]), + "TM35 Metronome": ItemData(235, ItemClassification.useful, ["Unique", "TMs"]), + "TM36 Self Destruct": ItemData(236, ItemClassification.useful, ["Unique", "TMs"]), + "TM37 Egg Bomb": ItemData(237, ItemClassification.useful, ["Unique", "TMs"]), + "TM38 Fire Blast": ItemData(238, ItemClassification.useful, ["Unique", "TMs"]), + "TM39 Swift": ItemData(239, ItemClassification.useful, ["Unique", "TMs"]), + "TM40 Skull Bash": ItemData(240, ItemClassification.filler, ["Unique", "TMs"]), + "TM41 Soft Boiled": ItemData(241, ItemClassification.useful, ["Unique", "TMs"]), + "TM42 Dream Eater": ItemData(242, ItemClassification.useful, ["Unique", "TMs"]), + "TM43 Sky Attack": ItemData(243, ItemClassification.filler, ["Unique", "TMs"]), + "TM44 Rest": ItemData(244, ItemClassification.useful, ["Unique", "TMs"]), + "TM45 Thunder Wave": ItemData(245, ItemClassification.useful, ["Unique", "TMs"]), + "TM46 Psywave": ItemData(246, ItemClassification.filler, ["Unique", "TMs"]), + "TM47 Explosion": ItemData(247, ItemClassification.useful, ["Unique", "TMs"]), + "TM48 Rock Slide": ItemData(248, ItemClassification.useful, ["Unique", "TMs"]), + "TM49 Tri Attack": ItemData(249, ItemClassification.useful, ["Unique", "TMs"]), + "TM50 Substitute": ItemData(250, ItemClassification.useful, ["Unique", "TMs"]), + + "Fuji Saved": ItemData(None, ItemClassification.progression, []), + "Silph Co Liberated": ItemData(None, ItemClassification.progression, []), + "Become Champion": ItemData(None, ItemClassification.progression, []) +} +item_table.update( + {pokemon: ItemData(None, ItemClassification.progression, []) for pokemon in pokemon_data.keys()} +) +item_table.update( + {f"Missable {pokemon}": ItemData(None, ItemClassification.useful, []) for pokemon in pokemon_data.keys()} +) +item_table.update( + {f"Static {pokemon}": ItemData(None, ItemClassification.progression, []) for pokemon in pokemon_data.keys()} +) + + +item_groups = {} +for item, data in item_table.items(): + for group in data.groups: + item_groups[group] = item_groups.get(group, []) + [item] \ No newline at end of file diff --git a/worlds/pokemon_rb/locations.py b/worlds/pokemon_rb/locations.py new file mode 100644 index 00000000..a619336f --- /dev/null +++ b/worlds/pokemon_rb/locations.py @@ -0,0 +1,1719 @@ + +from BaseClasses import Location +from .rom_addresses import rom_addresses +loc_id_start = 17200000 + +class LocationData: + def __init__(self, region, name, original_item, rom_address=None, ram_address=None, event=False, type="Item"): + self.region = region + if "Route" in region: + region = " ".join(region.split()[:2]) + self.name = region + " - " + name + self.original_item = original_item + self.rom_address = rom_address + self.ram_address = ram_address + self.event = event + self.type = type + +class EventFlag: + def __init__(self, flag): + self.byte = int(flag / 8) + self.bit = flag % 8 + self.flag = flag + + +class Missable: + def __init__(self, flag): + self.byte = int(flag / 8) + self.bit = flag % 8 + self.flag = flag + + +class Hidden: + def __init__(self, flag): + self.byte = int(flag / 8) + self.bit = flag % 8 + self.flag = flag + + +class Rod: + def __init__(self, flag): + self.byte = 0 + self.bit = flag + self.flag = flag + +# def get_locations(player=None): +location_data = [ + + LocationData("Vermilion City", "Fishing Guru", "Old Rod", rom_addresses["Rod_Vermilion_City_Fishing_Guru"], Rod(3)), + LocationData("Fuchsia City", "Fishing Guru's Brother", "Good Rod", rom_addresses["Rod_Fuchsia_City_Fishing_Brother"], Rod(4)), + LocationData("Route 12 South", "Fishing Guru's Brother", "Super Rod", rom_addresses["Rod_Route12_Fishing_Brother"], Rod(5)), + + LocationData("Pallet Town", "Player's PC", "Potion", rom_addresses['PC_Item'], EventFlag(1),), + LocationData("Celadon City", "Mansion Lady", "Tea", rom_addresses["Event_Mansion_Lady"], EventFlag(2)), + LocationData("Pallet Town", "Rival's Sister", "Town Map", rom_addresses["Event_Rivals_Sister"], EventFlag(24)), + LocationData("Pallet Town", "Oak's Post-Route-22-Rival Gift", "Poke Ball", rom_addresses["Event_Oaks_Gift"], EventFlag(36)), + LocationData("Route 1", "Free Sample Man", "Potion", rom_addresses["Event_Free_Sample"], EventFlag(960)), + LocationData("Viridian City", "Sleepy Guy", "TM42 Dream Eater", rom_addresses["Event_Sleepy_Guy"], + EventFlag(41)), + LocationData("Viridian City", "Pokemart", "Oak's Parcel", rom_addresses["Event_Pokemart_Quest"], + EventFlag(57)), + LocationData("Viridian Gym", "Giovanni 2", "TM27 Fissure", rom_addresses["Event_Viridian_Gym"], EventFlag(80)), + LocationData("Route 2 East", "Oak's Aide", "HM05 Flash", rom_addresses["Event_Route_2_Oaks_Aide"], + EventFlag(984)), + LocationData("Pewter City", "Museum", "Old Amber", rom_addresses["Event_Museum"], EventFlag(105)), + LocationData("Pewter Gym", "Brock 2", "TM34 Bide", rom_addresses["Event_Pewter_Gym"], EventFlag(118)), + LocationData("Cerulean City", "Bicycle Shop", "Bicycle", rom_addresses["Event_Bicycle_Shop"], EventFlag(192)), + LocationData("Cerulean Gym", "Misty 2", "TM11 Bubble Beam", rom_addresses["Event_Cerulean_Gym"], + EventFlag(190)), + LocationData("Route 24", "Nugget Bridge", "Nugget", rom_addresses["Event_Nugget_Bridge"], EventFlag(1344)), + LocationData("Route 25", "Bill", "S.S. Ticket", rom_addresses["Event_Bill"], EventFlag(1372)), + LocationData("Lavender Town", "Mr. Fuji", "Poke Flute", rom_addresses["Event_Fuji"], EventFlag(296)), + LocationData("Route 12 North", "Mourning Girl", "TM39 Swift", rom_addresses["Event_Mourning_Girl"], + EventFlag(1152)), + LocationData("Vermilion City", "Pokemon Fan Club", "Bike Voucher", rom_addresses["Event_Pokemon_Fan_Club"], + EventFlag(337)), + LocationData("Vermilion Gym", "Lt. Surge 2", "TM24 Thunderbolt", rom_addresses["Event_Vermillion_Gym"], + EventFlag(358)), + LocationData("S.S. Anne 2F", "Captain", "HM01 Cut", rom_addresses["Event_SS_Anne_Captain"], EventFlag(1504)), + LocationData("Route 11 East", "Oak's Aide", "Item Finder", rom_addresses["Event_Rt11_Oaks_Aide"], + EventFlag(1151)), + LocationData("Celadon City", "Stranded Man", "TM41 Soft Boiled", rom_addresses["Event_Stranded_Man"], + EventFlag(384)), + LocationData("Celadon City", "Thirsty Girl Gets Water", "TM13 Ice Beam", + rom_addresses["Event_Thirsty_Girl_Water"], EventFlag(396)), + LocationData("Celadon City", "Thirsty Girl Gets Soda Pop", "TM48 Rock Slide", + rom_addresses["Event_Thirsty_Girl_Soda"], EventFlag(397)), + LocationData("Celadon City", "Thirsty Girl Gets Lemonade", "TM49 Tri Attack", + rom_addresses["Event_Thirsty_Girl_Lemonade"], EventFlag(398)), + LocationData("Celadon City", "Counter Man", "TM18 Counter", rom_addresses["Event_Counter"], EventFlag(399)), + 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"], + EventFlag(1933)), + LocationData("Silph Co 2F", "Woman", "TM36 Self Destruct", rom_addresses["Event_Scared_Woman"], + EventFlag(1791)), + LocationData("Route 16 North", "House Woman", "HM02 Fly", rom_addresses["Event_Rt16_House_Woman"], EventFlag(1230)), + LocationData("Route 15", "Oak's Aide", "Exp. All", rom_addresses["Event_Rt_15_Oaks_Aide"], EventFlag(1200)), + LocationData("Fuchsia City", "Safari Zone Warden", "HM04 Strength", rom_addresses["Event_Warden"], EventFlag(568)), + LocationData("Fuchsia Gym", "Koga 2", "TM06 Toxic", rom_addresses["Event_Fuschia_Gym"], EventFlag(600)), + LocationData("Safari Zone West", "Secret House", "HM03 Surf", rom_addresses["Event_Safari_Zone_Secret_House"], EventFlag(2176)), + LocationData("Cinnabar Island", "Lab Scientist", "TM35 Metronome", rom_addresses["Event_Lab_Scientist"], EventFlag(727)), + LocationData("Cinnabar Gym", "Blaine 2", "TM38 Fire Blast", rom_addresses["Event_Cinnabar_Gym"], + EventFlag(664)), + LocationData("Copycat's House", "Copycat", "TM31 Mimic", rom_addresses["Event_Copycat"], EventFlag(832)), + LocationData("Saffron City", "Mr. Psychic", "TM29 Psychic", rom_addresses["Event_Mr_Psychic"], EventFlag(944)), + LocationData("Saffron Gym", "Sabrina 2", "TM46 Psywave", rom_addresses["Event_Saffron_Gym"], EventFlag(864)), + LocationData("Fossil", "Choice A", "Dome Fossil", + [rom_addresses["Event_Dome_Fossil"], rom_addresses["Event_Dome_Fossil_B"], + rom_addresses["Dome_Fossil_Text"]], EventFlag(0x57E)), + LocationData("Fossil", "Choice B", "Helix Fossil", + [rom_addresses["Event_Helix_Fossil"], rom_addresses["Event_Helix_Fossil_B"], + rom_addresses["Helix_Fossil_Text"]], EventFlag(0x57F)), + + LocationData("Cerulean City", "Rocket Thief", "TM28 Dig", rom_addresses["Event_Rocket_Thief"], + Missable(6)), + LocationData("Route 2 East", "South Item", "Moon Stone", rom_addresses["Missable_Route_2_Item_1"], + Missable(25)), + LocationData("Route 2 East", "North Item", "HP Up", rom_addresses["Missable_Route_2_Item_2"], Missable(26)), + LocationData("Route 4", "Item", "TM04 Whirlwind", rom_addresses["Missable_Route_4_Item"], Missable(27)), + LocationData("Route 9", "Item", "TM30 Teleport", rom_addresses["Missable_Route_9_Item"], Missable(28)), + LocationData("Route 12 North", "Island Item", "TM16 Pay Day", rom_addresses["Missable_Route_12_Item_1"], Missable(30)), + LocationData("Route 12 South", "Item Behind Cuttable Tree", "Iron", rom_addresses["Missable_Route_12_Item_2"], Missable(31)), + LocationData("Route 15", "Item", "TM20 Rage", rom_addresses["Missable_Route_15_Item"], Missable(32)), + LocationData("Route 24", "Item", "TM45 Thunder Wave", rom_addresses["Missable_Route_24_Item"], Missable(37)), + LocationData("Route 25", "Item", "TM19 Seismic Toss", rom_addresses["Missable_Route_25_Item"], Missable(38)), + LocationData("Viridian Gym", "Item", "Revive", rom_addresses["Missable_Viridian_Gym_Item"], Missable(51)), + LocationData("Cerulean Cave 1F", "Southwest Item", "Full Restore", rom_addresses["Missable_Cerulean_Cave_1F_Item_1"], + Missable(53)), + LocationData("Cerulean Cave 1F", "Northeast Item", "Max Elixir", rom_addresses["Missable_Cerulean_Cave_1F_Item_2"], + Missable(54)), + LocationData("Cerulean Cave 1F", "Northwest Item", "Nugget", rom_addresses["Missable_Cerulean_Cave_1F_Item_3"], + Missable(55)), + LocationData("Pokemon Tower 3F", "North Item", "Escape Rope", rom_addresses["Missable_Pokemon_Tower_3F_Item"], + Missable(57)), + LocationData("Pokemon Tower 4F", "East Item", "Elixir", rom_addresses["Missable_Pokemon_Tower_4F_Item_1"], + Missable(58)), + LocationData("Pokemon Tower 4F", "West Item", "Awakening", rom_addresses["Missable_Pokemon_Tower_4F_Item_2"], + Missable(59)), + LocationData("Pokemon Tower 4F", "South Item", "HP Up", rom_addresses["Missable_Pokemon_Tower_4F_Item_3"], + Missable(60)), + LocationData("Pokemon Tower 5F", "Southwest Item", "Nugget", rom_addresses["Missable_Pokemon_Tower_5F_Item"], + Missable(61)), + LocationData("Pokemon Tower 6F", "West Item", "Rare Candy", rom_addresses["Missable_Pokemon_Tower_6F_Item_1"], + Missable(62)), + LocationData("Pokemon Tower 6F", "Southeast Item", "X Accuracy", rom_addresses["Missable_Pokemon_Tower_6F_Item_2"], + Missable(63)), + LocationData("Fuchsia City", "Warden's House Item", "Rare Candy", rom_addresses["Missable_Wardens_House_Item"], + Missable(71)), + LocationData("Pokemon Mansion 1F", "North Item", "Escape Rope", + rom_addresses["Missable_Pokemon_Mansion_1F_Item_1"], Missable(72)), + LocationData("Pokemon Mansion 1F", "South Item", "Carbos", rom_addresses["Missable_Pokemon_Mansion_1F_Item_2"], + Missable(73)), + LocationData("Power Plant", "Southwest Item", "Carbos", rom_addresses["Missable_Power_Plant_Item_1"], Missable(86)), + LocationData("Power Plant", "North Item", "HP Up", rom_addresses["Missable_Power_Plant_Item_2"], Missable(87)), + LocationData("Power Plant", "Northeast Item", "Rare Candy", rom_addresses["Missable_Power_Plant_Item_3"], + Missable(88)), + LocationData("Power Plant", "Southeast Item", "TM25 Thunder", rom_addresses["Missable_Power_Plant_Item_4"], + Missable(89)), + LocationData("Power Plant", "South Item", "TM33 Reflect", rom_addresses["Missable_Power_Plant_Item_5"], + Missable(90)), + LocationData("Victory Road 2F", "Northeast Item", "TM17 Submission", rom_addresses["Missable_Victory_Road_2F_Item_1"], + Missable(92)), + LocationData("Victory Road 2F", "East Item", "Full Heal", rom_addresses["Missable_Victory_Road_2F_Item_2"], + Missable(93)), + LocationData("Victory Road 2F", "West Item", "TM05 Mega Kick", rom_addresses["Missable_Victory_Road_2F_Item_3"], + Missable(94)), + LocationData("Victory Road 2F", "North Item Near Moltres", "Guard Spec", rom_addresses["Missable_Victory_Road_2F_Item_4"], + Missable(95)), + LocationData("Viridian Forest", "East Item", "Antidote", rom_addresses["Missable_Viridian_Forest_Item_1"], + Missable(100)), + LocationData("Viridian Forest", "Northwest Item", "Potion", rom_addresses["Missable_Viridian_Forest_Item_2"], + Missable(101)), + LocationData("Viridian Forest", "Southwest Item", "Poke Ball", + rom_addresses["Missable_Viridian_Forest_Item_3"], Missable(102)), + LocationData("Mt Moon 1F", "West Item", "Potion", rom_addresses["Missable_Mt_Moon_1F_Item_1"], Missable(103)), + LocationData("Mt Moon 1F", "Northwest Item", "Moon Stone", rom_addresses["Missable_Mt_Moon_1F_Item_2"], Missable(104)), + LocationData("Mt Moon 1F", "Southeast Item", "Rare Candy", rom_addresses["Missable_Mt_Moon_1F_Item_3"], Missable(105)), + LocationData("Mt Moon 1F", "East Item", "Escape Rope", rom_addresses["Missable_Mt_Moon_1F_Item_4"], + Missable(106)), + LocationData("Mt Moon 1F", "South Item", "Potion", rom_addresses["Missable_Mt_Moon_1F_Item_5"], Missable(107)), + LocationData("Mt Moon 1F", "Southwest Item", "TM12 Water Gun", rom_addresses["Missable_Mt_Moon_1F_Item_6"], + Missable(108)), + LocationData("Mt Moon B2F", "South Item", "HP Up", rom_addresses["Missable_Mt_Moon_B2F_Item_1"], Missable(111)), + LocationData("Mt Moon B2F", "North Item", "TM01 Mega Punch", rom_addresses["Missable_Mt_Moon_B2F_Item_2"], + Missable(112)), + LocationData("S.S. Anne 1F", "Item", "TM08 Body Slam", rom_addresses["Missable_SS_Anne_1F_Item"], + Missable(114)), + LocationData("S.S. Anne 2F", "Item 1", "Max Ether", rom_addresses["Missable_SS_Anne_2F_Item_1"], + Missable(115)), + LocationData("S.S. Anne 2F", "Item 2", "Rare Candy", rom_addresses["Missable_SS_Anne_2F_Item_2"], + Missable(116)), + LocationData("S.S. Anne B1F", "Item 1", "Ether", rom_addresses["Missable_SS_Anne_B1F_Item_1"], Missable(117)), + LocationData("S.S. Anne B1F", "Item 2", "TM44 Rest", rom_addresses["Missable_SS_Anne_B1F_Item_2"], + Missable(118)), + LocationData("S.S. Anne B1F", "Item 3", "Max Potion", rom_addresses["Missable_SS_Anne_B1F_Item_3"], + Missable(119)), + LocationData("Victory Road 3F", "Northeast Item", "Max Revive", rom_addresses["Missable_Victory_Road_3F_Item_1"], + Missable(120)), + LocationData("Victory Road 3F", "Northwest Item", "TM47 Explosion", rom_addresses["Missable_Victory_Road_3F_Item_2"], + Missable(121)), + LocationData("Rocket Hideout B1F", "West Item", "Escape Rope", + rom_addresses["Missable_Rocket_Hideout_B1F_Item_1"], Missable(123)), + LocationData("Rocket Hideout B1F", "Southwest Item", "Hyper Potion", + rom_addresses["Missable_Rocket_Hideout_B1F_Item_2"], Missable(124)), + LocationData("Rocket Hideout B2F", "Northwest Left Item", "Moon Stone", rom_addresses["Missable_Rocket_Hideout_B2F_Item_1"], + Missable(125)), + LocationData("Rocket Hideout B2F", "Northeast Item", "Nugget", rom_addresses["Missable_Rocket_Hideout_B2F_Item_2"], + Missable(126)), + LocationData("Rocket Hideout B2F", "Northwest Right Item", "TM07 Horn Drill", + rom_addresses["Missable_Rocket_Hideout_B2F_Item_3"], Missable(127)), + LocationData("Rocket Hideout B2F", "Southwest Item", "Super Potion", + rom_addresses["Missable_Rocket_Hideout_B2F_Item_4"], Missable(128)), + LocationData("Rocket Hideout B3F", "East Item", "TM10 Double Edge", + rom_addresses["Missable_Rocket_Hideout_B3F_Item_1"], Missable(129)), + LocationData("Rocket Hideout B3F", "Center Item", "Rare Candy", rom_addresses["Missable_Rocket_Hideout_B3F_Item_2"], + Missable(130)), + LocationData("Rocket Hideout B4F", "West Item", "HP Up", rom_addresses["Missable_Rocket_Hideout_B4F_Item_1"], + Missable(132)), + LocationData("Rocket Hideout B4F", "Northwest Item", "TM02 Razor Wind", + rom_addresses["Missable_Rocket_Hideout_B4F_Item_2"], Missable(133)), + LocationData("Rocket Hideout B4F", "Southwest Item (Lift Key)", "Iron", rom_addresses["Missable_Rocket_Hideout_B4F_Item_3"], + Missable(134)), + LocationData("Rocket Hideout B4F", "Giovanni Item (Lift Key)", "Silph Scope", + rom_addresses["Missable_Rocket_Hideout_B4F_Item_4"], [EventFlag(0x6A7), Missable(135)]), + LocationData("Rocket Hideout B4F", "Rocket Grunt Item", "Lift Key", rom_addresses["Missable_Rocket_Hideout_B4F_Item_5"], + [EventFlag(0x6A6), Missable(136)]), + LocationData("Silph Co 3F", "Item (Card Key)", "Hyper Potion", rom_addresses["Missable_Silph_Co_3F_Item"], Missable(144)), + LocationData("Silph Co 4F", "Left Item (Card Key)", "Full Heal", rom_addresses["Missable_Silph_Co_4F_Item_1"], + Missable(148)), + LocationData("Silph Co 4F", "Middle Item (Card Key)", "Max Revive", rom_addresses["Missable_Silph_Co_4F_Item_2"], + Missable(149)), + LocationData("Silph Co 4F", "Right Item (Card Key)", "Escape Rope", rom_addresses["Missable_Silph_Co_4F_Item_3"], + Missable(150)), + LocationData("Silph Co 5F", "Southwest Item", "TM09 Take Down", rom_addresses["Missable_Silph_Co_5F_Item_1"], + Missable(155)), + LocationData("Silph Co 5F", "Northwest Item (Card Key)", "Protein", rom_addresses["Missable_Silph_Co_5F_Item_2"], Missable(156)), + LocationData("Silph Co 5F", "Southeast Item", "Card Key", rom_addresses["Missable_Silph_Co_5F_Item_3"], Missable(157)), + LocationData("Silph Co 6F", "West Item (Card Key)", "HP Up", rom_addresses["Missable_Silph_Co_6F_Item_1"], Missable(161)), + LocationData("Silph Co 6F", "Southwest Item (Card Key)", "X Accuracy", rom_addresses["Missable_Silph_Co_6F_Item_2"], + Missable(162)), + LocationData("Silph Co 7F", "West Item", "Calcium", rom_addresses["Missable_Silph_Co_7F_Item_1"], Missable(168)), + LocationData("Silph Co 7F", "East Item (Card Key)", "TM03 Swords Dance", rom_addresses["Missable_Silph_Co_7F_Item_2"], + Missable(169)), + LocationData("Silph Co 10F", "Left Item", "TM26 Earthquake", rom_addresses["Missable_Silph_Co_10F_Item_1"], + Missable(180)), + LocationData("Silph Co 10F", "Bottom Item", "Rare Candy", rom_addresses["Missable_Silph_Co_10F_Item_2"], + Missable(181)), + LocationData("Silph Co 10F", "Right Item", "Carbos", rom_addresses["Missable_Silph_Co_10F_Item_3"], Missable(182)), + LocationData("Pokemon Mansion 2F", "Northeast Item", "Calcium", rom_addresses["Missable_Pokemon_Mansion_2F_Item"], + Missable(187)), + LocationData("Pokemon Mansion 3F", "Southwest Item", "Max Potion", rom_addresses["Missable_Pokemon_Mansion_3F_Item_1"], + Missable(188)), + LocationData("Pokemon Mansion 3F", "Northeast Item", "Iron", rom_addresses["Missable_Pokemon_Mansion_3F_Item_2"], + Missable(189)), + LocationData("Pokemon Mansion B1F", "North Item", "Rare Candy", + rom_addresses["Missable_Pokemon_Mansion_B1F_Item_1"], Missable(190)), + LocationData("Pokemon Mansion B1F", "Southwest Item", "Full Restore", + rom_addresses["Missable_Pokemon_Mansion_B1F_Item_2"], Missable(191)), + LocationData("Pokemon Mansion B1F", "South Item", "TM14 Blizzard", + rom_addresses["Missable_Pokemon_Mansion_B1F_Item_3"], Missable(192)), + LocationData("Pokemon Mansion B1F", "Northwest Item", "TM22 Solar Beam", + rom_addresses["Missable_Pokemon_Mansion_B1F_Item_4"], Missable(193)), + LocationData("Pokemon Mansion B1F", "West Item", "Secret Key", + rom_addresses["Missable_Pokemon_Mansion_B1F_Item_5"], Missable(194)), + LocationData("Safari Zone East", "Northeast Item", "Full Restore", rom_addresses["Missable_Safari_Zone_East_Item_1"], + Missable(195)), + LocationData("Safari Zone East", "West Item", "Max Potion", rom_addresses["Missable_Safari_Zone_East_Item_2"], + Missable(196)), + LocationData("Safari Zone East", "East Item", "Carbos", rom_addresses["Missable_Safari_Zone_East_Item_3"], + Missable(197)), + LocationData("Safari Zone East", "Center Item", "TM37 Egg Bomb", rom_addresses["Missable_Safari_Zone_East_Item_4"], + Missable(198)), + LocationData("Safari Zone North", "Northeast Item", "Protein", rom_addresses["Missable_Safari_Zone_North_Item_1"], + Missable(199)), + LocationData("Safari Zone North", "North Item", "TM40 Skull Bash", + rom_addresses["Missable_Safari_Zone_North_Item_2"], Missable(200)), + LocationData("Safari Zone West", "Southwest Item", "Max Potion", rom_addresses["Missable_Safari_Zone_West_Item_1"], + Missable(201)), + LocationData("Safari Zone West", "Northwest Item", "TM32 Double Team", + rom_addresses["Missable_Safari_Zone_West_Item_2"], Missable(202)), + LocationData("Safari Zone West", "Southeast Item", "Max Revive", rom_addresses["Missable_Safari_Zone_West_Item_3"], + Missable(203)), + LocationData("Safari Zone West", "Northeast Item", "Gold Teeth", rom_addresses["Missable_Safari_Zone_West_Item_4"], + Missable(204)), + LocationData("Safari Zone Center", "Island Item", "Nugget", rom_addresses["Missable_Safari_Zone_Center_Item"], + Missable(205)), + LocationData("Cerulean Cave 2F", "East Item", "PP Up", rom_addresses["Missable_Cerulean_Cave_2F_Item_1"], + Missable(206)), + LocationData("Cerulean Cave 2F", "Southwest Item", "Ultra Ball", rom_addresses["Missable_Cerulean_Cave_2F_Item_2"], + Missable(207)), + LocationData("Cerulean Cave 2F", "North Item", "Full Restore", rom_addresses["Missable_Cerulean_Cave_2F_Item_3"], + Missable(208)), + LocationData("Cerulean Cave B1F", "Center Item", "Ultra Ball", rom_addresses["Missable_Cerulean_Cave_B1F_Item_1"], + Missable(210)), + LocationData("Cerulean Cave B1F", "North Item", "Max Revive", rom_addresses["Missable_Cerulean_Cave_B1F_Item_2"], + Missable(211)), + LocationData("Victory Road 1F", "Top Item", "TM43 Sky Attack", rom_addresses["Missable_Victory_Road_1F_Item_1"], + Missable(212)), + LocationData("Victory Road 1F", "Left Item", "Rare Candy", rom_addresses["Missable_Victory_Road_1F_Item_2"], + Missable(213)), + LocationData("Rock Tunnel B1F", "Southwest Item", "Hideout Key", rom_addresses["Missable_Rock_Tunnel_B1F_Item_1"], + Missable(231)), + LocationData("Rock Tunnel B1F", "West Item", "Mansion Key", rom_addresses["Missable_Rock_Tunnel_B1F_Item_2"], + Missable(232)), + LocationData("Rock Tunnel B1F", "Northwest Item", "Plant Key", rom_addresses["Missable_Rock_Tunnel_B1F_Item_3"], + Missable(233)), + LocationData("Rock Tunnel B1F", "North Item", "Safari Pass", rom_addresses["Missable_Rock_Tunnel_B1F_Item_4"], + Missable(234)), + + LocationData("Pewter Gym", "Brock 1", "Boulder Badge", rom_addresses['Badge_Pewter_Gym'], EventFlag(0x8A0)), + LocationData("Cerulean Gym", "Misty 1", "Cascade Badge", rom_addresses['Badge_Cerulean_Gym'], EventFlag(0x8A1)), + LocationData("Vermilion Gym", "Lt. Surge 1", "Thunder Badge", rom_addresses['Badge_Vermilion_Gym'], EventFlag(0x8A2)), + LocationData("Celadon Gym", "Erika 1", "Rainbow Badge", rom_addresses['Badge_Celadon_Gym'], EventFlag(0x8A3)), + LocationData("Fuchsia Gym", "Koga 1", "Soul Badge", rom_addresses['Badge_Fuchsia_Gym'], EventFlag(0x8A4)), + LocationData("Saffron Gym", "Sabrina 1", "Marsh Badge", rom_addresses['Badge_Saffron_Gym'], EventFlag(0x8A5)), + LocationData("Cinnabar Gym", "Blaine 1", "Volcano Badge", rom_addresses['Badge_Cinnabar_Gym'], EventFlag(0x8A6)), + LocationData("Viridian Gym", "Giovanni 1", "Earth Badge", rom_addresses['Badge_Viridian_Gym'], EventFlag(0x8A7)), + + LocationData("Viridian Forest", "Hidden Item Northwest by Trainer", "Potion", rom_addresses['Hidden_Item_Viridian_Forest_1'], Hidden(0)), + LocationData("Viridian Forest", "Hidden Item Entrance Tree", "Antidote", rom_addresses['Hidden_Item_Viridian_Forest_2'], Hidden(1)), + LocationData("Mt Moon B2F", "Hidden Item Dead End Before Fossils", "Moon Stone", rom_addresses['Hidden_Item_MtMoonB2F_1'], Hidden(2)), + LocationData("Route 25", "Hidden Item Fence Outside Bill's House", "Ether", rom_addresses['Hidden_Item_Route_25_1'], Hidden(3)), + LocationData("Route 9", "Hidden Item Rock By Grass", "Ether", rom_addresses['Hidden_Item_Route_9'], Hidden(4)), + LocationData("S.S. Anne 1F", "Hidden Item Kitchen Trash", "Great Ball", rom_addresses['Hidden_Item_SS_Anne_Kitchen'], Hidden(5)), + LocationData("S.S. Anne B1F", "Hidden Item Under Pillow", "Hyper Potion", rom_addresses['Hidden_Item_SS_Anne_B1F'], Hidden(6)), + LocationData("Route 10 North", "Hidden Item Behind Rock Tunnel Entrance Tree", "Super Potion", rom_addresses['Hidden_Item_Route_10_1'], Hidden(7)), + LocationData("Route 10 South", "Hidden Item Rock", "Max Ether", rom_addresses['Hidden_Item_Route_10_2'], Hidden(8)), + LocationData("Rocket Hideout B1F", "Hidden Item Pot Plant", "PP Up", rom_addresses['Hidden_Item_Rocket_Hideout_B1F'], Hidden(9)), + LocationData("Rocket Hideout B3F", "Hidden Item Near East Item", "Nugget", rom_addresses['Hidden_Item_Rocket_Hideout_B3F'], Hidden(10)), + LocationData("Rocket Hideout B4F", "Hidden Item Behind Giovanni", "Super Potion", rom_addresses['Hidden_Item_Rocket_Hideout_B4F'], Hidden(11)), + LocationData("Pokemon Tower 5F", "Hidden Item Near West Staircase", "Elixir", rom_addresses['Hidden_Item_Pokemon_Tower_5F'], Hidden(12)), + LocationData("Route 13", "Hidden Item Dead End Boulder", "PP Up", rom_addresses['Hidden_Item_Route_13_1'], Hidden(13)), + LocationData("Route 13", "Hidden Item Dead End By Water Corner", "Calcium", rom_addresses['Hidden_Item_Route_13_2'], Hidden(14)), + LocationData("Pokemon Mansion B1F", "Hidden Item Secret Key Room Corner", "Rare Candy", rom_addresses['Hidden_Item_Pokemon_Mansion_B1F'], Hidden(15)), + LocationData("Safari Zone West", "Hidden Item Secret House Statue", "Revive", rom_addresses['Hidden_Item_Safari_Zone_West'], Hidden(17)), + LocationData("Silph Co 5F", "Hidden Item Pot Plant", "Elixir", rom_addresses['Hidden_Item_Silph_Co_5F'], Hidden(18)), + LocationData("Silph Co 9F", "Hidden Item Nurse Bed", "Max Potion", rom_addresses['Hidden_Item_Silph_Co_9F'], Hidden(19)), + LocationData("Copycat's House", "Hidden Item Desk", "Nugget", rom_addresses['Hidden_Item_Copycats_House'], Hidden(20)), + LocationData("Cerulean Cave 1F", "Hidden Item Center Rocks", "Rare Candy", rom_addresses['Hidden_Item_Cerulean_Cave_1F'], Hidden(21)), + LocationData("Cerulean Cave B1F", "Hidden Item Northeast Rocks", "Ultra Ball", rom_addresses['Hidden_Item_Cerulean_Cave_B1F'], Hidden(22)), + LocationData("Power Plant", "Hidden Item Central Dead End", "Max Elixir", rom_addresses['Hidden_Item_Power_Plant_1'], Hidden(23)), + LocationData("Power Plant", "Hidden Item Before Zapdos", "PP Up", rom_addresses['Hidden_Item_Power_Plant_2'], Hidden(24)), + LocationData("Seafoam Islands B2F", "Hidden Item Rock", "Nugget", rom_addresses['Hidden_Item_Seafoam_Islands_B2F'], Hidden(25)), + LocationData("Seafoam Islands B4F", "Hidden Item Corner Island", "Ultra Ball", rom_addresses['Hidden_Item_Seafoam_Islands_B4F'], Hidden(26)), + LocationData("Pokemon Mansion 1F", "Hidden Item Block Near Entrance Carpet", "Moon Stone", rom_addresses['Hidden_Item_Pokemon_Mansion_1F'], Hidden(27)), + LocationData("Pokemon Mansion 3F", "Hidden Item Behind Burglar", "Max Revive", rom_addresses['Hidden_Item_Pokemon_Mansion_3F'], Hidden(28)), + LocationData("Route 23 North", "Hidden Item Rocks Before Final Guard", "Full Restore", rom_addresses['Hidden_Item_Route_23_1'], Hidden(29)), + LocationData("Route 23 North", "Hidden Item East Tree After Water", "Ultra Ball", rom_addresses['Hidden_Item_Route_23_2'], Hidden(30)), + LocationData("Route 23 South", "Hidden Item On Island", "Max Ether", rom_addresses['Hidden_Item_Route_23_3'], Hidden(31)), + LocationData("Victory Road 2F", "Hidden Item Rock Before Moltres", "Ultra Ball", rom_addresses['Hidden_Item_Victory_Road_2F_1'], Hidden(32)), + LocationData("Victory Road 2F", "Hidden Item Rock In Final Room", "Full Restore", rom_addresses['Hidden_Item_Victory_Road_2F_2'], Hidden(33)), + #LocationData("Vermilion City", "Hidden Item The Truck", "Max Elixir", rom_addresses['Hidden_Item_Unused_6F'], Hidden(34)), + LocationData("Viridian City", "Hidden Item Cuttable Tree", "Potion", rom_addresses['Hidden_Item_Viridian_City'], Hidden(35)), + LocationData("Route 11", "Hidden Item Isolated Tree Near Gate", "Potion", rom_addresses['Hidden_Item_Route_11'], Hidden(36)), + LocationData("Route 12 West", "Hidden Item Tree Near Gate", "Hyper Potion", rom_addresses['Hidden_Item_Route_12'], Hidden(37)), + LocationData("Route 17", "Hidden Item In Grass", "Rare Candy", rom_addresses['Hidden_Item_Route_17_1'], Hidden(38)), + LocationData("Route 17", "Hidden Item Near Northernmost Sign", "Full Restore", rom_addresses['Hidden_Item_Route_17_2'], Hidden(39)), + LocationData("Route 17", "Hidden Item East Center", "PP Up", rom_addresses['Hidden_Item_Route_17_3'], Hidden(40)), + LocationData("Route 17", "Hidden Item West Center", "Max Revive", rom_addresses['Hidden_Item_Route_17_4'], Hidden(41)), + LocationData("Route 17", "Hidden Item Before Final Bridge", "Max Elixir", rom_addresses['Hidden_Item_Route_17_5'], Hidden(42)), + LocationData("Underground Tunnel North-South", "Hidden Item Near Northern Stairs", "Full Restore", rom_addresses['Hidden_Item_Underground_Path_NS_1'], Hidden(43)), + LocationData("Underground Tunnel North-South", "Hidden Item Near Southern Stairs", "X Special", rom_addresses['Hidden_Item_Underground_Path_NS_2'], Hidden(44)), + LocationData("Underground Tunnel West-East", "Hidden Item West", "Nugget", rom_addresses['Hidden_Item_Underground_Path_WE_1'], Hidden(45)), + LocationData("Underground Tunnel West-East", "Hidden Item East", "Elixir", rom_addresses['Hidden_Item_Underground_Path_WE_2'], Hidden(46)), + LocationData("Celadon City", "Hidden Item Dead End Near Cuttable Tree", "PP Up", rom_addresses['Hidden_Item_Celadon_City'], Hidden(47)), + LocationData("Route 25", "Hidden Item Northeast Of Grass", "Elixir", rom_addresses['Hidden_Item_Route_25_2'], Hidden(48)), + LocationData("Mt Moon B2F", "Hidden Item Lone Rock", "Ether", rom_addresses['Hidden_Item_MtMoonB2F_2'], Hidden(49)), + LocationData("Seafoam Islands B3F", "Hidden Item Rock", "Max Elixir", rom_addresses['Hidden_Item_Seafoam_Islands_B3F'], Hidden(50)), + LocationData("Vermilion City", "Hidden Item In Water Near Fan Club", "Max Ether", rom_addresses['Hidden_Item_Vermilion_City'], Hidden(51)), + LocationData("Cerulean City", "Hidden Item Gym Badge Guy's Backyard", "Rare Candy", rom_addresses['Hidden_Item_Cerulean_City'], Hidden(52)), + LocationData("Route 4", "Hidden Item Plateau East Of Mt Moon", "Great Ball", rom_addresses['Hidden_Item_Route_4'], Hidden(53)), + + LocationData("Indigo Plateau", "Become Champion", "Become Champion", event=True), + LocationData("Pokemon Tower 7F", "Fuji Saved", "Fuji Saved", event=True), + LocationData("Silph Co 11F", "Silph Co Liberated", "Silph Co Liberated", event=True), + + LocationData("Pallet Town", "Super Rod Pokemon - 1", "Tentacool", rom_addresses["Wild_Super_Rod_A"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Pallet Town", "Super Rod Pokemon - 2", "Poliwag", rom_addresses["Wild_Super_Rod_A"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Route 22", "Super Rod Pokemon - 1", "Goldeen", rom_addresses["Wild_Super_Rod_B"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Route 22", "Super Rod Pokemon - 2", "Poliwag", rom_addresses["Wild_Super_Rod_B"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Route 24", "Super Rod Pokemon - 1", "Psyduck", rom_addresses["Wild_Super_Rod_C"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Route 24", "Super Rod Pokemon - 2", "Goldeen", rom_addresses["Wild_Super_Rod_C"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Route 24", "Super Rod Pokemon - 3", "Krabby", rom_addresses["Wild_Super_Rod_C"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Route 6", "Super Rod Pokemon - 1", "Krabby", rom_addresses["Wild_Super_Rod_D"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Route 6", "Super Rod Pokemon - 2", "Shellder", rom_addresses["Wild_Super_Rod_D"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Route 10 North", "Super Rod Pokemon - 1", "Poliwhirl", rom_addresses["Wild_Super_Rod_E"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Route 10 North", "Super Rod Pokemon - 2", "Slowpoke", rom_addresses["Wild_Super_Rod_E"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Safari Zone Center", "Super Rod Pokemon - 1", "Dratini", rom_addresses["Wild_Super_Rod_F"] + 1, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone Center", "Super Rod Pokemon - 2", "Krabby", rom_addresses["Wild_Super_Rod_F"] + 3, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone Center", "Super Rod Pokemon - 3", "Psyduck", rom_addresses["Wild_Super_Rod_F"] + 5, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone Center", "Super Rod Pokemon - 4", "Slowpoke", rom_addresses["Wild_Super_Rod_F"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Route 12 North", "Super Rod Pokemon - 1", "Tentacool", rom_addresses["Wild_Super_Rod_G"] + 1, + None, event=True, type="Wild Encounter"), + LocationData("Route 12 North", "Super Rod Pokemon - 2", "Krabby", rom_addresses["Wild_Super_Rod_G"] + 3, + None, event=True, type="Wild Encounter"), + LocationData("Route 12 North", "Super Rod Pokemon - 3", "Goldeen", rom_addresses["Wild_Super_Rod_G"] + 5, + None, event=True, type="Wild Encounter"), + LocationData("Route 12 North", "Super Rod Pokemon - 4", "Magikarp", rom_addresses["Wild_Super_Rod_G"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Route 19", "Super Rod Pokemon - 1", "Staryu", rom_addresses["Wild_Super_Rod_H"] + 1, + None, event=True, type="Wild Encounter"), + LocationData("Route 19", "Super Rod Pokemon - 2", "Horsea", rom_addresses["Wild_Super_Rod_H"] + 3, + None, event=True, type="Wild Encounter"), + LocationData("Route 19", "Super Rod Pokemon - 3", "Shellder", rom_addresses["Wild_Super_Rod_H"] + 5, + None, event=True, type="Wild Encounter"), + LocationData("Route 19", "Super Rod Pokemon - 4", "Goldeen", rom_addresses["Wild_Super_Rod_H"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Route 23 South", "Super Rod Pokemon - 1", "Slowbro", rom_addresses["Wild_Super_Rod_I"] + 1, + None, event=True, type="Wild Encounter"), + LocationData("Route 23 South", "Super Rod Pokemon - 2", "Seaking", rom_addresses["Wild_Super_Rod_I"] + 3, + None, event=True, type="Wild Encounter"), + LocationData("Route 23 South", "Super Rod Pokemon - 3", "Kingler", rom_addresses["Wild_Super_Rod_I"] + 5, + None, event=True, type="Wild Encounter"), + LocationData("Route 23 South", "Super Rod Pokemon - 4", "Seadra", rom_addresses["Wild_Super_Rod_I"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Fuchsia City", "Super Rod Pokemon - 1", "Seaking", rom_addresses["Wild_Super_Rod_J"] + 1, + None, event=True, type="Wild Encounter"), + LocationData("Fuchsia City", "Super Rod Pokemon - 2", "Krabby", rom_addresses["Wild_Super_Rod_J"] + 3, + None, event=True, type="Wild Encounter"), + LocationData("Fuchsia City", "Super Rod Pokemon - 3", "Goldeen", rom_addresses["Wild_Super_Rod_J"] + 5, + None, event=True, type="Wild Encounter"), + LocationData("Fuchsia City", "Super Rod Pokemon - 4", "Magikarp", rom_addresses["Wild_Super_Rod_J"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Route 1", "Wild Pokemon - 1", "Pidgey", rom_addresses["Wild_Route1"] + 1, None, event=True, + type="Wild Encounter"), + LocationData("Route 1", "Wild Pokemon - 2", "Rattata", rom_addresses["Wild_Route1"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Route 1", "Wild Pokemon - 3", "Rattata", rom_addresses["Wild_Route1"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 1", "Wild Pokemon - 4", "Rattata", rom_addresses["Wild_Route1"] + 7, None, event=True, + type="Wild Encounter"), + LocationData("Route 1", "Wild Pokemon - 5", "Pidgey", rom_addresses["Wild_Route1"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Route 1", "Wild Pokemon - 6", "Pidgey", rom_addresses["Wild_Route1"] + 11, None, event=True, + type="Wild Encounter"), + LocationData("Route 1", "Wild Pokemon - 7", "Pidgey", rom_addresses["Wild_Route1"] + 13, None, event=True, + type="Wild Encounter"), + LocationData("Route 1", "Wild Pokemon - 8", "Rattata", rom_addresses["Wild_Route1"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Route 1", "Wild Pokemon - 9", "Pidgey", rom_addresses["Wild_Route1"] + 17, None, event=True, + type="Wild Encounter"), + LocationData("Route 1", "Wild Pokemon - 10", "Pidgey", rom_addresses["Wild_Route1"] + 19, None, event=True, + type="Wild Encounter"), + LocationData("Route 2", "Wild Pokemon - 1", "Rattata", rom_addresses["Wild_Route2"] + 1, None, event=True, + type="Wild Encounter"), + LocationData("Route 2", "Wild Pokemon - 2", "Pidgey", rom_addresses["Wild_Route2"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Route 2", "Wild Pokemon - 3", "Pidgey", rom_addresses["Wild_Route2"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 2", "Wild Pokemon - 4", "Rattata", rom_addresses["Wild_Route2"] + 7, None, event=True, + type="Wild Encounter"), + LocationData("Route 2", "Wild Pokemon - 5", "Pidgey", rom_addresses["Wild_Route2"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Route 2", "Wild Pokemon - 6", ["Weedle", "Caterpie"], rom_addresses["Wild_Route2"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Route 2", "Wild Pokemon - 7", "Rattata", rom_addresses["Wild_Route2"] + 13, None, event=True, + type="Wild Encounter"), + LocationData("Route 2", "Wild Pokemon - 8", "Rattata", rom_addresses["Wild_Route2"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Route 2", "Wild Pokemon - 9", ["Weedle", "Caterpie"], rom_addresses["Wild_Route2"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Route 2", "Wild Pokemon - 10", ["Weedle", "Caterpie"], rom_addresses["Wild_Route2"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Route 22", "Wild Pokemon - 1", "Rattata", rom_addresses["Wild_Route22"] + 1, None, event=True, + type="Wild Encounter"), + LocationData("Route 22", "Wild Pokemon - 2", ["Nidoran M", "Nidoran F"], rom_addresses["Wild_Route22"] + 3, + None, event=True, type="Wild Encounter"), + LocationData("Route 22", "Wild Pokemon - 3", "Rattata", rom_addresses["Wild_Route22"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 22", "Wild Pokemon - 4", ["Nidoran M", "Nidoran F"], rom_addresses["Wild_Route22"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Route 22", "Wild Pokemon - 5", "Rattata", rom_addresses["Wild_Route22"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Route 22", "Wild Pokemon - 6", ["Nidoran M", "Nidoran F"], rom_addresses["Wild_Route22"] + 11, + None, event=True, type="Wild Encounter"), + LocationData("Route 22", "Wild Pokemon - 7", "Spearow", rom_addresses["Wild_Route22"] + 13, None, event=True, + type="Wild Encounter"), + LocationData("Route 22", "Wild Pokemon - 8", "Spearow", rom_addresses["Wild_Route22"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Route 22", "Wild Pokemon - 9", ["Nidoran F", "Nidoran M"], rom_addresses["Wild_Route22"] + 17, + None, event=True, type="Wild Encounter"), + LocationData("Route 22", "Wild Pokemon - 10", ["Nidoran F", "Nidoran M"], rom_addresses["Wild_Route22"] + 19, + None, event=True, type="Wild Encounter"), + LocationData("Viridian Forest", "Wild Pokemon - 1", ["Weedle", "Caterpie"], + rom_addresses["Wild_ViridianForest"] + 1, None, event=True, type="Wild Encounter"), + LocationData("Viridian Forest", "Wild Pokemon - 2", ["Kakuna", "Metapod"], + rom_addresses["Wild_ViridianForest"] + 3, None, event=True, type="Wild Encounter"), + LocationData("Viridian Forest", "Wild Pokemon - 3", ["Weedle", "Caterpie"], + rom_addresses["Wild_ViridianForest"] + 5, None, event=True, type="Wild Encounter"), + LocationData("Viridian Forest", "Wild Pokemon - 4", ["Weedle", "Caterpie"], + rom_addresses["Wild_ViridianForest"] + 7, None, event=True, type="Wild Encounter"), + LocationData("Viridian Forest", "Wild Pokemon - 5", ["Kakuna", "Metapod"], + rom_addresses["Wild_ViridianForest"] + 9, None, event=True, type="Wild Encounter"), + LocationData("Viridian Forest", "Wild Pokemon - 6", ["Kakuna", "Metapod"], + rom_addresses["Wild_ViridianForest"] + 11, None, event=True, type="Wild Encounter"), + LocationData("Viridian Forest", "Wild Pokemon - 7", ["Metapod", "Kakuna"], + rom_addresses["Wild_ViridianForest"] + 13, None, event=True, type="Wild Encounter"), + LocationData("Viridian Forest", "Wild Pokemon - 8", ["Caterpie", "Weedle"], + rom_addresses["Wild_ViridianForest"] + 15, + None, event=True, type="Wild Encounter"), + LocationData("Viridian Forest", "Wild Pokemon - 9", "Pikachu", rom_addresses["Wild_ViridianForest"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Viridian Forest", "Wild Pokemon - 10", "Pikachu", rom_addresses["Wild_ViridianForest"] + 19, + None, event=True, type="Wild Encounter"), + LocationData("Route 3", "Wild Pokemon - 1", "Pidgey", rom_addresses["Wild_Route3"] + 1, None, event=True, + type="Wild Encounter"), + LocationData("Route 3", "Wild Pokemon - 2", "Spearow", rom_addresses["Wild_Route3"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Route 3", "Wild Pokemon - 3", "Pidgey", rom_addresses["Wild_Route3"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 3", "Wild Pokemon - 4", "Spearow", rom_addresses["Wild_Route3"] + 7, None, event=True, + type="Wild Encounter"), + LocationData("Route 3", "Wild Pokemon - 5", "Spearow", rom_addresses["Wild_Route3"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Route 3", "Wild Pokemon - 6", "Pidgey", rom_addresses["Wild_Route3"] + 11, None, event=True, + type="Wild Encounter"), + LocationData("Route 3", "Wild Pokemon - 7", "Spearow", rom_addresses["Wild_Route3"] + 13, None, event=True, + type="Wild Encounter"), + LocationData("Route 3", "Wild Pokemon - 8", "Jigglypuff", rom_addresses["Wild_Route3"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Route 3", "Wild Pokemon - 9", "Jigglypuff", rom_addresses["Wild_Route3"] + 17, None, event=True, + type="Wild Encounter"), + LocationData("Route 3", "Wild Pokemon - 10", "Jigglypuff", rom_addresses["Wild_Route3"] + 19, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon 1F", "Wild Pokemon - 1", "Zubat", rom_addresses["Wild_MtMoon1F"] + 1, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon 1F", "Wild Pokemon - 2", "Zubat", rom_addresses["Wild_MtMoon1F"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon 1F", "Wild Pokemon - 3", "Zubat", rom_addresses["Wild_MtMoon1F"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon 1F", "Wild Pokemon - 4", "Geodude", rom_addresses["Wild_MtMoon1F"] + 7, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon 1F", "Wild Pokemon - 5", "Zubat", rom_addresses["Wild_MtMoon1F"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon 1F", "Wild Pokemon - 6", "Zubat", rom_addresses["Wild_MtMoon1F"] + 11, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon 1F", "Wild Pokemon - 7", "Geodude", rom_addresses["Wild_MtMoon1F"] + 13, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon 1F", "Wild Pokemon - 8", "Paras", rom_addresses["Wild_MtMoon1F"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon 1F", "Wild Pokemon - 9", "Zubat", rom_addresses["Wild_MtMoon1F"] + 17, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon 1F", "Wild Pokemon - 10", "Clefairy", rom_addresses["Wild_MtMoon1F"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Mt Moon B1F", "Wild Pokemon - 1", "Zubat", rom_addresses["Wild_MtMoonB1F"] + 1, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon B1F", "Wild Pokemon - 2", "Zubat", rom_addresses["Wild_MtMoonB1F"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon B1F", "Wild Pokemon - 3", "Geodude", rom_addresses["Wild_MtMoonB1F"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Mt Moon B1F", "Wild Pokemon - 4", "Geodude", rom_addresses["Wild_MtMoonB1F"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Mt Moon B1F", "Wild Pokemon - 5", "Zubat", rom_addresses["Wild_MtMoonB1F"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon B1F", "Wild Pokemon - 6", "Paras", rom_addresses["Wild_MtMoonB1F"] + 11, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon B1F", "Wild Pokemon - 7", "Zubat", rom_addresses["Wild_MtMoonB1F"] + 13, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon B1F", "Wild Pokemon - 8", "Zubat", rom_addresses["Wild_MtMoonB1F"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon B1F", "Wild Pokemon - 9", "Clefairy", rom_addresses["Wild_MtMoonB1F"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Mt Moon B1F", "Wild Pokemon - 10", "Geodude", rom_addresses["Wild_MtMoonB1F"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Mt Moon B2F", "Wild Pokemon - 1", "Zubat", rom_addresses["Wild_MtMoonB2F"] + 1, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon B2F", "Wild Pokemon - 2", "Geodude", rom_addresses["Wild_MtMoonB2F"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Mt Moon B2F", "Wild Pokemon - 3", "Zubat", rom_addresses["Wild_MtMoonB2F"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon B2F", "Wild Pokemon - 4", "Geodude", rom_addresses["Wild_MtMoonB2F"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Mt Moon B2F", "Wild Pokemon - 5", "Zubat", rom_addresses["Wild_MtMoonB2F"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon B2F", "Wild Pokemon - 6", "Paras", rom_addresses["Wild_MtMoonB2F"] + 11, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon B2F", "Wild Pokemon - 7", "Paras", rom_addresses["Wild_MtMoonB2F"] + 13, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon B2F", "Wild Pokemon - 8", "Clefairy", rom_addresses["Wild_MtMoonB2F"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Mt Moon B2F", "Wild Pokemon - 9", "Zubat", rom_addresses["Wild_MtMoonB2F"] + 17, None, event=True, + type="Wild Encounter"), + LocationData("Mt Moon B2F", "Wild Pokemon - 10", "Clefairy", rom_addresses["Wild_MtMoonB2F"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Route 4", "Wild Pokemon - 1", "Rattata", rom_addresses["Wild_Route4"] + 1, None, event=True, + type="Wild Encounter"), + LocationData("Route 4", "Wild Pokemon - 2", "Spearow", rom_addresses["Wild_Route4"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Route 4", "Wild Pokemon - 3", "Rattata", rom_addresses["Wild_Route4"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 4", "Wild Pokemon - 4", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route4"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Route 4", "Wild Pokemon - 5", "Spearow", rom_addresses["Wild_Route4"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Route 4", "Wild Pokemon - 6", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route4"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Route 4", "Wild Pokemon - 7", "Rattata", rom_addresses["Wild_Route4"] + 13, None, event=True, + type="Wild Encounter"), + LocationData("Route 4", "Wild Pokemon - 8", "Spearow", rom_addresses["Wild_Route4"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Route 4", "Wild Pokemon - 9", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route4"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Route 4", "Wild Pokemon - 10", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route4"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Route 24", "Wild Pokemon - 1", ["Weedle", "Caterpie"], rom_addresses["Wild_Route24"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Route 24", "Wild Pokemon - 2", ["Kakuna", "Metapod"], rom_addresses["Wild_Route24"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Route 24", "Wild Pokemon - 3", "Pidgey", rom_addresses["Wild_Route24"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 24", "Wild Pokemon - 4", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route24"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Route 24", "Wild Pokemon - 5", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route24"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Route 24", "Wild Pokemon - 6", "Abra", rom_addresses["Wild_Route24"] + 11, None, event=True, + type="Wild Encounter"), + LocationData("Route 24", "Wild Pokemon - 7", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route24"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Route 24", "Wild Pokemon - 8", "Pidgey", rom_addresses["Wild_Route24"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Route 24", "Wild Pokemon - 9", "Abra", rom_addresses["Wild_Route24"] + 17, None, event=True, + type="Wild Encounter"), + LocationData("Route 24", "Wild Pokemon - 10", "Abra", rom_addresses["Wild_Route24"] + 19, None, event=True, + type="Wild Encounter"), + LocationData("Route 25", "Wild Pokemon - 1", ["Weedle", "Caterpie"], rom_addresses["Wild_Route25"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Route 25", "Wild Pokemon - 2", ["Kakuna", "Metapod"], rom_addresses["Wild_Route25"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Route 25", "Wild Pokemon - 3", "Pidgey", rom_addresses["Wild_Route25"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 25", "Wild Pokemon - 4", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route25"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Route 25", "Wild Pokemon - 5", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route25"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Route 25", "Wild Pokemon - 6", "Abra", rom_addresses["Wild_Route25"] + 11, None, event=True, + type="Wild Encounter"), + LocationData("Route 25", "Wild Pokemon - 7", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route25"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Route 25", "Wild Pokemon - 8", "Abra", rom_addresses["Wild_Route25"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Route 25", "Wild Pokemon - 9", ["Metapod", "Kakuna"], rom_addresses["Wild_Route25"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Route 25", "Wild Pokemon - 10", ["Caterpie", "Weedle"], rom_addresses["Wild_Route25"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Route 9", "Wild Pokemon - 1", "Rattata", rom_addresses["Wild_Route9"] + 1, None, event=True, + type="Wild Encounter"), + LocationData("Route 9", "Wild Pokemon - 2", "Spearow", rom_addresses["Wild_Route9"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Route 9", "Wild Pokemon - 3", "Rattata", rom_addresses["Wild_Route9"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 9", "Wild Pokemon - 4", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route9"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Route 9", "Wild Pokemon - 5", "Spearow", rom_addresses["Wild_Route9"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Route 9", "Wild Pokemon - 6", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route9"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Route 9", "Wild Pokemon - 7", "Rattata", rom_addresses["Wild_Route9"] + 13, None, event=True, + type="Wild Encounter"), + LocationData("Route 9", "Wild Pokemon - 8", "Spearow", rom_addresses["Wild_Route9"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Route 9", "Wild Pokemon - 9", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route9"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Route 9", "Wild Pokemon - 10", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route9"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Route 5", "Wild Pokemon - 1", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route5"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Route 5", "Wild Pokemon - 2", "Pidgey", rom_addresses["Wild_Route5"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Route 5", "Wild Pokemon - 3", "Pidgey", rom_addresses["Wild_Route5"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 5", "Wild Pokemon - 4", ["Mankey", "Meowth"], rom_addresses["Wild_Route5"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Route 5", "Wild Pokemon - 5", ["Mankey", "Meowth"], rom_addresses["Wild_Route5"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Route 5", "Wild Pokemon - 6", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route5"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Route 5", "Wild Pokemon - 7", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route5"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Route 5", "Wild Pokemon - 8", "Pidgey", rom_addresses["Wild_Route5"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Route 5", "Wild Pokemon - 9", ["Mankey", "Meowth"], rom_addresses["Wild_Route5"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Route 5", "Wild Pokemon - 10", ["Mankey", "Meowth"], rom_addresses["Wild_Route5"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Route 6", "Wild Pokemon - 1", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route6"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Route 6", "Wild Pokemon - 2", "Pidgey", rom_addresses["Wild_Route6"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Route 6", "Wild Pokemon - 3", "Pidgey", rom_addresses["Wild_Route6"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 6", "Wild Pokemon - 4", ["Mankey", "Meowth"], rom_addresses["Wild_Route6"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Route 6", "Wild Pokemon - 5", ["Mankey", "Meowth"], rom_addresses["Wild_Route6"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Route 6", "Wild Pokemon - 6", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route6"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Route 6", "Wild Pokemon - 7", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route6"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Route 6", "Wild Pokemon - 8", "Pidgey", rom_addresses["Wild_Route6"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Route 6", "Wild Pokemon - 9", ["Mankey", "Meowth"], rom_addresses["Wild_Route6"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Route 6", "Wild Pokemon - 10", ["Mankey", "Meowth"], rom_addresses["Wild_Route6"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Route 11", "Wild Pokemon - 1", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route11"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Route 11", "Wild Pokemon - 2", "Spearow", rom_addresses["Wild_Route11"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Route 11", "Wild Pokemon - 3", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route11"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Route 11", "Wild Pokemon - 4", "Drowzee", rom_addresses["Wild_Route11"] + 7, None, event=True, + type="Wild Encounter"), + LocationData("Route 11", "Wild Pokemon - 5", "Spearow", rom_addresses["Wild_Route11"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Route 11", "Wild Pokemon - 6", "Drowzee", rom_addresses["Wild_Route11"] + 11, None, event=True, + type="Wild Encounter"), + LocationData("Route 11", "Wild Pokemon - 7", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route11"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Route 11", "Wild Pokemon - 8", "Spearow", rom_addresses["Wild_Route11"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Route 11", "Wild Pokemon - 9", "Drowzee", rom_addresses["Wild_Route11"] + 17, None, event=True, + type="Wild Encounter"), + LocationData("Route 11", "Wild Pokemon - 10", "Drowzee", rom_addresses["Wild_Route11"] + 19, None, event=True, + type="Wild Encounter"), + LocationData("Rock Tunnel 1F", "Wild Pokemon - 1", "Zubat", rom_addresses["Wild_RockTunnel1F"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel 1F", "Wild Pokemon - 2", "Zubat", rom_addresses["Wild_RockTunnel1F"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel 1F", "Wild Pokemon - 3", "Geodude", rom_addresses["Wild_RockTunnel1F"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel 1F", "Wild Pokemon - 4", "Machop", rom_addresses["Wild_RockTunnel1F"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel 1F", "Wild Pokemon - 5", "Geodude", rom_addresses["Wild_RockTunnel1F"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel 1F", "Wild Pokemon - 6", "Zubat", rom_addresses["Wild_RockTunnel1F"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel 1F", "Wild Pokemon - 7", "Zubat", rom_addresses["Wild_RockTunnel1F"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel 1F", "Wild Pokemon - 8", "Machop", rom_addresses["Wild_RockTunnel1F"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel 1F", "Wild Pokemon - 9", "Onix", rom_addresses["Wild_RockTunnel1F"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel 1F", "Wild Pokemon - 10", "Onix", rom_addresses["Wild_RockTunnel1F"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel B1F", "Wild Pokemon - 1", "Zubat", rom_addresses["Wild_RockTunnelB1F"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel B1F", "Wild Pokemon - 2", "Zubat", rom_addresses["Wild_RockTunnelB1F"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel B1F", "Wild Pokemon - 3", "Geodude", rom_addresses["Wild_RockTunnelB1F"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel B1F", "Wild Pokemon - 4", "Machop", rom_addresses["Wild_RockTunnelB1F"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel B1F", "Wild Pokemon - 5", "Geodude", rom_addresses["Wild_RockTunnelB1F"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel B1F", "Wild Pokemon - 6", "Zubat", rom_addresses["Wild_RockTunnelB1F"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel B1F", "Wild Pokemon - 7", "Machop", rom_addresses["Wild_RockTunnelB1F"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel B1F", "Wild Pokemon - 8", "Onix", rom_addresses["Wild_RockTunnelB1F"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel B1F", "Wild Pokemon - 9", "Onix", rom_addresses["Wild_RockTunnelB1F"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Rock Tunnel B1F", "Wild Pokemon - 10", "Geodude", rom_addresses["Wild_RockTunnelB1F"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Route 10 North", "Wild Pokemon - 1", "Voltorb", rom_addresses["Wild_Route10"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Route 10 North", "Wild Pokemon - 2", "Spearow", rom_addresses["Wild_Route10"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Route 10 North", "Wild Pokemon - 3", "Voltorb", rom_addresses["Wild_Route10"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Route 10 North", "Wild Pokemon - 4", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route10"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Route 10 North", "Wild Pokemon - 5", "Spearow", rom_addresses["Wild_Route10"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Route 10 North", "Wild Pokemon - 6", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route10"] + 11, + None, event=True, type="Wild Encounter"), + LocationData("Route 10 North", "Wild Pokemon - 7", "Voltorb", rom_addresses["Wild_Route10"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Route 10 North", "Wild Pokemon - 8", "Spearow", rom_addresses["Wild_Route10"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Route 10 North", "Wild Pokemon - 9", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route10"] + 17, + None, event=True, type="Wild Encounter"), + LocationData("Route 10 North", "Wild Pokemon - 10", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route10"] + 19, + None, event=True, type="Wild Encounter"), + LocationData("Route 12 Grass", "Wild Pokemon - 1", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route12"] + 1, + None, event=True, type="Wild Encounter"), + LocationData("Route 12 Grass", "Wild Pokemon - 2", "Pidgey", rom_addresses["Wild_Route12"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Route 12 Grass", "Wild Pokemon - 3", "Pidgey", rom_addresses["Wild_Route12"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Route 12 Grass", "Wild Pokemon - 4", "Venonat", rom_addresses["Wild_Route12"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Route 12 Grass", "Wild Pokemon - 5", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route12"] + 9, + None, event=True, type="Wild Encounter"), + LocationData("Route 12 Grass", "Wild Pokemon - 6", "Venonat", rom_addresses["Wild_Route12"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Route 12 Grass", "Wild Pokemon - 7", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route12"] + 13, + None, event=True, type="Wild Encounter"), + LocationData("Route 12 Grass", "Wild Pokemon - 8", "Pidgey", rom_addresses["Wild_Route12"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Route 12 Grass", "Wild Pokemon - 9", ["Gloom", "Weepinbell"], rom_addresses["Wild_Route12"] + 17, + None, event=True, type="Wild Encounter"), + LocationData("Route 12 Grass", "Wild Pokemon - 10", ["Gloom", "Weepinbell"], rom_addresses["Wild_Route12"] + 19, + None, event=True, type="Wild Encounter"), + LocationData("Route 8 Grass", "Wild Pokemon - 1", "Pidgey", rom_addresses["Wild_Route8"] + 1, None, event=True, + type="Wild Encounter"), + LocationData("Route 8 Grass", "Wild Pokemon - 2", ["Mankey", "Meowth"], rom_addresses["Wild_Route8"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Route 8 Grass", "Wild Pokemon - 3", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route8"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Route 8 Grass", "Wild Pokemon - 4", ["Growlithe", "Vulpix"], rom_addresses["Wild_Route8"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Route 8 Grass", "Wild Pokemon - 5", "Pidgey", rom_addresses["Wild_Route8"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Route 8 Grass", "Wild Pokemon - 6", ["Mankey", "Meowth"], rom_addresses["Wild_Route8"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Route 8 Grass", "Wild Pokemon - 7", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route8"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Route 8 Grass", "Wild Pokemon - 8", ["Growlithe", "Vulpix"], rom_addresses["Wild_Route8"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Route 8 Grass", "Wild Pokemon - 9", ["Growlithe", "Vulpix"], rom_addresses["Wild_Route8"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Route 8 Grass", "Wild Pokemon - 10", ["Growlithe", "Vulpix"], rom_addresses["Wild_Route8"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Route 7", "Wild Pokemon - 1", "Pidgey", rom_addresses["Wild_Route7"] + 1, None, event=True, + type="Wild Encounter"), + LocationData("Route 7", "Wild Pokemon - 2", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route7"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Route 7", "Wild Pokemon - 3", ["Mankey", "Meowth"], rom_addresses["Wild_Route7"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Route 7", "Wild Pokemon - 4", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route7"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Route 7", "Wild Pokemon - 5", "Pidgey", rom_addresses["Wild_Route7"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Route 7", "Wild Pokemon - 6", ["Mankey", "Meowth"], rom_addresses["Wild_Route7"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Route 7", "Wild Pokemon - 7", ["Growlithe", "Vulpix"], rom_addresses["Wild_Route7"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Route 7", "Wild Pokemon - 8", ["Growlithe", "Vulpix"], rom_addresses["Wild_Route7"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Route 7", "Wild Pokemon - 9", ["Mankey", "Meowth"], rom_addresses["Wild_Route7"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Route 7", "Wild Pokemon - 10", ["Mankey", "Meowth"], rom_addresses["Wild_Route7"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 3F", "Wild Pokemon - 1", "Gastly", rom_addresses["Wild_PokemonTower3F"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 3F", "Wild Pokemon - 2", "Gastly", rom_addresses["Wild_PokemonTower3F"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 3F", "Wild Pokemon - 3", "Gastly", rom_addresses["Wild_PokemonTower3F"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 3F", "Wild Pokemon - 4", "Gastly", rom_addresses["Wild_PokemonTower3F"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 3F", "Wild Pokemon - 5", "Gastly", rom_addresses["Wild_PokemonTower3F"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 3F", "Wild Pokemon - 6", "Gastly", rom_addresses["Wild_PokemonTower3F"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 3F", "Wild Pokemon - 7", "Gastly", rom_addresses["Wild_PokemonTower3F"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 3F", "Wild Pokemon - 8", "Cubone", rom_addresses["Wild_PokemonTower3F"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 3F", "Wild Pokemon - 9", "Cubone", rom_addresses["Wild_PokemonTower3F"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 3F", "Wild Pokemon - 10", "Haunter", rom_addresses["Wild_PokemonTower3F"] + 19, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 4F", "Wild Pokemon - 1", "Gastly", rom_addresses["Wild_PokemonTower4F"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 4F", "Wild Pokemon - 2", "Gastly", rom_addresses["Wild_PokemonTower4F"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 4F", "Wild Pokemon - 3", "Gastly", rom_addresses["Wild_PokemonTower4F"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 4F", "Wild Pokemon - 4", "Gastly", rom_addresses["Wild_PokemonTower4F"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 4F", "Wild Pokemon - 5", "Gastly", rom_addresses["Wild_PokemonTower4F"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 4F", "Wild Pokemon - 6", "Gastly", rom_addresses["Wild_PokemonTower4F"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 4F", "Wild Pokemon - 7", "Haunter", rom_addresses["Wild_PokemonTower4F"] + 13, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 4F", "Wild Pokemon - 8", "Cubone", rom_addresses["Wild_PokemonTower4F"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 4F", "Wild Pokemon - 9", "Cubone", rom_addresses["Wild_PokemonTower4F"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 4F", "Wild Pokemon - 10", "Gastly", rom_addresses["Wild_PokemonTower4F"] + 19, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 5F", "Wild Pokemon - 1", "Gastly", rom_addresses["Wild_PokemonTower5F"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 5F", "Wild Pokemon - 2", "Gastly", rom_addresses["Wild_PokemonTower5F"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 5F", "Wild Pokemon - 3", "Gastly", rom_addresses["Wild_PokemonTower5F"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 5F", "Wild Pokemon - 4", "Gastly", rom_addresses["Wild_PokemonTower5F"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 5F", "Wild Pokemon - 5", "Gastly", rom_addresses["Wild_PokemonTower5F"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 5F", "Wild Pokemon - 6", "Gastly", rom_addresses["Wild_PokemonTower5F"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 5F", "Wild Pokemon - 7", "Haunter", rom_addresses["Wild_PokemonTower5F"] + 13, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 5F", "Wild Pokemon - 8", "Cubone", rom_addresses["Wild_PokemonTower5F"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 5F", "Wild Pokemon - 9", "Cubone", rom_addresses["Wild_PokemonTower5F"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 5F", "Wild Pokemon - 10", "Gastly", rom_addresses["Wild_PokemonTower5F"] + 19, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 6F", "Wild Pokemon - 1", "Gastly", rom_addresses["Wild_PokemonTower6F"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 6F", "Wild Pokemon - 2", "Gastly", rom_addresses["Wild_PokemonTower6F"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 6F", "Wild Pokemon - 3", "Gastly", rom_addresses["Wild_PokemonTower6F"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 6F", "Wild Pokemon - 4", "Gastly", rom_addresses["Wild_PokemonTower6F"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 6F", "Wild Pokemon - 5", "Gastly", rom_addresses["Wild_PokemonTower6F"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 6F", "Wild Pokemon - 6", "Gastly", rom_addresses["Wild_PokemonTower6F"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 6F", "Wild Pokemon - 7", "Haunter", rom_addresses["Wild_PokemonTower6F"] + 13, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 6F", "Wild Pokemon - 8", "Cubone", rom_addresses["Wild_PokemonTower6F"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 6F", "Wild Pokemon - 9", "Cubone", rom_addresses["Wild_PokemonTower6F"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 6F", "Wild Pokemon - 10", "Haunter", rom_addresses["Wild_PokemonTower6F"] + 19, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 7F", "Wild Pokemon - 1", "Gastly", rom_addresses["Wild_PokemonTower7F"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 7F", "Wild Pokemon - 2", "Gastly", rom_addresses["Wild_PokemonTower7F"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 7F", "Wild Pokemon - 3", "Gastly", rom_addresses["Wild_PokemonTower7F"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 7F", "Wild Pokemon - 4", "Gastly", rom_addresses["Wild_PokemonTower7F"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 7F", "Wild Pokemon - 5", "Gastly", rom_addresses["Wild_PokemonTower7F"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 7F", "Wild Pokemon - 6", "Haunter", rom_addresses["Wild_PokemonTower7F"] + 11, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 7F", "Wild Pokemon - 7", "Cubone", rom_addresses["Wild_PokemonTower7F"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 7F", "Wild Pokemon - 8", "Cubone", rom_addresses["Wild_PokemonTower7F"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 7F", "Wild Pokemon - 9", "Haunter", rom_addresses["Wild_PokemonTower7F"] + 17, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Tower 7F", "Wild Pokemon - 10", "Haunter", rom_addresses["Wild_PokemonTower7F"] + 19, + None, event=True, type="Wild Encounter"), + LocationData("Route 13", "Wild Pokemon - 1", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route13"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Route 13", "Wild Pokemon - 2", "Pidgey", rom_addresses["Wild_Route13"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Route 13", "Wild Pokemon - 3", "Pidgey", rom_addresses["Wild_Route13"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 13", "Wild Pokemon - 4", "Venonat", rom_addresses["Wild_Route13"] + 7, None, event=True, + type="Wild Encounter"), + LocationData("Route 13", "Wild Pokemon - 5", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route13"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Route 13", "Wild Pokemon - 6", "Venonat", rom_addresses["Wild_Route13"] + 11, None, event=True, + type="Wild Encounter"), + LocationData("Route 13", "Wild Pokemon - 7", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route13"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Route 13", "Wild Pokemon - 8", "Ditto", rom_addresses["Wild_Route13"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Route 13", "Wild Pokemon - 9", ["Gloom", "Weepinbell"], rom_addresses["Wild_Route13"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Route 13", "Wild Pokemon - 10", ["Gloom", "Weepinbell"], rom_addresses["Wild_Route13"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Route 14", "Wild Pokemon - 1", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route14"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Route 14", "Wild Pokemon - 2", "Pidgey", rom_addresses["Wild_Route14"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Route 14", "Wild Pokemon - 3", "Ditto", rom_addresses["Wild_Route14"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 14", "Wild Pokemon - 4", "Venonat", rom_addresses["Wild_Route14"] + 7, None, event=True, + type="Wild Encounter"), + LocationData("Route 14", "Wild Pokemon - 5", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route14"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Route 14", "Wild Pokemon - 6", "Venonat", rom_addresses["Wild_Route14"] + 11, None, event=True, + type="Wild Encounter"), + LocationData("Route 14", "Wild Pokemon - 7", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route14"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Route 14", "Wild Pokemon - 8", ["Gloom", "Weepinbell"], rom_addresses["Wild_Route14"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Route 14", "Wild Pokemon - 9", "Pidgeotto", rom_addresses["Wild_Route14"] + 17, None, event=True, + type="Wild Encounter"), + LocationData("Route 14", "Wild Pokemon - 10", "Pidgeotto", rom_addresses["Wild_Route14"] + 19, None, event=True, + type="Wild Encounter"), + LocationData("Route 15", "Wild Pokemon - 1", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route15"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Route 15", "Wild Pokemon - 2", "Ditto", rom_addresses["Wild_Route15"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Route 15", "Wild Pokemon - 3", "Pidgey", rom_addresses["Wild_Route15"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 15", "Wild Pokemon - 4", "Venonat", rom_addresses["Wild_Route15"] + 7, None, event=True, + type="Wild Encounter"), + LocationData("Route 15", "Wild Pokemon - 5", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route15"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Route 15", "Wild Pokemon - 6", "Venonat", rom_addresses["Wild_Route15"] + 11, None, event=True, + type="Wild Encounter"), + LocationData("Route 15", "Wild Pokemon - 7", ["Oddish", "Bellsprout"], rom_addresses["Wild_Route15"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Route 15", "Wild Pokemon - 8", ["Gloom", "Weepinbell"], rom_addresses["Wild_Route15"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Route 15", "Wild Pokemon - 9", "Pidgeotto", rom_addresses["Wild_Route15"] + 17, None, event=True, + type="Wild Encounter"), + LocationData("Route 15", "Wild Pokemon - 10", "Pidgeotto", rom_addresses["Wild_Route15"] + 19, None, event=True, + type="Wild Encounter"), + LocationData("Route 16 North", "Wild Pokemon - 1", "Spearow", rom_addresses["Wild_Route16"] + 1, None, event=True, + type="Wild Encounter"), + LocationData("Route 16 North", "Wild Pokemon - 2", "Spearow", rom_addresses["Wild_Route16"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Route 16 North", "Wild Pokemon - 3", "Rattata", rom_addresses["Wild_Route16"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 16 North", "Wild Pokemon - 4", "Doduo", rom_addresses["Wild_Route16"] + 7, None, event=True, + type="Wild Encounter"), + LocationData("Route 16 North", "Wild Pokemon - 5", "Rattata", rom_addresses["Wild_Route16"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Route 16 North", "Wild Pokemon - 6", "Doduo", rom_addresses["Wild_Route16"] + 11, None, event=True, + type="Wild Encounter"), + LocationData("Route 16 North", "Wild Pokemon - 7", "Doduo", rom_addresses["Wild_Route16"] + 13, None, event=True, + type="Wild Encounter"), + LocationData("Route 16 North", "Wild Pokemon - 8", "Rattata", rom_addresses["Wild_Route16"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Route 16 North", "Wild Pokemon - 9", "Raticate", rom_addresses["Wild_Route16"] + 17, None, event=True, + type="Wild Encounter"), + LocationData("Route 16 North", "Wild Pokemon - 10", "Raticate", rom_addresses["Wild_Route16"] + 19, None, + event=True, + type="Wild Encounter"), + LocationData("Route 17", "Wild Pokemon - 1", "Spearow", rom_addresses["Wild_Route17"] + 1, None, event=True, + type="Wild Encounter"), + LocationData("Route 17", "Wild Pokemon - 2", "Spearow", rom_addresses["Wild_Route17"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Route 17", "Wild Pokemon - 3", "Raticate", rom_addresses["Wild_Route17"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 17", "Wild Pokemon - 4", "Doduo", rom_addresses["Wild_Route17"] + 7, None, event=True, + type="Wild Encounter"), + LocationData("Route 17", "Wild Pokemon - 5", "Raticate", rom_addresses["Wild_Route17"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Route 17", "Wild Pokemon - 6", "Doduo", rom_addresses["Wild_Route17"] + 11, None, event=True, + type="Wild Encounter"), + LocationData("Route 17", "Wild Pokemon - 7", "Doduo", rom_addresses["Wild_Route17"] + 13, None, event=True, + type="Wild Encounter"), + LocationData("Route 17", "Wild Pokemon - 8", "Raticate", rom_addresses["Wild_Route17"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Route 17", "Wild Pokemon - 9", "Fearow", rom_addresses["Wild_Route17"] + 17, None, event=True, + type="Wild Encounter"), + LocationData("Route 17", "Wild Pokemon - 10", "Fearow", rom_addresses["Wild_Route17"] + 19, None, event=True, + type="Wild Encounter"), + LocationData("Route 18", "Wild Pokemon - 1", "Spearow", rom_addresses["Wild_Route18"] + 1, None, event=True, + type="Wild Encounter"), + LocationData("Route 18", "Wild Pokemon - 2", "Spearow", rom_addresses["Wild_Route18"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Route 18", "Wild Pokemon - 3", "Raticate", rom_addresses["Wild_Route18"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 18", "Wild Pokemon - 4", "Doduo", rom_addresses["Wild_Route18"] + 7, None, event=True, + type="Wild Encounter"), + LocationData("Route 18", "Wild Pokemon - 5", "Fearow", rom_addresses["Wild_Route18"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Route 18", "Wild Pokemon - 6", "Doduo", rom_addresses["Wild_Route18"] + 11, None, event=True, + type="Wild Encounter"), + LocationData("Route 18", "Wild Pokemon - 7", "Doduo", rom_addresses["Wild_Route18"] + 13, None, event=True, + type="Wild Encounter"), + LocationData("Route 18", "Wild Pokemon - 8", "Raticate", rom_addresses["Wild_Route18"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Route 18", "Wild Pokemon - 9", "Fearow", rom_addresses["Wild_Route18"] + 17, None, event=True, + type="Wild Encounter"), + LocationData("Route 18", "Wild Pokemon - 10", "Fearow", rom_addresses["Wild_Route18"] + 19, None, event=True, + type="Wild Encounter"), + LocationData("Safari Zone Center", "Wild Pokemon - 1", ["Nidoran M", "Nidoran F"], + rom_addresses["Wild_SafariZoneCenter"] + 1, None, event=True, type="Wild Encounter"), + LocationData("Safari Zone Center", "Wild Pokemon - 2", "Rhyhorn", rom_addresses["Wild_SafariZoneCenter"] + 3, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone Center", "Wild Pokemon - 3", "Venonat", rom_addresses["Wild_SafariZoneCenter"] + 5, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone Center", "Wild Pokemon - 4", "Exeggcute", rom_addresses["Wild_SafariZoneCenter"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone Center", "Wild Pokemon - 5", ["Nidorino", "Nidorina"], + rom_addresses["Wild_SafariZoneCenter"] + 9, None, event=True, type="Wild Encounter"), + LocationData("Safari Zone Center", "Wild Pokemon - 6", "Exeggcute", rom_addresses["Wild_SafariZoneCenter"] + 11, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone Center", "Wild Pokemon - 7", ["Nidorina", "Nidorino"], + rom_addresses["Wild_SafariZoneCenter"] + 13, None, event=True, type="Wild Encounter"), + LocationData("Safari Zone Center", "Wild Pokemon - 8", "Parasect", rom_addresses["Wild_SafariZoneCenter"] + 15, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone Center", "Wild Pokemon - 9", ["Scyther", "Pinsir"], + rom_addresses["Wild_SafariZoneCenter"] + 17, None, event=True, type="Wild Encounter"), + LocationData("Safari Zone Center", "Wild Pokemon - 10", "Chansey", rom_addresses["Wild_SafariZoneCenter"] + 19, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone East", "Wild Pokemon - 1", ["Nidoran M", "Nidoran F"], + rom_addresses["Wild_SafariZoneEast"] + 1, None, event=True, type="Wild Encounter"), + LocationData("Safari Zone East", "Wild Pokemon - 2", "Doduo", rom_addresses["Wild_SafariZoneEast"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Safari Zone East", "Wild Pokemon - 3", "Paras", rom_addresses["Wild_SafariZoneEast"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Safari Zone East", "Wild Pokemon - 4", "Exeggcute", rom_addresses["Wild_SafariZoneEast"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone East", "Wild Pokemon - 5", ["Nidorino", "Nidorina"], + rom_addresses["Wild_SafariZoneEast"] + 9, None, event=True, type="Wild Encounter"), + LocationData("Safari Zone East", "Wild Pokemon - 6", "Exeggcute", rom_addresses["Wild_SafariZoneEast"] + 11, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone East", "Wild Pokemon - 7", ["Nidoran F", "Nidoran M"], + rom_addresses["Wild_SafariZoneEast"] + 13, None, event=True, type="Wild Encounter"), + LocationData("Safari Zone East", "Wild Pokemon - 8", "Parasect", rom_addresses["Wild_SafariZoneEast"] + 15, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone East", "Wild Pokemon - 9", "Kangaskhan", rom_addresses["Wild_SafariZoneEast"] + 17, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone East", "Wild Pokemon - 10", ["Scyther", "Pinsir"], + rom_addresses["Wild_SafariZoneEast"] + 19, None, event=True, type="Wild Encounter"), + LocationData("Safari Zone North", "Wild Pokemon - 1", ["Nidoran M", "Nidoran F"], + rom_addresses["Wild_SafariZoneNorth"] + 1, None, event=True, type="Wild Encounter"), + LocationData("Safari Zone North", "Wild Pokemon - 2", "Rhyhorn", rom_addresses["Wild_SafariZoneNorth"] + 3, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone North", "Wild Pokemon - 3", "Paras", rom_addresses["Wild_SafariZoneNorth"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Safari Zone North", "Wild Pokemon - 4", "Exeggcute", rom_addresses["Wild_SafariZoneNorth"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone North", "Wild Pokemon - 5", ["Nidorino", "Nidorina"], + rom_addresses["Wild_SafariZoneNorth"] + 9, None, event=True, type="Wild Encounter"), + LocationData("Safari Zone North", "Wild Pokemon - 6", "Exeggcute", rom_addresses["Wild_SafariZoneNorth"] + 11, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone North", "Wild Pokemon - 7", ["Nidorina", "Nidorino"], + rom_addresses["Wild_SafariZoneNorth"] + 13, None, event=True, type="Wild Encounter"), + LocationData("Safari Zone North", "Wild Pokemon - 8", "Venomoth", rom_addresses["Wild_SafariZoneNorth"] + 15, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone North", "Wild Pokemon - 9", "Chansey", rom_addresses["Wild_SafariZoneNorth"] + 17, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone North", "Wild Pokemon - 10", "Tauros", rom_addresses["Wild_SafariZoneNorth"] + 19, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone West", "Wild Pokemon - 1", ["Nidoran M", "Nidoran F"], + rom_addresses["Wild_SafariZoneWest"] + 1, None, event=True, type="Wild Encounter"), + LocationData("Safari Zone West", "Wild Pokemon - 2", "Doduo", rom_addresses["Wild_SafariZoneWest"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Safari Zone West", "Wild Pokemon - 3", "Venonat", rom_addresses["Wild_SafariZoneWest"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Safari Zone West", "Wild Pokemon - 4", "Exeggcute", rom_addresses["Wild_SafariZoneWest"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone West", "Wild Pokemon - 5", ["Nidorino", "Nidorina"], + rom_addresses["Wild_SafariZoneWest"] + 9, None, event=True, type="Wild Encounter"), + LocationData("Safari Zone West", "Wild Pokemon - 6", "Exeggcute", rom_addresses["Wild_SafariZoneWest"] + 11, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone West", "Wild Pokemon - 7", ["Nidoran F", "Nidoran M"], + rom_addresses["Wild_SafariZoneWest"] + 13, None, event=True, type="Wild Encounter"), + LocationData("Safari Zone West", "Wild Pokemon - 8", "Venomoth", rom_addresses["Wild_SafariZoneWest"] + 15, + None, event=True, type="Wild Encounter"), + LocationData("Safari Zone West", "Wild Pokemon - 9", "Tauros", rom_addresses["Wild_SafariZoneWest"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Safari Zone West", "Wild Pokemon - 10", "Kangaskhan", rom_addresses["Wild_SafariZoneWest"] + 19, + None, event=True, type="Wild Encounter"), + LocationData("Route 20 West", "Surf Pokemon - 1", "Tentacool", rom_addresses["Wild_SeaRoutes"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Route 20 West", "Surf Pokemon - 2", "Tentacool", rom_addresses["Wild_SeaRoutes"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Route 20 West", "Surf Pokemon - 3", "Tentacool", rom_addresses["Wild_SeaRoutes"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Route 20 West", "Surf Pokemon - 4", "Tentacool", rom_addresses["Wild_SeaRoutes"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Route 20 West", "Surf Pokemon - 5", "Tentacool", rom_addresses["Wild_SeaRoutes"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Route 20 West", "Surf Pokemon - 6", "Tentacool", rom_addresses["Wild_SeaRoutes"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Route 20 West", "Surf Pokemon - 7", "Tentacool", rom_addresses["Wild_SeaRoutes"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Route 20 West", "Surf Pokemon - 8", "Tentacool", rom_addresses["Wild_SeaRoutes"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Route 20 West", "Surf Pokemon - 9", "Tentacool", rom_addresses["Wild_SeaRoutes"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Route 20 West", "Surf Pokemon - 10", "Tentacool", rom_addresses["Wild_SeaRoutes"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Route 21", "Surf Pokemon - 1", "Tentacool", rom_addresses["Wild_Surf_Route21"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Route 21", "Surf Pokemon - 2", "Tentacool", rom_addresses["Wild_Surf_Route21"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Route 21", "Surf Pokemon - 3", "Tentacool", rom_addresses["Wild_Surf_Route21"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Route 21", "Surf Pokemon - 4", "Tentacool", rom_addresses["Wild_Surf_Route21"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Route 21", "Surf Pokemon - 5", "Tentacool", rom_addresses["Wild_Surf_Route21"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Route 21", "Surf Pokemon - 6", "Tentacool", rom_addresses["Wild_Surf_Route21"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Route 21", "Surf Pokemon - 7", "Tentacool", rom_addresses["Wild_Surf_Route21"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Route 21", "Surf Pokemon - 8", "Tentacool", rom_addresses["Wild_Surf_Route21"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Route 21", "Surf Pokemon - 9", "Tentacool", rom_addresses["Wild_Surf_Route21"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Route 21", "Surf Pokemon - 10", "Tentacool", rom_addresses["Wild_Surf_Route21"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Seafoam Islands 1F", "Wild Pokemon - 1", "Seel", rom_addresses["Wild_SeafoamIslands1F"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Seafoam Islands 1F", "Wild Pokemon - 2", ["Slowpoke", "Psyduck"], + rom_addresses["Wild_SeafoamIslands1F"] + 3, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands 1F", "Wild Pokemon - 3", ["Shellder", "Staryu"], + rom_addresses["Wild_SeafoamIslands1F"] + 5, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands 1F", "Wild Pokemon - 4", ["Horsea", "Krabby"], + rom_addresses["Wild_SeafoamIslands1F"] + 7, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands 1F", "Wild Pokemon - 5", ["Horsea", "Krabby"], + rom_addresses["Wild_SeafoamIslands1F"] + 9, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands 1F", "Wild Pokemon - 6", "Zubat", rom_addresses["Wild_SeafoamIslands1F"] + 11, + None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands 1F", "Wild Pokemon - 7", "Golbat", rom_addresses["Wild_SeafoamIslands1F"] + 13, + None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands 1F", "Wild Pokemon - 8", ["Psyduck", "Slowpoke"], + rom_addresses["Wild_SeafoamIslands1F"] + 15, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands 1F", "Wild Pokemon - 9", ["Shellder", "Staryu"], + rom_addresses["Wild_SeafoamIslands1F"] + 17, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands 1F", "Wild Pokemon - 10", ["Golduck", "Slowbro"], + rom_addresses["Wild_SeafoamIslands1F"] + 19, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B1F", "Wild Pokemon - 1", ["Staryu", "Shellder"], + rom_addresses["Wild_SeafoamIslandsB1F"] + 1, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B1F", "Wild Pokemon - 2", ["Horsea", "Krabby"], + rom_addresses["Wild_SeafoamIslandsB1F"] + 3, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B1F", "Wild Pokemon - 3", ["Shellder", "Staryu"], + rom_addresses["Wild_SeafoamIslandsB1F"] + 5, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B1F", "Wild Pokemon - 4", ["Horsea", "Krabby"], + rom_addresses["Wild_SeafoamIslandsB1F"] + 7, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B1F", "Wild Pokemon - 5", ["Slowpoke", "Psyduck"], + rom_addresses["Wild_SeafoamIslandsB1F"] + 9, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B1F", "Wild Pokemon - 6", "Seel", rom_addresses["Wild_SeafoamIslandsB1F"] + 11, + None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B1F", "Wild Pokemon - 7", ["Slowpoke", "Psyduck"], + rom_addresses["Wild_SeafoamIslandsB1F"] + 13, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B1F", "Wild Pokemon - 8", "Seel", rom_addresses["Wild_SeafoamIslandsB1F"] + 15, + None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B1F", "Wild Pokemon - 9", "Dewgong", rom_addresses["Wild_SeafoamIslandsB1F"] + 17, + None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B1F", "Wild Pokemon - 10", ["Seadra", "Kingler"], + rom_addresses["Wild_SeafoamIslandsB1F"] + 19, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B2F", "Wild Pokemon - 1", "Seel", rom_addresses["Wild_SeafoamIslandsB2F"] + 1, + None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B2F", "Wild Pokemon - 2", ["Slowpoke", "Psyduck"], + rom_addresses["Wild_SeafoamIslandsB2F"] + 3, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B2F", "Wild Pokemon - 3", "Seel", rom_addresses["Wild_SeafoamIslandsB2F"] + 5, + None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B2F", "Wild Pokemon - 4", ["Slowpoke", "Psyduck"], + rom_addresses["Wild_SeafoamIslandsB2F"] + 7, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B2F", "Wild Pokemon - 5", ["Horsea", "Krabby"], + rom_addresses["Wild_SeafoamIslandsB2F"] + 9, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B2F", "Wild Pokemon - 6", ["Staryu", "Shellder"], + rom_addresses["Wild_SeafoamIslandsB2F"] + 11, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B2F", "Wild Pokemon - 7", ["Horsea", "Krabby"], + rom_addresses["Wild_SeafoamIslandsB2F"] + 13, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B2F", "Wild Pokemon - 8", ["Shellder", "Staryu"], + rom_addresses["Wild_SeafoamIslandsB2F"] + 15, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B2F", "Wild Pokemon - 9", "Golbat", rom_addresses["Wild_SeafoamIslandsB2F"] + 17, + None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B2F", "Wild Pokemon - 10", ["Slowbro", "Golduck"], + rom_addresses["Wild_SeafoamIslandsB2F"] + 19, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B3F", "Wild Pokemon - 1", ["Slowpoke", "Psyduck"], + rom_addresses["Wild_SeafoamIslandsB3F"] + 1, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B3F", "Wild Pokemon - 2", "Seel", rom_addresses["Wild_SeafoamIslandsB3F"] + 3, + None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B3F", "Wild Pokemon - 3", ["Slowpoke", "Psyduck"], + rom_addresses["Wild_SeafoamIslandsB3F"] + 5, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B3F", "Wild Pokemon - 4", "Seel", rom_addresses["Wild_SeafoamIslandsB3F"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B3F", "Wild Pokemon - 5", ["Horsea", "Krabby"], + rom_addresses["Wild_SeafoamIslandsB3F"] + 9, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B3F", "Wild Pokemon - 6", ["Shellder", "Staryu"], + rom_addresses["Wild_SeafoamIslandsB3F"] + 11, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B3F", "Wild Pokemon - 7", ["Horsea", "Krabby"], + rom_addresses["Wild_SeafoamIslandsB3F"] + 13, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B3F", "Wild Pokemon - 8", ["Shellder", "Staryu"], + rom_addresses["Wild_SeafoamIslandsB3F"] + 15, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B3F", "Wild Pokemon - 9", ["Seadra", "Kingler"], + rom_addresses["Wild_SeafoamIslandsB3F"] + 17, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B3F", "Wild Pokemon - 10", "Dewgong", + rom_addresses["Wild_SeafoamIslandsB3F"] + 19, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B4F", "Wild Pokemon - 1", ["Horsea", "Krabby"], + rom_addresses["Wild_SeafoamIslandsB4F"] + 1, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B4F", "Wild Pokemon - 2", ["Shellder", "Staryu"], + rom_addresses["Wild_SeafoamIslandsB4F"] + 3, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B4F", "Wild Pokemon - 3", ["Horsea", "Krabby"], + rom_addresses["Wild_SeafoamIslandsB4F"] + 5, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B4F", "Wild Pokemon - 4", "Shellder", rom_addresses["Wild_SeafoamIslandsB4F"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B4F", "Wild Pokemon - 5", ["Slowpoke", "Psyduck"], + rom_addresses["Wild_SeafoamIslandsB4F"] + 9, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B4F", "Wild Pokemon - 6", "Seel", rom_addresses["Wild_SeafoamIslandsB4F"] + 11, + None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B4F", "Wild Pokemon - 7", ["Slowpoke", "Psyduck"], + rom_addresses["Wild_SeafoamIslandsB4F"] + 13, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B4F", "Wild Pokemon - 8", "Seel", rom_addresses["Wild_SeafoamIslandsB4F"] + 15, + None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B4F", "Wild Pokemon - 9", ["Slowbro", "Golduck"], + rom_addresses["Wild_SeafoamIslandsB4F"] + 17, None, event=True, type="Wild Encounter"), + LocationData("Seafoam Islands B4F", "Wild Pokemon - 10", "Golbat", rom_addresses["Wild_SeafoamIslandsB4F"] + 19, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 1F", "Wild Pokemon - 1", ["Koffing", "Grimer"], + rom_addresses["Wild_PokemonMansion1F"] + 1, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 1F", "Wild Pokemon - 2", ["Koffing", "Grimer"], + rom_addresses["Wild_PokemonMansion1F"] + 3, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 1F", "Wild Pokemon - 3", "Ponyta", rom_addresses["Wild_PokemonMansion1F"] + 5, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 1F", "Wild Pokemon - 4", "Ponyta", rom_addresses["Wild_PokemonMansion1F"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 1F", "Wild Pokemon - 5", ["Growlithe", "Vulpix"], + rom_addresses["Wild_PokemonMansion1F"] + 9, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 1F", "Wild Pokemon - 6", "Ponyta", rom_addresses["Wild_PokemonMansion1F"] + 11, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 1F", "Wild Pokemon - 7", ["Grimer", "Koffing"], + rom_addresses["Wild_PokemonMansion1F"] + 13, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 1F", "Wild Pokemon - 8", "Ponyta", rom_addresses["Wild_PokemonMansion1F"] + 15, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 1F", "Wild Pokemon - 9", ["Weezing", "Muk"], + rom_addresses["Wild_PokemonMansion1F"] + 17, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 1F", "Wild Pokemon - 10", ["Muk", "Weezing"], + rom_addresses["Wild_PokemonMansion1F"] + 19, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 2F", "Wild Pokemon - 1", ["Growlithe", "Vulpix"], + rom_addresses["Wild_PokemonMansion2F"] + 1, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 2F", "Wild Pokemon - 2", ["Koffing", "Grimer"], + rom_addresses["Wild_PokemonMansion2F"] + 3, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 2F", "Wild Pokemon - 3", ["Koffing", "Grimer"], + rom_addresses["Wild_PokemonMansion2F"] + 5, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 2F", "Wild Pokemon - 4", "Ponyta", rom_addresses["Wild_PokemonMansion2F"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 2F", "Wild Pokemon - 5", ["Koffing", "Grimer"], + rom_addresses["Wild_PokemonMansion2F"] + 9, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 2F", "Wild Pokemon - 6", "Ponyta", rom_addresses["Wild_PokemonMansion2F"] + 11, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 2F", "Wild Pokemon - 7", ["Grimer", "Koffing"], + rom_addresses["Wild_PokemonMansion2F"] + 13, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 2F", "Wild Pokemon - 8", "Ponyta", rom_addresses["Wild_PokemonMansion2F"] + 15, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 2F", "Wild Pokemon - 9", ["Weezing", "Muk"], + rom_addresses["Wild_PokemonMansion2F"] + 17, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 2F", "Wild Pokemon - 10", ["Muk", "Weezing"], + rom_addresses["Wild_PokemonMansion2F"] + 19, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 3F", "Wild Pokemon - 1", ["Koffing", "Grimer"], + rom_addresses["Wild_PokemonMansion3F"] + 1, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 3F", "Wild Pokemon - 2", ["Growlithe", "Vulpix"], + rom_addresses["Wild_PokemonMansion3F"] + 3, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 3F", "Wild Pokemon - 3", ["Koffing", "Grimer"], + rom_addresses["Wild_PokemonMansion3F"] + 5, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 3F", "Wild Pokemon - 4", "Ponyta", rom_addresses["Wild_PokemonMansion3F"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 3F", "Wild Pokemon - 5", ["Ponyta", "Magmar"], + rom_addresses["Wild_PokemonMansion3F"] + 9, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 3F", "Wild Pokemon - 6", ["Weezing", "Muk"], + rom_addresses["Wild_PokemonMansion3F"] + 11, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 3F", "Wild Pokemon - 7", ["Grimer", "Koffing"], + rom_addresses["Wild_PokemonMansion3F"] + 13, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 3F", "Wild Pokemon - 8", ["Weezing", "Muk"], + rom_addresses["Wild_PokemonMansion3F"] + 15, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 3F", "Wild Pokemon - 9", "Ponyta", rom_addresses["Wild_PokemonMansion3F"] + 17, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion 3F", "Wild Pokemon - 10", ["Muk", "Weezing"], + rom_addresses["Wild_PokemonMansion3F"] + 19, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion B1F", "Wild Pokemon - 1", ["Koffing", "Grimer"], + rom_addresses["Wild_PokemonMansionB1F"] + 1, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion B1F", "Wild Pokemon - 2", ["Koffing", "Grimer"], + rom_addresses["Wild_PokemonMansionB1F"] + 3, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion B1F", "Wild Pokemon - 3", ["Growlithe", "Vulpix"], + rom_addresses["Wild_PokemonMansionB1F"] + 5, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion B1F", "Wild Pokemon - 4", "Ponyta", rom_addresses["Wild_PokemonMansionB1F"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion B1F", "Wild Pokemon - 5", ["Koffing", "Grimer"], + rom_addresses["Wild_PokemonMansionB1F"] + 9, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion B1F", "Wild Pokemon - 6", ["Weezing", "Muk"], + rom_addresses["Wild_PokemonMansionB1F"] + 11, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion B1F", "Wild Pokemon - 7", "Ponyta", rom_addresses["Wild_PokemonMansionB1F"] + 13, + None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion B1F", "Wild Pokemon - 8", ["Grimer", "Koffing"], + rom_addresses["Wild_PokemonMansionB1F"] + 15, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion B1F", "Wild Pokemon - 9", ["Weezing", "Magmar"], + rom_addresses["Wild_PokemonMansionB1F"] + 17, None, event=True, type="Wild Encounter"), + LocationData("Pokemon Mansion B1F", "Wild Pokemon - 10", ["Muk", "Weezing"], + rom_addresses["Wild_PokemonMansionB1F"] + 19, None, event=True, type="Wild Encounter"), + LocationData("Route 21", "Wild Pokemon - 1", "Rattata", rom_addresses["Wild_Route21"] + 1, None, event=True, + type="Wild Encounter"), + LocationData("Route 21", "Wild Pokemon - 2", "Pidgey", rom_addresses["Wild_Route21"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Route 21", "Wild Pokemon - 3", "Raticate", rom_addresses["Wild_Route21"] + 5, None, event=True, + type="Wild Encounter"), + LocationData("Route 21", "Wild Pokemon - 4", "Rattata", rom_addresses["Wild_Route21"] + 7, None, event=True, + type="Wild Encounter"), + LocationData("Route 21", "Wild Pokemon - 5", "Pidgey", rom_addresses["Wild_Route21"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Route 21", "Wild Pokemon - 6", "Pidgeotto", rom_addresses["Wild_Route21"] + 11, None, event=True, + type="Wild Encounter"), + LocationData("Route 21", "Wild Pokemon - 7", "Pidgeotto", rom_addresses["Wild_Route21"] + 13, None, event=True, + type="Wild Encounter"), + LocationData("Route 21", "Wild Pokemon - 8", "Tangela", rom_addresses["Wild_Route21"] + 15, None, event=True, + type="Wild Encounter"), + LocationData("Route 21", "Wild Pokemon - 9", "Tangela", rom_addresses["Wild_Route21"] + 17, None, event=True, + type="Wild Encounter"), + LocationData("Route 21", "Wild Pokemon - 10", "Tangela", rom_addresses["Wild_Route21"] + 19, None, event=True, + type="Wild Encounter"), + LocationData("Cerulean Cave 1F", "Wild Pokemon - 1", "Golbat", rom_addresses["Wild_CeruleanCave1F"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 1F", "Wild Pokemon - 2", "Hypno", rom_addresses["Wild_CeruleanCave1F"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 1F", "Wild Pokemon - 3", "Magneton", rom_addresses["Wild_CeruleanCave1F"] + 5, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 1F", "Wild Pokemon - 4", "Dodrio", rom_addresses["Wild_CeruleanCave1F"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 1F", "Wild Pokemon - 5", "Venomoth", rom_addresses["Wild_CeruleanCave1F"] + 9, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 1F", "Wild Pokemon - 6", ["Arbok", "Sandslash"], + rom_addresses["Wild_CeruleanCave1F"] + 11, None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 1F", "Wild Pokemon - 7", "Kadabra", rom_addresses["Wild_CeruleanCave1F"] + 13, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 1F", "Wild Pokemon - 8", "Parasect", rom_addresses["Wild_CeruleanCave1F"] + 15, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 1F", "Wild Pokemon - 9", "Raichu", rom_addresses["Wild_CeruleanCave1F"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 1F", "Wild Pokemon - 10", "Ditto", rom_addresses["Wild_CeruleanCave1F"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 2F", "Wild Pokemon - 1", "Dodrio", rom_addresses["Wild_CeruleanCave2F"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 2F", "Wild Pokemon - 2", "Venomoth", rom_addresses["Wild_CeruleanCave2F"] + 3, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 2F", "Wild Pokemon - 3", "Kadabra", rom_addresses["Wild_CeruleanCave2F"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 2F", "Wild Pokemon - 4", "Rhydon", rom_addresses["Wild_CeruleanCave2F"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 2F", "Wild Pokemon - 5", "Marowak", rom_addresses["Wild_CeruleanCave2F"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 2F", "Wild Pokemon - 6", "Electrode", rom_addresses["Wild_CeruleanCave2F"] + 11, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 2F", "Wild Pokemon - 7", "Chansey", rom_addresses["Wild_CeruleanCave2F"] + 13, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 2F", "Wild Pokemon - 8", "Wigglytuff", rom_addresses["Wild_CeruleanCave2F"] + 15, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 2F", "Wild Pokemon - 9", "Ditto", rom_addresses["Wild_CeruleanCave2F"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Cerulean Cave 2F", "Wild Pokemon - 10", "Ditto", rom_addresses["Wild_CeruleanCave2F"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Cerulean Cave B1F", "Wild Pokemon - 1", "Rhydon", rom_addresses["Wild_CeruleanCaveB1F"] + 1, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave B1F", "Wild Pokemon - 2", "Marowak", rom_addresses["Wild_CeruleanCaveB1F"] + 3, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave B1F", "Wild Pokemon - 3", "Electrode", rom_addresses["Wild_CeruleanCaveB1F"] + 5, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave B1F", "Wild Pokemon - 4", "Chansey", rom_addresses["Wild_CeruleanCaveB1F"] + 7, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave B1F", "Wild Pokemon - 5", "Parasect", rom_addresses["Wild_CeruleanCaveB1F"] + 9, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave B1F", "Wild Pokemon - 6", "Raichu", rom_addresses["Wild_CeruleanCaveB1F"] + 11, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave B1F", "Wild Pokemon - 7", ["Arbok", "Sandslash"], + rom_addresses["Wild_CeruleanCaveB1F"] + 13, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave B1F", "Wild Pokemon - 8", "Ditto", rom_addresses["Wild_CeruleanCaveB1F"] + 15, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave B1F", "Wild Pokemon - 9", "Ditto", rom_addresses["Wild_CeruleanCaveB1F"] + 17, + None, event=True, type="Wild Encounter"), + LocationData("Cerulean Cave B1F", "Wild Pokemon - 10", "Ditto", rom_addresses["Wild_CeruleanCaveB1F"] + 19, + None, event=True, type="Wild Encounter"), + LocationData("Power Plant", "Wild Pokemon - 1", "Voltorb", rom_addresses["Wild_PowerPlant"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Power Plant", "Wild Pokemon - 2", "Magnemite", rom_addresses["Wild_PowerPlant"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Power Plant", "Wild Pokemon - 3", "Pikachu", rom_addresses["Wild_PowerPlant"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Power Plant", "Wild Pokemon - 4", "Pikachu", rom_addresses["Wild_PowerPlant"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Power Plant", "Wild Pokemon - 5", "Magnemite", rom_addresses["Wild_PowerPlant"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Power Plant", "Wild Pokemon - 6", "Voltorb", rom_addresses["Wild_PowerPlant"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Power Plant", "Wild Pokemon - 7", "Magneton", rom_addresses["Wild_PowerPlant"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Power Plant", "Wild Pokemon - 8", "Magneton", rom_addresses["Wild_PowerPlant"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Power Plant", "Wild Pokemon - 9", ["Electabuzz", "Raichu"], rom_addresses["Wild_PowerPlant"] + 17, + None, event=True, type="Wild Encounter"), + LocationData("Power Plant", "Wild Pokemon - 10", ["Electabuzz", "Raichu"], + rom_addresses["Wild_PowerPlant"] + 19, None, event=True, type="Wild Encounter"), + LocationData("Route 23 North", "Wild Pokemon - 1", ["Ekans", "Sandshrew"], rom_addresses["Wild_Route23"] + 1, + None, event=True, type="Wild Encounter"), + LocationData("Route 23 North", "Wild Pokemon - 2", "Ditto", rom_addresses["Wild_Route23"] + 3, None, event=True, + type="Wild Encounter"), + LocationData("Route 23 North", "Wild Pokemon - 3", "Spearow", rom_addresses["Wild_Route23"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Route 23 North", "Wild Pokemon - 4", "Fearow", rom_addresses["Wild_Route23"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Route 23 North", "Wild Pokemon - 5", "Ditto", rom_addresses["Wild_Route23"] + 9, None, event=True, + type="Wild Encounter"), + LocationData("Route 23 North", "Wild Pokemon - 6", "Fearow", rom_addresses["Wild_Route23"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Route 23 North", "Wild Pokemon - 7", ["Arbok", "Sandslash"], rom_addresses["Wild_Route23"] + 13, + None, event=True, type="Wild Encounter"), + LocationData("Route 23 North", "Wild Pokemon - 8", "Ditto", rom_addresses["Wild_Route23"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Route 23 North", "Wild Pokemon - 9", "Fearow", rom_addresses["Wild_Route23"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Route 23 North", "Wild Pokemon - 10", "Fearow", rom_addresses["Wild_Route23"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 2F", "Wild Pokemon - 1", "Machop", rom_addresses["Wild_VictoryRoad2F"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 2F", "Wild Pokemon - 2", "Geodude", rom_addresses["Wild_VictoryRoad2F"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 2F", "Wild Pokemon - 3", "Zubat", rom_addresses["Wild_VictoryRoad2F"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 2F", "Wild Pokemon - 4", "Onix", rom_addresses["Wild_VictoryRoad2F"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 2F", "Wild Pokemon - 5", "Onix", rom_addresses["Wild_VictoryRoad2F"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 2F", "Wild Pokemon - 6", "Onix", rom_addresses["Wild_VictoryRoad2F"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 2F", "Wild Pokemon - 7", "Machoke", rom_addresses["Wild_VictoryRoad2F"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 2F", "Wild Pokemon - 8", "Golbat", rom_addresses["Wild_VictoryRoad2F"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 2F", "Wild Pokemon - 9", "Marowak", rom_addresses["Wild_VictoryRoad2F"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 2F", "Wild Pokemon - 10", "Graveler", rom_addresses["Wild_VictoryRoad2F"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 3F", "Wild Pokemon - 1", "Machop", rom_addresses["Wild_VictoryRoad3F"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 3F", "Wild Pokemon - 2", "Geodude", rom_addresses["Wild_VictoryRoad3F"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 3F", "Wild Pokemon - 3", "Zubat", rom_addresses["Wild_VictoryRoad3F"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 3F", "Wild Pokemon - 4", "Onix", rom_addresses["Wild_VictoryRoad3F"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 3F", "Wild Pokemon - 5", "Venomoth", rom_addresses["Wild_VictoryRoad3F"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 3F", "Wild Pokemon - 6", "Onix", rom_addresses["Wild_VictoryRoad3F"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 3F", "Wild Pokemon - 7", "Graveler", rom_addresses["Wild_VictoryRoad3F"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 3F", "Wild Pokemon - 8", "Golbat", rom_addresses["Wild_VictoryRoad3F"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 3F", "Wild Pokemon - 9", "Machoke", rom_addresses["Wild_VictoryRoad3F"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 3F", "Wild Pokemon - 10", "Machoke", rom_addresses["Wild_VictoryRoad3F"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 1F", "Wild Pokemon - 1", "Machop", rom_addresses["Wild_VictoryRoad1F"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 1F", "Wild Pokemon - 2", "Geodude", rom_addresses["Wild_VictoryRoad1F"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 1F", "Wild Pokemon - 3", "Zubat", rom_addresses["Wild_VictoryRoad1F"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 1F", "Wild Pokemon - 4", "Onix", rom_addresses["Wild_VictoryRoad1F"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 1F", "Wild Pokemon - 5", "Onix", rom_addresses["Wild_VictoryRoad1F"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 1F", "Wild Pokemon - 6", "Onix", rom_addresses["Wild_VictoryRoad1F"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 1F", "Wild Pokemon - 7", "Graveler", rom_addresses["Wild_VictoryRoad1F"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 1F", "Wild Pokemon - 8", "Golbat", rom_addresses["Wild_VictoryRoad1F"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 1F", "Wild Pokemon - 9", "Machoke", rom_addresses["Wild_VictoryRoad1F"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Victory Road 1F", "Wild Pokemon - 10", "Marowak", rom_addresses["Wild_VictoryRoad1F"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Diglett's Cave", "Wild Pokemon - 1", "Diglett", rom_addresses["Wild_DiglettsCave"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Diglett's Cave", "Wild Pokemon - 2", "Diglett", rom_addresses["Wild_DiglettsCave"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Diglett's Cave", "Wild Pokemon - 3", "Diglett", rom_addresses["Wild_DiglettsCave"] + 5, None, + event=True, type="Wild Encounter"), + LocationData("Diglett's Cave", "Wild Pokemon - 4", "Diglett", rom_addresses["Wild_DiglettsCave"] + 7, None, + event=True, type="Wild Encounter"), + LocationData("Diglett's Cave", "Wild Pokemon - 5", "Diglett", rom_addresses["Wild_DiglettsCave"] + 9, None, + event=True, type="Wild Encounter"), + LocationData("Diglett's Cave", "Wild Pokemon - 6", "Diglett", rom_addresses["Wild_DiglettsCave"] + 11, None, + event=True, type="Wild Encounter"), + LocationData("Diglett's Cave", "Wild Pokemon - 7", "Diglett", rom_addresses["Wild_DiglettsCave"] + 13, None, + event=True, type="Wild Encounter"), + LocationData("Diglett's Cave", "Wild Pokemon - 8", "Diglett", rom_addresses["Wild_DiglettsCave"] + 15, None, + event=True, type="Wild Encounter"), + LocationData("Diglett's Cave", "Wild Pokemon - 9", "Dugtrio", rom_addresses["Wild_DiglettsCave"] + 17, None, + event=True, type="Wild Encounter"), + LocationData("Diglett's Cave", "Wild Pokemon - 10", "Dugtrio", rom_addresses["Wild_DiglettsCave"] + 19, None, + event=True, type="Wild Encounter"), + LocationData("Anywhere", "Good Rod Pokemon - 1", "Goldeen", rom_addresses["Wild_Good_Rod"] + 1, None, + event=True, type="Wild Encounter"), + LocationData("Anywhere", "Good Rod Pokemon - 2", "Poliwag", rom_addresses["Wild_Good_Rod"] + 3, None, + event=True, type="Wild Encounter"), + LocationData("Anywhere", "Old Rod Pokemon", "Magikarp", rom_addresses["Wild_Old_Rod"] + 1, None, + event=True, type="Wild Encounter"), + + # "Wild encounters" means a Pokemon you cannot miss or release and lose - re-use it for these + LocationData("Celadon Prize Corner", "Pokemon Prize - 1", "Abra", [rom_addresses["Prize_Mon_A"], + rom_addresses["Prize_Mon_A2"]], None, event=True, + type="Wild Encounter"), + LocationData("Celadon Prize Corner", "Pokemon Prize - 2", "Clefairy", [rom_addresses["Prize_Mon_B"], + rom_addresses["Prize_Mon_B2"]], None, + event=True, type="Wild Encounter"), + LocationData("Celadon Prize Corner", "Pokemon Prize - 3", ["Nidorina", "Nidorino"], [rom_addresses["Prize_Mon_C"], + rom_addresses["Prize_Mon_C2"]], + None, + event=True, type="Wild Encounter"), + LocationData("Celadon Prize Corner", "Pokemon Prize - 4", ["Dratini", "Pinsir"], [rom_addresses["Prize_Mon_D"], + rom_addresses["Prize_Mon_D2"]], + None, event=True, type="Wild Encounter"), + LocationData("Celadon Prize Corner", "Pokemon Prize - 5", ["Scyther", "Dratini"], [rom_addresses["Prize_Mon_E"], + rom_addresses["Prize_Mon_E2"]], + None, event=True, type="Wild Encounter"), + LocationData("Celadon Prize Corner", "Pokemon Prize - 6", "Porygon", [rom_addresses["Prize_Mon_F"], + rom_addresses["Prize_Mon_F2"]], None, + event=True, type="Wild Encounter"), + + # counted for pokedex, because they cannot be permanently "missed" but not for HMs since they can be released + # or evolved forms may not be able to learn the same HMs + LocationData("Celadon City", "Celadon Mansion Pokemon", "Eevee", rom_addresses["Gift_Eevee"], None, + event=True, type="Static Pokemon"), + LocationData("Silph Co 7F", "Gift Pokemon", "Lapras", rom_addresses["Gift_Lapras"], None, + event=True, type="Static Pokemon"), + LocationData("Route 3", "Pokemon For Sale", "Magikarp", rom_addresses["Gift_Magikarp"], None, + event=True, type="Static Pokemon"), + LocationData("Cinnabar Island", "Old Amber Pokemon", "Aerodactyl", rom_addresses["Gift_Aerodactyl"], None, + event=True, type="Static Pokemon"), + LocationData("Cinnabar Island", "Helix Fossil Pokemon", "Omanyte", rom_addresses["Gift_Omanyte"], None, + event=True, type="Static Pokemon"), + LocationData("Cinnabar Island", "Dome Fossil Pokemon", "Kabuto", rom_addresses["Gift_Kabuto"], 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"), + LocationData("Power Plant", "Fake Pokeball Battle 2", "Voltorb", rom_addresses["Static_Encounter_Voltorb_B"], + None, event=True, type="Missable Pokemon"), + LocationData("Power Plant", "Fake Pokeball Battle 3", "Voltorb", rom_addresses["Static_Encounter_Voltorb_C"], + None, event=True, type="Missable Pokemon"), + LocationData("Power Plant", "Fake Pokeball Battle 4", "Voltorb", rom_addresses["Static_Encounter_Voltorb_D"], + None, event=True, type="Missable Pokemon"), + LocationData("Power Plant", "Fake Pokeball Battle 5", "Voltorb", rom_addresses["Static_Encounter_Voltorb_E"], + None, event=True, type="Missable Pokemon"), + LocationData("Power Plant", "Fake Pokeball Battle 6", "Voltorb", rom_addresses["Static_Encounter_Voltorb_F"], + None, event=True, type="Missable Pokemon"), + LocationData("Power Plant", "Fake Pokeball Battle 7", "Voltorb", rom_addresses["Static_Encounter_Electrode_A"], + None, event=True, type="Missable Pokemon"), + LocationData("Power Plant", "Fake Pokeball Battle 8", "Voltorb", rom_addresses["Static_Encounter_Electrode_B"], + None, event=True, type="Missable Pokemon"), + + LocationData("Pokemon Tower 6F", "Restless Soul", "Marowak", [rom_addresses["Ghost_Battle1"], + rom_addresses["Ghost_Battle2"], + rom_addresses["Ghost_Battle3"], + rom_addresses["Ghost_Battle4"], + rom_addresses["Ghost_Battle5"], + rom_addresses["Ghost_Battle6"]], None, event=True, + type="Missable Pokemon"), + + LocationData("Route 12 West", "Sleeping Pokemon", "Snorlax", rom_addresses["Static_Encounter_Snorlax_A"], + None, event=True, type="Missable Pokemon"), + LocationData("Route 16", "Sleeping Pokemon", "Snorlax", rom_addresses["Static_Encounter_Snorlax_B"], + None, event=True, type="Missable Pokemon"), + + LocationData("Saffron City", "Fighting Dojo Gift 1", "Hitmonlee", rom_addresses["Gift_Hitmonlee"], + None, event=True, type="Missable Pokemon"), + LocationData("Saffron City", "Fighting Dojo Gift 2", "Hitmonchan", rom_addresses["Gift_Hitmonchan"], + None, event=True, type="Missable Pokemon"), + + LocationData("Pallet Town", "Starter 1", "Charmander", [rom_addresses["Starter1_A"], + rom_addresses["Starter1_B"], rom_addresses["Starter1_C"], + rom_addresses["Starter1_D"], + rom_addresses["Starter1_F"], rom_addresses["Starter1_H"]], + None, event=True, + type="Starter Pokemon"), + + LocationData("Pallet Town", "Starter 2", "Squirtle", [rom_addresses["Starter2_A"], + rom_addresses["Starter2_B"], rom_addresses["Starter2_E"], + rom_addresses["Starter2_F"], + rom_addresses["Starter2_G"], rom_addresses["Starter2_H"], + rom_addresses["Starter2_I"], + rom_addresses["Starter2_J"], rom_addresses["Starter2_K"], + rom_addresses["Starter2_L"], + rom_addresses["Starter2_M"], rom_addresses["Starter2_N"], + rom_addresses["Starter2_O"]], None, + event=True, type="Starter Pokemon"), + + LocationData("Pallet Town", "Starter 3", "Bulbasaur", [rom_addresses["Starter3_A"], + rom_addresses["Starter3_B"], rom_addresses["Starter3_C"], + rom_addresses["Starter3_D"], + rom_addresses["Starter3_E"], rom_addresses["Starter3_G"], + rom_addresses["Starter3_I"], + rom_addresses["Starter3_J"], rom_addresses["Starter3_K"], + rom_addresses["Starter3_L"], + rom_addresses["Starter3_M"], rom_addresses["Starter3_N"], + rom_addresses["Starter3_O"]], None, + event=True, type="Starter Pokemon"), + + LocationData("Power Plant", "Legendary Pokemon", "Zapdos", rom_addresses["Static_Encounter_Zapdos"], + None, event=True, type="Legendary Pokemon"), + LocationData("Seafoam Islands B4F", "Legendary Pokemon", "Articuno", rom_addresses["Static_Encounter_Articuno"], + None, event=True, type="Legendary Pokemon"), + LocationData("Victory Road 2F", "Legendary Pokemon", "Moltres", rom_addresses["Static_Encounter_Moltres"], + None, event=True, type="Legendary Pokemon"), + LocationData("Cerulean Cave B1F", "Legendary Pokemon", "Mewtwo", rom_addresses["Static_Encounter_Mewtwo"], + None, event=True, type="Legendary Pokemon"), + LocationData("Vermilion City", "Legendary Pokemon", "Mew", rom_addresses["Static_Encounter_Mew"], + None, event=True, type="Legendary Pokemon"), +] + +for i, location in enumerate(location_data): + if location.event or location.rom_address is None: + location.address = None + else: + location.address = loc_id_start + i + + + +class PokemonRBLocation(Location): + game = "Pokemon Red and Blue" + + def __init__(self, player, name, address, rom_address): + super(PokemonRBLocation, self).__init__( + player, name, + address + ) + self.rom_address = rom_address \ No newline at end of file diff --git a/worlds/pokemon_rb/logic.py b/worlds/pokemon_rb/logic.py new file mode 100644 index 00000000..3b1a3594 --- /dev/null +++ b/worlds/pokemon_rb/logic.py @@ -0,0 +1,73 @@ +from ..AutoWorld import LogicMixin +import worlds.pokemon_rb.poke_data as poke_data + + +class PokemonLogic(LogicMixin): + def pokemon_rb_can_surf(self, player): + return (((self.has("HM03 Surf", player) and self.can_learn_hm("10000", player)) + or self.has("Flippers", player)) and (self.has("Soul Badge", player) or + self.has(self.world.worlds[player].extra_badges.get("Surf"), player) + or self.world.badges_needed_for_hm_moves[player].value == 0)) + + def pokemon_rb_can_cut(self, player): + return ((self.has("HM01 Cut", player) and self.can_learn_hm("100", player) or self.has("Master Sword", player)) + and (self.has("Cascade Badge", player) or + self.has(self.world.worlds[player].extra_badges.get("Cut"), player) or + self.world.badges_needed_for_hm_moves[player].value == 0)) + + def pokemon_rb_can_fly(self, player): + return (((self.has("HM02 Fly", player) and self.can_learn_hm("1000", player)) or self.has("Flute", player)) and + (self.has("Thunder Badge", player) or self.has(self.world.worlds[player].extra_badges.get("Fly"), player) + or self.world.badges_needed_for_hm_moves[player].value == 0)) + + def pokemon_rb_can_strength(self, player): + return ((self.has("HM04 Strength", player) and self.can_learn_hm("100000", player)) or + self.has("Titan's Mitt", player)) and (self.has("Rainbow Badge", player) or + self.has(self.world.worlds[player].extra_badges.get("Strength"), player) + or self.world.badges_needed_for_hm_moves[player].value == 0) + + def pokemon_rb_can_flash(self, player): + return (((self.has("HM05 Flash", player) and self.can_learn_hm("1000000", player)) or self.has("Lamp", player)) + and (self.has("Boulder Badge", player) or self.has(self.world.worlds[player].extra_badges.get("Flash"), + player) or self.world.badges_needed_for_hm_moves[player].value == 0)) + + def can_learn_hm(self, move, player): + for pokemon, data in self.world.worlds[player].local_poke_data.items(): + if self.has(pokemon, player) and data["tms"][6] & int(move, 2): + return True + return False + + def pokemon_rb_can_get_hidden_items(self, player): + return self.has("Item Finder", player) or not self.world.require_item_finder[player].value + + def pokemon_rb_cerulean_cave(self, count, player): + return len([item for item in + ["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 + + def pokemon_rb_can_pass_guards(self, player): + if self.world.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): + return len([item for item in ["Boulder Badge", "Cascade Badge", "Thunder Badge", "Rainbow Badge", "Marsh Badge", + "Soul Badge", "Volcano Badge", "Earth Badge"] if self.has(item, player)]) >= count + + def pokemon_rb_has_pokemon(self, count, player): + obtained_pokemon = set() + for pokemon in poke_data.pokemon_data.keys(): + if self.has(pokemon, player) or self.has(f"Static {pokemon}", player): + obtained_pokemon.add(pokemon) + + return len(obtained_pokemon) >= count + + def pokemon_rb_fossil_checks(self, count, player): + return (self.can_reach('Mt Moon 1F - Southwest Item', 'Location', player) and + self.can_reach('Cinnabar Island - Lab Scientist', 'Location', player) and len( + [item for item in ["Dome Fossil", "Helix Fossil", "Old Amber"] if self.has(item, player)]) >= count) diff --git a/worlds/pokemon_rb/options.py b/worlds/pokemon_rb/options.py new file mode 100644 index 00000000..37672c25 --- /dev/null +++ b/worlds/pokemon_rb/options.py @@ -0,0 +1,481 @@ + +from Options import Toggle, Choice, Range, SpecialRange, FreeText, TextChoice + + +class GameVersion(Choice): + """Select Red or Blue version.""" + display_name = "Game Version" + option_red = 1 + option_blue = 0 + default = "random" + + +class TrainerName(FreeText): + """Your trainer name. Cannot exceed 7 characters. + See the setup guide on archipelago.gg for a list of allowed characters.""" + display_name = "Trainer Name" + default = "ASH" + + +class RivalName(FreeText): + """Your rival's name. Cannot exceed 7 characters. + See the setup guide on archipelago.gg for a list of allowed characters.""" + display_name = "Rival's Name" + default = "GARY" + + +class Goal(Choice): + """If Professor Oak is selected, your victory condition will require challenging and defeating Oak after becoming""" + """Champion and defeating or capturing the Pokemon at the end of Cerulean Cave.""" + display_name = "Goal" + option_pokemon_league = 0 + option_professor_oak = 1 + default = 0 + + +class EliteFourCondition(Range): + """Number of badges required to challenge the Elite Four once the Indigo Plateau has been reached. + Your rival will reveal the amount needed on the first Route 22 battle (after turning in Oak's Parcel).""" + display_name = "Elite Four Condition" + range_start = 0 + range_end = 8 + default = 8 + + +class VictoryRoadCondition(Range): + """Number of badges required to reach Victory Road.""" + display_name = "Victory Road Condition" + range_start = 0 + range_end = 8 + default = 8 + + +class ViridianGymCondition(Range): + """Number of badges required to enter Viridian Gym.""" + display_name = "Viridian Gym Condition" + range_start = 0 + range_end = 7 + default = 7 + + +class CeruleanCaveCondition(Range): + """Number of badges, HMs, and key items (not counting items you can lose) required to access Cerulean Cave.""" + """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 + default = 20 + + +class SecondFossilCheckCondition(Range): + """After choosing one of the fossil location items, you can obtain the remaining item from the Cinnabar Lab + Scientist after reviving this number of fossils.""" + display_name = "Second Fossil Check Condition" + range_start = 0 + range_end = 3 + default = 3 + + +class BadgeSanity(Toggle): + """Shuffle gym badges into the general item pool. If turned off, badges will be shuffled across the 8 gyms.""" + display_name = "Badgesanity" + default = 0 + + +class BadgesNeededForHMMoves(Choice): + """Off will remove the requirement for badges to use HM moves. Extra will give the Marsh, Volcano, and Earth + Badges a random HM move to enable. Extra Plus will additionally pick two random badges to enable a second HM move. + A man in Cerulean City will reveal the moves enabled by each Badge.""" + display_name = "Badges Needed For HM Moves" + default = 1 + option_on = 1 + alias_true = 1 + option_off = 0 + alias_false = 0 + option_extra = 2 + option_extra_plus = 3 + + +class OldMan(Choice): + """With Open Viridian City, the Old Man will let you through without needing to turn in Oak's Parcel.""" + """Early Parcel will ensure Oak's Parcel is available at the beginning of your game.""" + display_name = "Old Man" + option_vanilla = 0 + option_early_parcel = 1 + option_open_viridian_city = 2 + default = 1 + + +class Tea(Toggle): + """Adds a Tea item to the item pool which the Saffron guards require instead of the vending machine drinks. + Adds a location check to the Celadon Mansion 1F, where Tea is acquired in FireRed and LeafGreen.""" + display_name = "Tea" + default = 0 + + +class ExtraKeyItems(Toggle): + """Adds key items that are required to access the Rocket Hideout, Cinnabar Mansion, Safari Zone, and Power Plant. + Adds four item pickups to Rock Tunnel B1F.""" + display_name = "Extra Key Items" + default = 0 + + +class ExtraStrengthBoulders(Toggle): + """Adds Strength Boulders blocking the Route 11 gate, and in Route 13 (can be bypassed with Surf). + This potentially increases the usefulness of Strength as well as the Bicycle.""" + display_name = "Extra Strength Boulders" + default = 0 + + +class RequireItemFinder(Toggle): + """Require Item Finder to pick up hidden items.""" + display_name = "Require Item Finder" + default = 0 + + +class RandomizeHiddenItems(Choice): + """Randomize hidden items. If you choose exclude, they will be randomized but will be guaranteed junk items.""" + display_name = "Randomize Hidden Items" + option_on = 1 + option_off = 0 + alias_true = 1 + alias_false = 0 + option_exclude = 2 + default = 0 + + +class FreeFlyLocation(Toggle): + """One random fly destination will be unlocked by default.""" + display_name = "Free Fly Location" + default = 1 + + +class OaksAidRt2(Range): + """Number of Pokemon registered in the Pokedex required to receive the item from Oak's Aide on Route 2""" + display_name = "Oak's Aide Route 2" + range_start = 0 + range_end = 80 + default = 10 + + +class OaksAidRt11(Range): + """Number of Pokemon registered in the Pokedex required to receive the item from Oak's Aide on Route 11""" + display_name = "Oak's Aide Route 11" + range_start = 0 + range_end = 80 + default = 30 + + +class OaksAidRt15(Range): + """Number of Pokemon registered in the Pokedex required to receive the item from Oak's Aide on Route 15""" + display_name = "Oak's Aide Route 15" + range_start = 0 + range_end = 80 + default = 50 + + +class ExpModifier(SpecialRange): + """Modifier for EXP gained. When specifying a number, exp is multiplied by this amount and divided by 16.""" + display_name = "Exp Modifier" + range_start = 0 + range_end = 255 + default = 16 + special_range_names = { + "half": default / 2, + "normal": default, + "double": default * 2, + "triple": default * 3, + "quadruple": default * 4, + "quintuple": default * 5, + "sextuple": default * 6, + "septuple": default * 7, + "octuple": default * 8, + } + + +class RandomizeWildPokemon(Choice): + """Randomize all wild Pokemon and game corner prize Pokemon. match_types will select a Pokemon with at least one + type matching the original type of the original Pokemon. match_base_stats will prefer Pokemon with closer base stat + totals. match_types_and_base_stats will match types and will weight towards similar base stats, but there may not be + many to choose from.""" + display_name = "Randomize Wild Pokemon" + default = 0 + option_vanilla = 0 + option_match_types = 1 + option_match_base_stats = 2 + option_match_types_and_base_stats = 3 + option_completely_random = 4 + + +class RandomizeStarterPokemon(Choice): + """Randomize the starter Pokemon choices.""" + display_name = "Randomize Starter Pokemon" + default = 0 + option_vanilla = 0 + option_match_types = 1 + option_match_base_stats = 2 + option_match_types_and_base_stats = 3 + option_completely_random = 4 + + +class RandomizeStaticPokemon(Choice): + """Randomize all one-time gift and encountered Pokemon, except legendaries. + These will always be first evolution stage Pokemon.""" + display_name = "Randomize Static Pokemon" + default = 0 + option_vanilla = 0 + option_match_types = 1 + option_match_base_stats = 2 + option_match_types_and_base_stats = 3 + option_completely_random = 4 + + +class RandomizeLegendaryPokemon(Choice): + """Randomize Legendaries. Mew has been added as an encounter at the Vermilion dock truck. + Shuffle will shuffle the legendaries with each other. Static will shuffle them into other static Pokemon locations. + 'Any' will allow legendaries to appear anywhere based on wild and static randomization options, and their locations + will be randomized according to static Pokemon randomization options.""" + display_name = "Randomize Legendary Pokemon" + default = 0 + option_vanilla = 0 + option_shuffle = 1 + option_static = 2 + option_any = 3 + + +class CatchEmAll(Choice): + """Guarantee all first evolution stage Pokemon are available, or all Pokemon of all stages. + Currently only has an effect if wild Pokemon are randomized.""" + display_name = "Catch 'Em All" + default = 0 + option_off = 0 + alias_false = 0 + option_first_stage = 1 + option_all_pokemon = 2 + + +class RandomizeTrainerParties(Choice): + """Randomize enemy Pokemon encountered in trainer battles.""" + display_name = "Randomize Trainer Parties" + default = 0 + option_vanilla = 0 + option_match_types = 1 + option_match_base_stats = 2 + option_match_types_and_base_stats = 3 + option_completely_random = 4 + + +class TrainerLegendaries(Toggle): + """Allow legendary Pokemon in randomized trainer parties.""" + display_name = "Trainer Legendaries" + default = 0 + + +class BlindTrainers(Range): + """Chance each frame that you are standing on a tile in a trainer's line of sight that they will fail to initiate a + battle. If you move into and out of their line of sight without stopping, this chance will only trigger once.""" + display_name = "Blind Trainers" + range_start = 0 + range_end = 100 + default = 0 + + +class MinimumStepsBetweenEncounters(Range): + """Minimum number of steps between wild Pokemon encounters.""" + display_name = "Minimum Steps Between Encounters" + default = 3 + range_start = 0 + range_end = 255 + + +class RandomizePokemonStats(Choice): + """Randomize base stats for each Pokemon. Shuffle will shuffle the 5 base stat values amongst each other. Randomize + will completely randomize each stat, but will still add up to the same base stat total.""" + display_name = "Randomize Pokemon Stats" + default = 0 + option_vanilla = 0 + option_shuffle = 1 + option_randomize = 2 + + +class RandomizePokemonCatchRates(Toggle): + """Randomize the catch rate for each Pokemon.""" + display_name = "Randomize Catch Rates" + default = 0 + + +class MinimumCatchRate(Range): + """Minimum catch rate for each Pokemon. If randomize_catch_rates is on, this will be the minimum value that can be + chosen. Otherwise, it will raise any Pokemon's catch rate up to this value if its normal catch rate is lower.""" + display_name = "Minimum Catch Rate" + range_start = 1 + range_end = 255 + default = 3 + + +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" + option_vanilla = 0 + option_prefer_types = 1 + option_completely_random = 2 + default = 0 + + +class StartWithFourMoves(Toggle): + """If movesets are randomized, this will give all Pokemon 4 starting moves.""" + display_name = "Start With Four Moves" + default = 0 + + +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 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 RandomizePokemonTypes(Choice): + """Randomize the types of each Pokemon. Follow Evolutions will ensure Pokemon's types remain the same when evolving + (except possibly gaining a type).""" + display_name = "Pokemon Types" + option_vanilla = 0 + option_follow_evolutions = 1 + option_randomize = 2 + default = 0 + + +class SecondaryTypeChance(SpecialRange): + """If randomize_pokemon_types is on, this is the chance each Pokemon will have a secondary type. If follow_evolutions + is selected, it is the chance a second type will be added at each evolution stage. vanilla will give secondary types + to Pokemon that normally have a secondary type.""" + display_name = "Secondary Type Chance" + range_start = -1 + range_end = 100 + default = -1 + special_range_names = { + "vanilla": -1 + } + + +class RandomizeTypeChartTypes(Choice): + """The game's type chart consists of 3 columns: attacking type, defending type, and type effectiveness. + Matchups that have regular type effectiveness are not in the chart. Shuffle will shuffle the attacking types + across the attacking type column and the defending types across the defending type column (so for example Normal + type will still have exactly 2 types that it receives non-regular damage from, and 2 types it deals non-regular + damage to). Randomize will randomize each type in both columns to any random type.""" + display_name = "Randomize Type Chart Types" + option_vanilla = 0 + option_shuffle = 1 + option_randomize = 2 + default = 0 + + +class RandomizeTypeChartTypeEffectiveness(Choice): + """The game's type chart consists of 3 columns: attacking type, defending type, and type effectiveness. + Matchups that have regular type effectiveness are not in the chart. Shuffle will shuffle the type effectiveness + across the type effectiveness column (so for example there will always be 6 type immunities). Randomize will + randomize each entry in the table to no effect, not very effective, or super effective; with no effect occurring + at a low chance. Chaos will randomize the values to anywhere between 0% and 200% damage, in 10% increments.""" + display_name = "Randomize Type Chart Type Effectiveness" + option_vanilla = 0 + option_shuffle = 1 + option_randomize = 2 + option_chaos = 3 + default = 0 + + +class SafariZoneNormalBattles(Toggle): + """Change the Safari Zone to have standard wild pokemon battles.""" + display_name = "Safari Zone Normal Battles" + default = 0 + + +class NormalizeEncounterChances(Toggle): + """Each wild encounter table has 10 slots for Pokemon. Normally the chance for each being chosen ranges from + 19.9% to 1.2%. Turn this on to normalize them all to 10% each.""" + display_name = "Normalize Encounter Chances" + default = 0 + + +class ReusableTMs(Toggle): + """Makes TMs reusable, so they will not be consumed upon use.""" + display_name = "Reusable TMs" + default = 0 + + +class StartingMoney(Range): + """The amount of money you start with.""" + display_name = "Starting Money" + default = 3000 + range_start = 0 + range_end = 999999 + + +pokemon_rb_options = { + "game_version": GameVersion, + "trainer_name": TrainerName, + "rival_name": RivalName, + #"goal": Goal, + "elite_four_condition": EliteFourCondition, + "victory_road_condition": VictoryRoadCondition, + "viridian_gym_condition": ViridianGymCondition, + "cerulean_cave_condition": CeruleanCaveCondition, + "second_fossil_check_condition": SecondFossilCheckCondition, + "badgesanity": BadgeSanity, + "old_man": OldMan, + "tea": Tea, + "extra_key_items": ExtraKeyItems, + "extra_strength_boulders": ExtraStrengthBoulders, + "require_item_finder": RequireItemFinder, + "randomize_hidden_items": RandomizeHiddenItems, + "badges_needed_for_hm_moves": BadgesNeededForHMMoves, + "free_fly_location": FreeFlyLocation, + "oaks_aide_rt_2": OaksAidRt2, + "oaks_aide_rt_11": OaksAidRt11, + "oaks_aide_rt_15": OaksAidRt15, + "blind_trainers": BlindTrainers, + "minimum_steps_between_encounters": MinimumStepsBetweenEncounters, + "exp_modifier": ExpModifier, + "randomize_wild_pokemon": RandomizeWildPokemon, + "randomize_starter_pokemon": RandomizeStarterPokemon, + "randomize_static_pokemon": RandomizeStaticPokemon, + "randomize_legendary_pokemon": RandomizeLegendaryPokemon, + "catch_em_all": CatchEmAll, + "randomize_pokemon_stats": RandomizePokemonStats, + "randomize_pokemon_catch_rates": RandomizePokemonCatchRates, + "minimum_catch_rate": MinimumCatchRate, + "randomize_trainer_parties": RandomizeTrainerParties, + "trainer_legendaries": TrainerLegendaries, + "randomize_pokemon_movesets": RandomizePokemonMovesets, + "start_with_four_moves": StartWithFourMoves, + "tm_compatibility": TMCompatibility, + "hm_compatibility": HMCompatibility, + "randomize_pokemon_types": RandomizePokemonTypes, + "secondary_type_chance": SecondaryTypeChance, + "randomize_type_matchup_types": RandomizeTypeChartTypes, + "randomize_type_matchup_type_effectiveness": RandomizeTypeChartTypeEffectiveness, + "safari_zone_normal_battles": SafariZoneNormalBattles, + "normalize_encounter_chances": NormalizeEncounterChances, + "reusable_tms": ReusableTMs, + "starting_money": StartingMoney, +} \ No newline at end of file diff --git a/worlds/pokemon_rb/poke_data.py b/worlds/pokemon_rb/poke_data.py new file mode 100644 index 00000000..75222d57 --- /dev/null +++ b/worlds/pokemon_rb/poke_data.py @@ -0,0 +1,1212 @@ +id_to_mon = {1: 'Rhydon', 2: 'Kangaskhan', 3: 'Nidoran M', 4: 'Clefairy', 5: 'Spearow', 6: 'Voltorb', 7: 'Nidoking', + 8: 'Slowbro', 9: 'Ivysaur', 10: 'Exeggutor', 11: 'Lickitung', 12: 'Exeggcute', 13: 'Grimer', 14: 'Gengar', + 15: 'Nidoran F', 16: 'Nidoqueen', 17: 'Cubone', 18: 'Rhyhorn', 19: 'Lapras', 20: 'Arcanine', 21: 'Mew', + 22: 'Gyarados', 23: 'Shellder', 24: 'Tentacool', 25: 'Gastly', 26: 'Scyther', 27: 'Staryu', + 28: 'Blastoise', 29: 'Pinsir', 30: 'Tangela', 33: 'Growlithe', 34: 'Onix', 35: 'Fearow', 36: 'Pidgey', + 37: 'Slowpoke', 38: 'Kadabra', 39: 'Graveler', 40: 'Chansey', 41: 'Machoke', 42: 'Mr Mime', + 43: 'Hitmonlee', 44: 'Hitmonchan', 45: 'Arbok', 46: 'Parasect', 47: 'Psyduck', 48: 'Drowzee', 49: 'Golem', + 51: 'Magmar', 53: 'Electabuzz', 54: 'Magneton', 55: 'Koffing', 57: 'Mankey', 58: 'Seel', 59: 'Diglett', + 60: 'Tauros', 64: 'Farfetchd', 65: 'Venonat', 66: 'Dragonite', 70: 'Doduo', 71: 'Poliwag', 72: 'Jynx', + 73: 'Moltres', 74: 'Articuno', 75: 'Zapdos', 76: 'Ditto', 77: 'Meowth', 78: 'Krabby', 82: 'Vulpix', + 83: 'Ninetales', 84: 'Pikachu', 85: 'Raichu', 88: 'Dratini', 89: 'Dragonair', 90: 'Kabuto', 91: 'Kabutops', + 92: 'Horsea', 93: 'Seadra', 96: 'Sandshrew', 97: 'Sandslash', 98: 'Omanyte', 99: 'Omastar', + 100: 'Jigglypuff', 101: 'Wigglytuff', 102: 'Eevee', 103: 'Flareon', 104: 'Jolteon', 105: 'Vaporeon', + 106: 'Machop', 107: 'Zubat', 108: 'Ekans', 109: 'Paras', 110: 'Poliwhirl', 111: 'Poliwrath', 112: 'Weedle', + 113: 'Kakuna', 114: 'Beedrill', 116: 'Dodrio', 117: 'Primeape', 118: 'Dugtrio', 119: 'Venomoth', + 120: 'Dewgong', 123: 'Caterpie', 124: 'Metapod', 125: 'Butterfree', 126: 'Machamp', 128: 'Golduck', + 129: 'Hypno', 130: 'Golbat', 131: 'Mewtwo', 132: 'Snorlax', 133: 'Magikarp', 136: 'Muk', 138: 'Kingler', + 139: 'Cloyster', 141: 'Electrode', 142: 'Clefable', 143: 'Weezing', 144: 'Persian', 145: 'Marowak', + 147: 'Haunter', 148: 'Abra', 149: 'Alakazam', 150: 'Pidgeotto', 151: 'Pidgeot', 152: 'Starmie', + 153: 'Bulbasaur', 154: 'Venusaur', 155: 'Tentacruel', 157: 'Goldeen', 158: 'Seaking', 163: 'Ponyta', + 164: 'Rapidash', 165: 'Rattata', 166: 'Raticate', 167: 'Nidorino', 168: 'Nidorina', 169: 'Geodude', + 170: 'Porygon', 171: 'Aerodactyl', 173: 'Magnemite', 176: 'Charmander', 177: 'Squirtle', 178: 'Charmeleon', + 179: 'Wartortle', 180: 'Charizard', 185: 'Oddish', 186: 'Gloom', 187: 'Vileplume', 188: 'Bellsprout', + 189: 'Weepinbell', 190: 'Victreebel'} + + +pokemon_dex = { + 'Bulbasaur': 1, 'Ivysaur': 2, 'Venusaur': 3, 'Charmander': 4, 'Charmeleon': 5, 'Charizard': 6, 'Squirtle': 7, + 'Wartortle': 8, 'Blastoise': 9, 'Caterpie': 10, 'Metapod': 11, 'Butterfree': 12, 'Weedle': 13, 'Kakuna': 14, + 'Beedrill': 15, 'Pidgey': 16, 'Pidgeotto': 17, 'Pidgeot': 18, 'Rattata': 19, 'Raticate': 20, 'Spearow': 21, + 'Fearow': 22, 'Ekans': 23, 'Arbok': 24, 'Pikachu': 25, 'Raichu': 26, 'Sandshrew': 27, 'Sandslash': 28, + 'Nidoran F': 29, 'Nidorina': 30, 'Nidoqueen': 31, 'Nidoran M': 32, 'Nidorino': 33, 'Nidoking': 34, 'Clefairy': 35, + 'Clefable': 36, 'Vulpix': 37, 'Ninetales': 38, 'Jigglypuff': 39, 'Wigglytuff': 40, 'Zubat': 41, 'Golbat': 42, + 'Oddish': 43, 'Gloom': 44, 'Vileplume': 45, 'Paras': 46, 'Parasect': 47, 'Venonat': 48, 'Venomoth': 49, + 'Diglett': 50, 'Dugtrio': 51, 'Meowth': 52, 'Persian': 53, 'Psyduck': 54, 'Golduck': 55, 'Mankey': 56, + 'Primeape': 57, 'Growlithe': 58, 'Arcanine': 59, 'Poliwag': 60, 'Poliwhirl': 61, 'Poliwrath': 62, 'Abra': 63, + 'Kadabra': 64, 'Alakazam': 65, 'Machop': 66, 'Machoke': 67, 'Machamp': 68, 'Bellsprout': 69, 'Weepinbell': 70, + 'Victreebel': 71, 'Tentacool': 72, 'Tentacruel': 73, 'Geodude': 74, 'Graveler': 75, 'Golem': 76, 'Ponyta': 77, + 'Rapidash': 78, 'Slowpoke': 79, 'Slowbro': 80, 'Magnemite': 81, 'Magneton': 82, 'Farfetchd': 83, 'Doduo': 84, + 'Dodrio': 85, 'Seel': 86, 'Dewgong': 87, 'Grimer': 88, 'Muk': 89, 'Shellder': 90, 'Cloyster': 91, 'Gastly': 92, + 'Haunter': 93, 'Gengar': 94, 'Onix': 95, 'Drowzee': 96, 'Hypno': 97, 'Krabby': 98, 'Kingler': 99, 'Voltorb': 100, + 'Electrode': 101, 'Exeggcute': 102, 'Exeggutor': 103, 'Cubone': 104, 'Marowak': 105, 'Hitmonlee': 106, + 'Hitmonchan': 107, 'Lickitung': 108, 'Koffing': 109, 'Weezing': 110, 'Rhyhorn': 111, 'Rhydon': 112, 'Chansey': 113, + 'Tangela': 114, 'Kangaskhan': 115, 'Horsea': 116, 'Seadra': 117, 'Goldeen': 118, 'Seaking': 119, 'Staryu': 120, + 'Starmie': 121, 'Mr Mime': 122, 'Scyther': 123, 'Jynx': 124, 'Electabuzz': 125, 'Magmar': 126, 'Pinsir': 127, + 'Tauros': 128, 'Magikarp': 129, 'Gyarados': 130, 'Lapras': 131, 'Ditto': 132, 'Eevee': 133, 'Vaporeon': 134, + 'Jolteon': 135, 'Flareon': 136, 'Porygon': 137, 'Omanyte': 138, 'Omastar': 139, 'Kabuto': 140, 'Kabutops': 141, + 'Aerodactyl': 142, 'Snorlax': 143, 'Articuno': 144, 'Zapdos': 145, 'Moltres': 146, 'Dratini': 147, 'Dragonair': 148, + 'Dragonite': 149, 'Mewtwo': 150, 'Mew': 151 +} + + +type_ids = { + "Normal": 0x0, + "Fighting": 0x1, + "Flying": 0x2, + "Poison": 0x3, + "Ground": 0x4, + "Rock": 0x5, + "Bug": 0x7, + "Ghost": 0x8, + "Fire": 0x14, + "Water": 0x15, + "Grass": 0x16, + "Electric": 0x17, + "Psychic": 0x18, + "Ice": 0x19, + "Dragon": 0x1A +} +type_names = { + 0x0: "Normal", + 0x1: "Fighting", + 0x2: "Flying", + 0x3: "Poison", + 0x4: "Ground", + 0x5: "Rock", + 0x7: "Bug", + 0x8: "Ghost", + 0x14: "Fire", + 0x15: "Water", + 0x16: "Grass", + 0x17: "Electric", + 0x18: "Psychic", + 0x19: "Ice", + 0x1a: "Dragon" +} + +type_chart = [ + ["Water", "Fire", 20], + ["Fire", "Grass", 20], + ["Fire", "Ice", 20], + ["Grass", "Water", 20], + ["Electric", "Water", 20], + ["Water", "Rock", 20], + ["Ground", "Flying", 0], + ["Water", "Water", 5], + ["Fire", "Fire", 5], + ["Electric", "Electric", 5], + ["Ice", "Ice", 5], + ["Grass", "Grass", 5], + ["Psychic", "Psychic", 5], + ["Fire", "Water", 5], + ["Grass", "Fire", 5], + ["Water", "Grass", 5], + ["Electric", "Grass", 5], + ["Normal", "Rock", 5], + ["Normal", "Ghost", 0], + ["Ghost", "Ghost", 20], + ["Fire", "Bug", 20], + ["Fire", "Rock", 5], + ["Water", "Ground", 20], + ["Electric", "Ground", 0], + ["Electric", "Flying", 20], + ["Grass", "Ground", 20], + ["Grass", "Bug", 5], + ["Grass", "Poison", 5], + ["Grass", "Rock", 20], + ["Grass", "Flying", 5], + ["Ice", "Water", 5], + ["Ice", "Grass", 20], + ["Ice", "Ground", 20], + ["Ice", "Flying", 20], + ["Fighting", "Normal", 20], + ["Fighting", "Poison", 5], + ["Fighting", "Flying", 5], + ["Fighting", "Psychic", 5], + ["Fighting", "Bug", 5], + ["Fighting", "Rock", 20], + ["Fighting", "Ice", 20], + ["Fighting", "Ghost", 0], + ["Poison", "Grass", 20], + ["Poison", "Poison", 5], + ["Poison", "Ground", 5], + ["Poison", "Bug", 20], + ["Poison", "Rock", 5], + ["Poison", "Ghost", 5], + ["Ground", "Fire", 20], + ["Ground", "Electric", 20], + ["Ground", "Grass", 5], + ["Ground", "Bug", 5], + ["Ground", "Rock", 20], + ["Ground", "Poison", 20], + ["Flying", "Electric", 5], + ["Flying", "Fighting", 20], + ["Flying", "Bug", 20], + ["Flying", "Grass", 20], + ["Flying", "Rock", 5], + ["Psychic", "Fighting", 20], + ["Psychic", "Poison", 20], + ["Bug", "Fire", 5], + ["Bug", "Grass", 20], + ["Bug", "Fighting", 5], + ["Bug", "Flying", 5], + ["Bug", "Psychic", 20], + ["Bug", "Ghost", 5], + ["Bug", "Poison", 20], + ["Rock", "Fire", 20], + ["Rock", "Fighting", 5], + ["Rock", "Ground", 5], + ["Rock", "Flying", 20], + ["Rock", "Bug", 20], + ["Rock", "Ice", 20], + ["Ghost", "Normal", 0], + ["Ghost", "Psychic", 0], + ["Fire", "Dragon", 5], + ["Water", "Dragon", 5], + ["Electric", "Dragon", 5], + ["Grass", "Dragon", 5], + ["Ice", "Dragon", 20], + ["Dragon", "Dragon", 20] +] + +pokemon_data = { + 'Bulbasaur': {'id': 153, 'dex': 1, 'hp': 45, 'atk': 49, 'def': 49, 'spd': 45, 'spc': 65, 'type1': 'Grass', + 'type2': 'Poison', 'catch rate': 45, 'base exp': 64, 'start move 1': 'Tackle', + 'start move 2': 'Growl', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xa4\x038\xc0\x03\x08\x06')}, + 'Ivysaur': {'id': 9, 'dex': 2, 'hp': 60, 'atk': 62, 'def': 63, 'spd': 60, 'spc': 80, 'type1': 'Grass', + 'type2': 'Poison', 'catch rate': 45, 'base exp': 141, 'start move 1': 'Tackle', 'start move 2': 'Growl', + 'start move 3': 'Leech Seed', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xa4\x038\xc0\x03\x08\x06')}, + 'Venusaur': {'id': 154, 'dex': 3, 'hp': 80, 'atk': 82, 'def': 83, 'spd': 80, 'spc': 100, 'type1': 'Grass', + 'type2': 'Poison', 'catch rate': 45, 'base exp': 208, 'start move 1': 'Tackle', + 'start move 2': 'Growl', 'start move 3': 'Leech Seed', 'start move 4': 'Vine Whip', 'growth rate': 3, + 'tms': bytearray(b'\xa4C8\xc0\x03\x08\x06')}, + 'Charmander': {'id': 176, 'dex': 4, 'hp': 39, 'atk': 52, 'def': 43, 'spd': 65, 'spc': 50, 'type1': 'Fire', + 'type2': 'Fire', 'catch rate': 45, 'base exp': 65, 'start move 1': 'Scratch', + 'start move 2': 'Growl', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xb5\x03O\xc8\xe3\x08&')}, + 'Charmeleon': {'id': 178, 'dex': 5, 'hp': 58, 'atk': 64, 'def': 58, 'spd': 80, 'spc': 65, 'type1': 'Fire', + 'type2': 'Fire', 'catch rate': 45, 'base exp': 142, 'start move 1': 'Scratch', + 'start move 2': 'Growl', 'start move 3': 'Ember', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xb5\x03O\xc8\xe3\x08&')}, + 'Charizard': {'id': 180, 'dex': 6, 'hp': 78, 'atk': 84, 'def': 78, 'spd': 100, 'spc': 85, 'type1': 'Fire', + 'type2': 'Flying', 'catch rate': 45, 'base exp': 209, 'start move 1': 'Scratch', + 'start move 2': 'Growl', 'start move 3': 'Ember', 'start move 4': 'Leer', 'growth rate': 3, + 'tms': bytearray(b'\xb5CO\xce\xe3\x08&')}, + 'Squirtle': {'id': 177, 'dex': 7, 'hp': 44, 'atk': 48, 'def': 65, 'spd': 43, 'spc': 50, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 45, 'base exp': 66, 'start move 1': 'Tackle', + 'start move 2': 'Tail Whip', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xb1?\x0f\xc8\x83\x082')}, + 'Wartortle': {'id': 179, 'dex': 8, 'hp': 59, 'atk': 63, 'def': 80, 'spd': 58, 'spc': 65, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 45, 'base exp': 143, 'start move 1': 'Tackle', + 'start move 2': 'Tail Whip', 'start move 3': 'Bubble', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xb1?\x0f\xc8\x83\x082')}, + 'Blastoise': {'id': 28, 'dex': 9, 'hp': 79, 'atk': 83, 'def': 100, 'spd': 78, 'spc': 85, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 45, 'base exp': 210, 'start move 1': 'Tackle', + 'start move 2': 'Tail Whip', 'start move 3': 'Bubble', 'start move 4': 'Water Gun', 'growth rate': 3, + 'tms': bytearray(b'\xb1\x7f\x0f\xce\x83\x082')}, + 'Caterpie': {'id': 123, 'dex': 10, 'hp': 45, 'atk': 30, 'def': 35, 'spd': 45, 'spc': 20, 'type1': 'Bug', + 'type2': 'Bug', 'catch rate': 255, 'base exp': 53, 'start move 1': 'Tackle', + 'start move 2': 'String Shot', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\x00\x00\x00\x00\x00\x00\x00')}, + 'Metapod': {'id': 124, 'dex': 11, 'hp': 50, 'atk': 20, 'def': 55, 'spd': 30, 'spc': 25, 'type1': 'Bug', + 'type2': 'Bug', 'catch rate': 120, 'base exp': 72, 'start move 1': 'Harden', 'start move 2': 'No Move', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\x00\x00\x00\x00\x00\x00\x00')}, + 'Butterfree': {'id': 125, 'dex': 12, 'hp': 60, 'atk': 45, 'def': 50, 'spd': 70, 'spc': 80, 'type1': 'Bug', + 'type2': 'Flying', 'catch rate': 45, 'base exp': 160, 'start move 1': 'Confusion', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'*C8\xf0C(\x02')}, + 'Weedle': {'id': 112, 'dex': 13, 'hp': 40, 'atk': 35, 'def': 30, 'spd': 50, 'spc': 20, 'type1': 'Bug', + 'type2': 'Poison', 'catch rate': 255, 'base exp': 52, 'start move 1': 'Poison Sting', + 'start move 2': 'String Shot', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\x00\x00\x00\x00\x00\x00\x00')}, + 'Kakuna': {'id': 113, 'dex': 14, 'hp': 45, 'atk': 25, 'def': 50, 'spd': 35, 'spc': 25, 'type1': 'Bug', + 'type2': 'Poison', 'catch rate': 120, 'base exp': 71, 'start move 1': 'Harden', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\x00\x00\x00\x00\x00\x00\x00')}, + 'Beedrill': {'id': 114, 'dex': 15, 'hp': 65, 'atk': 80, 'def': 40, 'spd': 75, 'spc': 45, 'type1': 'Bug', + 'type2': 'Poison', 'catch rate': 45, 'base exp': 159, 'start move 1': 'Fury Attack', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'$C\x18\xc0\xc3\x08\x06')}, + 'Pidgey': {'id': 36, 'dex': 16, 'hp': 40, 'atk': 45, 'def': 40, 'spd': 56, 'spc': 35, 'type1': 'Normal', + 'type2': 'Flying', 'catch rate': 255, 'base exp': 55, 'start move 1': 'Gust', 'start move 2': 'No Move', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'*\x03\x08\xc0C\x0c\n')}, + 'Pidgeotto': {'id': 150, 'dex': 17, 'hp': 63, 'atk': 60, 'def': 55, 'spd': 71, 'spc': 50, 'type1': 'Normal', + 'type2': 'Flying', 'catch rate': 120, 'base exp': 113, 'start move 1': 'Gust', + 'start move 2': 'Sand Attack', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'*\x03\x08\xc0C\x0c\n')}, + 'Pidgeot': {'id': 151, 'dex': 18, 'hp': 83, 'atk': 80, 'def': 75, 'spd': 91, 'spc': 70, 'type1': 'Normal', + 'type2': 'Flying', 'catch rate': 45, 'base exp': 172, 'start move 1': 'Gust', + 'start move 2': 'Sand Attack', 'start move 3': 'Quick Attack', 'start move 4': 'No Move', + 'growth rate': 3, 'tms': bytearray(b'*C\x08\xc0C\x0c\n')}, + 'Rattata': {'id': 165, 'dex': 19, 'hp': 30, 'atk': 56, 'def': 35, 'spd': 72, 'spc': 25, 'type1': 'Normal', + 'type2': 'Normal', 'catch rate': 255, 'base exp': 57, 'start move 1': 'Tackle', + 'start move 2': 'Tail Whip', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa0/\x88\xc9\xc2\x08\x02')}, + 'Raticate': {'id': 166, 'dex': 20, 'hp': 55, 'atk': 81, 'def': 60, 'spd': 97, 'spc': 50, 'type1': 'Normal', + 'type2': 'Normal', 'catch rate': 90, 'base exp': 116, 'start move 1': 'Tackle', + 'start move 2': 'Tail Whip', 'start move 3': 'Quick Attack', 'start move 4': 'No Move', + 'growth rate': 0, 'tms': bytearray(b'\xa0\x7f\x88\xc9\xc2\x08\x02')}, + 'Spearow': {'id': 5, 'dex': 21, 'hp': 40, 'atk': 60, 'def': 30, 'spd': 70, 'spc': 31, 'type1': 'Normal', + 'type2': 'Flying', 'catch rate': 255, 'base exp': 58, 'start move 1': 'Peck', 'start move 2': 'Growl', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'*\x03\x08\xc0B\x0c\n')}, + 'Fearow': {'id': 35, 'dex': 22, 'hp': 65, 'atk': 90, 'def': 65, 'spd': 100, 'spc': 61, 'type1': 'Normal', + 'type2': 'Flying', 'catch rate': 90, 'base exp': 162, 'start move 1': 'Peck', 'start move 2': 'Growl', + 'start move 3': 'Leer', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'*C\x08\xc0B\x0c\n')}, + 'Ekans': {'id': 108, 'dex': 23, 'hp': 35, 'atk': 60, 'def': 44, 'spd': 55, 'spc': 40, 'type1': 'Poison', + 'type2': 'Poison', 'catch rate': 255, 'base exp': 62, 'start move 1': 'Wrap', 'start move 2': 'Leer', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa0\x03\x18\xce\x82\x88"')}, + 'Arbok': {'id': 45, 'dex': 24, 'hp': 60, 'atk': 85, 'def': 69, 'spd': 80, 'spc': 65, 'type1': 'Poison', + 'type2': 'Poison', 'catch rate': 90, 'base exp': 147, 'start move 1': 'Wrap', 'start move 2': 'Leer', + 'start move 3': 'Poison Sting', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa0C\x18\xce\x82\x88"')}, + 'Pikachu': {'id': 84, 'dex': 25, 'hp': 35, 'atk': 55, 'def': 30, 'spd': 90, 'spc': 50, 'type1': 'Electric', + 'type2': 'Electric', 'catch rate': 190, 'base exp': 82, 'start move 1': 'Thundershock', + 'start move 2': 'Growl', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb1\x83\x8d\xc1\xc3\x18B')}, + 'Raichu': {'id': 85, 'dex': 26, 'hp': 60, 'atk': 90, 'def': 55, 'spd': 100, 'spc': 90, 'type1': 'Electric', + 'type2': 'Electric', 'catch rate': 75, 'base exp': 122, 'start move 1': 'Thundershock', + 'start move 2': 'Growl', 'start move 3': 'Thunder Wave', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb1\xc3\x8d\xc1\xc3\x18B')}, + 'Sandshrew': {'id': 96, 'dex': 27, 'hp': 50, 'atk': 75, 'def': 85, 'spd': 40, 'spc': 30, 'type1': 'Ground', + 'type2': 'Ground', 'catch rate': 255, 'base exp': 93, 'start move 1': 'Scratch', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa4\x03\r\xce\xc2\x88&')}, + 'Sandslash': {'id': 97, 'dex': 28, 'hp': 75, 'atk': 100, 'def': 110, 'spd': 65, 'spc': 55, 'type1': 'Ground', + 'type2': 'Ground', 'catch rate': 90, 'base exp': 163, 'start move 1': 'Scratch', + 'start move 2': 'Sand Attack', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa4C\r\xce\xc2\x88&')}, + 'Nidoran F': {'id': 15, 'dex': 29, 'hp': 55, 'atk': 47, 'def': 52, 'spd': 41, 'spc': 40, 'type1': 'Poison', + 'type2': 'Poison', 'catch rate': 235, 'base exp': 59, 'start move 1': 'Growl', + 'start move 2': 'Tackle', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xa0#\x88\xc1\x83\x08\x02')}, + 'Nidorina': {'id': 168, 'dex': 30, 'hp': 70, 'atk': 62, 'def': 67, 'spd': 56, 'spc': 55, 'type1': 'Poison', + 'type2': 'Poison', 'catch rate': 120, 'base exp': 117, 'start move 1': 'Growl', + 'start move 2': 'Tackle', 'start move 3': 'Scratch', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xe0?\x88\xc1\x83\x08\x02')}, + 'Nidoqueen': {'id': 16, 'dex': 31, 'hp': 90, 'atk': 82, 'def': 87, 'spd': 76, 'spc': 75, 'type1': 'Poison', + 'type2': 'Ground', 'catch rate': 45, 'base exp': 194, 'start move 1': 'Tackle', + 'start move 2': 'Scratch', 'start move 3': 'Tail Whip', 'start move 4': 'Body Slam', 'growth rate': 3, + 'tms': bytearray(b'\xf1\xff\x8f\xc7\xa3\x882')}, + 'Nidoran M': {'id': 3, 'dex': 32, 'hp': 46, 'atk': 57, 'def': 40, 'spd': 50, 'spc': 40, 'type1': 'Poison', + 'type2': 'Poison', 'catch rate': 235, 'base exp': 60, 'start move 1': 'Leer', + 'start move 2': 'Tackle', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xe0#\x88\xc1\x83\x08\x02')}, + 'Nidorino': {'id': 167, 'dex': 33, 'hp': 61, 'atk': 72, 'def': 57, 'spd': 65, 'spc': 55, 'type1': 'Poison', + 'type2': 'Poison', 'catch rate': 120, 'base exp': 118, 'start move 1': 'Leer', + 'start move 2': 'Tackle', 'start move 3': 'Horn Attack', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xe0?\x88\xc1\x83\x08\x02')}, + 'Nidoking': {'id': 7, 'dex': 34, 'hp': 81, 'atk': 92, 'def': 77, 'spd': 85, 'spc': 75, 'type1': 'Poison', + 'type2': 'Ground', 'catch rate': 45, 'base exp': 195, 'start move 1': 'Tackle', + 'start move 2': 'Horn Attack', 'start move 3': 'Poison Sting', 'start move 4': 'Thrash', + 'growth rate': 3, 'tms': bytearray(b'\xf1\xff\x8f\xc7\xa3\x882')}, + 'Clefairy': {'id': 4, 'dex': 35, 'hp': 70, 'atk': 45, 'def': 48, 'spd': 35, 'spc': 60, 'type1': 'Normal', + 'type2': 'Normal', 'catch rate': 150, 'base exp': 68, 'start move 1': 'Pound', 'start move 2': 'Growl', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 4, + 'tms': bytearray(b'\xb1?\xaf\xf1\xa78c')}, + 'Clefable': {'id': 142, 'dex': 36, 'hp': 95, 'atk': 70, 'def': 73, 'spd': 60, 'spc': 85, 'type1': 'Normal', + 'type2': 'Normal', 'catch rate': 25, 'base exp': 129, 'start move 1': 'Sing', + 'start move 2': 'Doubleslap', 'start move 3': 'Minimize', 'start move 4': 'Metronome', + 'growth rate': 4, 'tms': bytearray(b'\xb1\x7f\xaf\xf1\xa78c')}, + 'Vulpix': {'id': 82, 'dex': 37, 'hp': 38, 'atk': 41, 'def': 40, 'spd': 65, 'spc': 65, 'type1': 'Fire', + 'type2': 'Fire', 'catch rate': 190, 'base exp': 63, 'start move 1': 'Ember', 'start move 2': 'Tail Whip', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa0\x03\x08\xc8\xe3\x08\x02')}, + 'Ninetales': {'id': 83, 'dex': 38, 'hp': 73, 'atk': 76, 'def': 75, 'spd': 100, 'spc': 100, 'type1': 'Fire', + 'type2': 'Fire', 'catch rate': 75, 'base exp': 178, 'start move 1': 'Ember', + 'start move 2': 'Tail Whip', 'start move 3': 'Quick Attack', 'start move 4': 'Roar', 'growth rate': 0, + 'tms': bytearray(b'\xa0C\x08\xc8\xe3\x08\x02')}, + 'Jigglypuff': {'id': 100, 'dex': 39, 'hp': 115, 'atk': 45, 'def': 20, 'spd': 20, 'spc': 25, 'type1': 'Normal', + 'type2': 'Normal', 'catch rate': 170, 'base exp': 76, 'start move 1': 'Sing', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 4, + 'tms': bytearray(b'\xb1?\xaf\xf1\xa38c')}, + 'Wigglytuff': {'id': 101, 'dex': 40, 'hp': 140, 'atk': 70, 'def': 45, 'spd': 45, 'spc': 50, 'type1': 'Normal', + 'type2': 'Normal', 'catch rate': 50, 'base exp': 109, 'start move 1': 'Sing', + 'start move 2': 'Disable', 'start move 3': 'Defense Curl', 'start move 4': 'Doubleslap', + 'growth rate': 4, 'tms': bytearray(b'\xb1\x7f\xaf\xf1\xa38c')}, + 'Zubat': {'id': 107, 'dex': 41, 'hp': 40, 'atk': 45, 'def': 35, 'spd': 55, 'spc': 40, 'type1': 'Poison', + 'type2': 'Flying', 'catch rate': 255, 'base exp': 54, 'start move 1': 'Leech Life', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'*\x03\x18\xc0B\x08\x02')}, + 'Golbat': {'id': 130, 'dex': 42, 'hp': 75, 'atk': 80, 'def': 70, 'spd': 90, 'spc': 75, 'type1': 'Poison', + 'type2': 'Flying', 'catch rate': 90, 'base exp': 171, 'start move 1': 'Leech Life', + 'start move 2': 'Screech', 'start move 3': 'Bite', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'*C\x18\xc0B\x08\x02')}, + 'Oddish': {'id': 185, 'dex': 43, 'hp': 45, 'atk': 50, 'def': 55, 'spd': 30, 'spc': 75, 'type1': 'Grass', + 'type2': 'Poison', 'catch rate': 255, 'base exp': 78, 'start move 1': 'Absorb', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'$\x038\xc0\x03\x08\x06')}, + 'Gloom': {'id': 186, 'dex': 44, 'hp': 60, 'atk': 65, 'def': 70, 'spd': 40, 'spc': 85, 'type1': 'Grass', + 'type2': 'Poison', 'catch rate': 120, 'base exp': 132, 'start move 1': 'Absorb', + 'start move 2': 'Poisonpowder', 'start move 3': 'Stun Spore', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'$\x038\xc0\x03\x08\x06')}, + 'Vileplume': {'id': 187, 'dex': 45, 'hp': 75, 'atk': 80, 'def': 85, 'spd': 50, 'spc': 100, 'type1': 'Grass', + 'type2': 'Poison', 'catch rate': 45, 'base exp': 184, 'start move 1': 'Stun Spore', + 'start move 2': 'Sleep Powder', 'start move 3': 'Acid', 'start move 4': 'Petal Dance', + 'growth rate': 3, 'tms': bytearray(b'\xa4C8\xc0\x03\x08\x06')}, + 'Paras': {'id': 109, 'dex': 46, 'hp': 35, 'atk': 70, 'def': 55, 'spd': 25, 'spc': 55, 'type1': 'Bug', + 'type2': 'Grass', 'catch rate': 190, 'base exp': 70, 'start move 1': 'Scratch', 'start move 2': 'No Move', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa4\x038\xc8\x83\x08\x06')}, + 'Parasect': {'id': 46, 'dex': 47, 'hp': 60, 'atk': 95, 'def': 80, 'spd': 30, 'spc': 80, 'type1': 'Bug', + 'type2': 'Grass', 'catch rate': 75, 'base exp': 128, 'start move 1': 'Scratch', + 'start move 2': 'Stun Spore', 'start move 3': 'Leech Life', 'start move 4': 'No Move', + 'growth rate': 0, 'tms': bytearray(b'\xa4C8\xc8\x83\x08\x06')}, + 'Venonat': {'id': 65, 'dex': 48, 'hp': 60, 'atk': 55, 'def': 50, 'spd': 45, 'spc': 40, 'type1': 'Bug', + 'type2': 'Poison', 'catch rate': 190, 'base exp': 75, 'start move 1': 'Tackle', + 'start move 2': 'Disable', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b' \x038\xd0\x03(\x02')}, + 'Venomoth': {'id': 119, 'dex': 49, 'hp': 70, 'atk': 65, 'def': 60, 'spd': 90, 'spc': 90, 'type1': 'Bug', + 'type2': 'Poison', 'catch rate': 75, 'base exp': 138, 'start move 1': 'Tackle', + 'start move 2': 'Disable', 'start move 3': 'Poisonpowder', 'start move 4': 'Leech Life', + 'growth rate': 0, 'tms': bytearray(b'*C8\xf0C(\x02')}, + 'Diglett': {'id': 59, 'dex': 50, 'hp': 10, 'atk': 55, 'def': 25, 'spd': 95, 'spc': 45, 'type1': 'Ground', + 'type2': 'Ground', 'catch rate': 255, 'base exp': 81, 'start move 1': 'Scratch', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa0\x03\x08\xce\x02\x88\x02')}, + 'Dugtrio': {'id': 118, 'dex': 51, 'hp': 35, 'atk': 80, 'def': 50, 'spd': 120, 'spc': 70, 'type1': 'Ground', + 'type2': 'Ground', 'catch rate': 50, 'base exp': 153, 'start move 1': 'Scratch', + 'start move 2': 'Growl', 'start move 3': 'Dig', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa0C\x08\xce\x02\x88\x02')}, + 'Meowth': {'id': 77, 'dex': 52, 'hp': 40, 'atk': 45, 'def': 35, 'spd': 90, 'spc': 40, 'type1': 'Normal', + 'type2': 'Normal', 'catch rate': 255, 'base exp': 69, 'start move 1': 'Scratch', 'start move 2': 'Growl', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa0\x8f\x88\xc1\xc2\x08\x02')}, + 'Persian': {'id': 144, 'dex': 53, 'hp': 65, 'atk': 70, 'def': 60, 'spd': 115, 'spc': 65, 'type1': 'Normal', + 'type2': 'Normal', 'catch rate': 90, 'base exp': 148, 'start move 1': 'Scratch', + 'start move 2': 'Growl', 'start move 3': 'Bite', 'start move 4': 'Screech', 'growth rate': 0, + 'tms': bytearray(b'\xa0\xcf\x88\xc1\xc2\x08\x02')}, + 'Psyduck': {'id': 47, 'dex': 54, 'hp': 50, 'atk': 52, 'def': 48, 'spd': 55, 'spc': 50, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 190, 'base exp': 80, 'start move 1': 'Scratch', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb1\xbf\x0f\xc8\xc2\x082')}, + 'Golduck': {'id': 128, 'dex': 55, 'hp': 80, 'atk': 82, 'def': 78, 'spd': 85, 'spc': 80, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 75, 'base exp': 174, 'start move 1': 'Scratch', + 'start move 2': 'Tail Whip', 'start move 3': 'Disable', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb1\xff\x0f\xc8\xc2\x082')}, + 'Mankey': {'id': 57, 'dex': 56, 'hp': 40, 'atk': 80, 'def': 35, 'spd': 70, 'spc': 35, 'type1': 'Fighting', + 'type2': 'Fighting', 'catch rate': 190, 'base exp': 74, 'start move 1': 'Scratch', + 'start move 2': 'Leer', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb1\x83\x8f\xc9\xc6\x88"')}, + 'Primeape': {'id': 117, 'dex': 57, 'hp': 65, 'atk': 105, 'def': 60, 'spd': 95, 'spc': 60, 'type1': 'Fighting', + 'type2': 'Fighting', 'catch rate': 75, 'base exp': 149, 'start move 1': 'Scratch', + 'start move 2': 'Leer', 'start move 3': 'Karate Chop', 'start move 4': 'Fury Swipes', 'growth rate': 0, + 'tms': bytearray(b'\xb1\xc3\x8f\xc9\xc6\x88"')}, + 'Growlithe': {'id': 33, 'dex': 58, 'hp': 55, 'atk': 70, 'def': 45, 'spd': 60, 'spc': 50, 'type1': 'Fire', + 'type2': 'Fire', 'catch rate': 190, 'base exp': 91, 'start move 1': 'Bite', 'start move 2': 'Roar', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b'\xa0\x03H\xc8\xe3\x08\x02')}, + 'Arcanine': {'id': 20, 'dex': 59, 'hp': 90, 'atk': 110, 'def': 80, 'spd': 95, 'spc': 80, 'type1': 'Fire', + 'type2': 'Fire', 'catch rate': 75, 'base exp': 213, 'start move 1': 'Roar', 'start move 2': 'Ember', + 'start move 3': 'Leer', 'start move 4': 'Take Down', 'growth rate': 5, + 'tms': bytearray(b'\xa0CH\xe8\xe3\x08\x02')}, + 'Poliwag': {'id': 71, 'dex': 60, 'hp': 40, 'atk': 50, 'def': 40, 'spd': 90, 'spc': 40, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 255, 'base exp': 77, 'start move 1': 'Bubble', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xa0?\x08\xd0\x82(\x12')}, + 'Poliwhirl': {'id': 110, 'dex': 61, 'hp': 65, 'atk': 65, 'def': 65, 'spd': 90, 'spc': 50, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 120, 'base exp': 131, 'start move 1': 'Bubble', + 'start move 2': 'Hypnosis', 'start move 3': 'Water Gun', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xb1?\x0f\xd6\x86(2')}, + 'Poliwrath': {'id': 111, 'dex': 62, 'hp': 90, 'atk': 85, 'def': 95, 'spd': 70, 'spc': 70, 'type1': 'Water', + 'type2': 'Fighting', 'catch rate': 45, 'base exp': 185, 'start move 1': 'Hypnosis', + 'start move 2': 'Water Gun', 'start move 3': 'Doubleslap', 'start move 4': 'Body Slam', + 'growth rate': 3, 'tms': bytearray(b'\xb1\x7f\x0f\xd6\x86(2')}, + 'Abra': {'id': 148, 'dex': 63, 'hp': 25, 'atk': 20, 'def': 15, 'spd': 90, 'spc': 105, 'type1': 'Psychic', + 'type2': 'Psychic', 'catch rate': 200, 'base exp': 73, 'start move 1': 'Teleport', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xb1\x03\x0f\xf0\x878C')}, + 'Kadabra': {'id': 38, 'dex': 64, 'hp': 40, 'atk': 35, 'def': 30, 'spd': 105, 'spc': 120, 'type1': 'Psychic', + 'type2': 'Psychic', 'catch rate': 100, 'base exp': 145, 'start move 1': 'Teleport', + 'start move 2': 'Confusion', 'start move 3': 'Disable', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xb1\x03\x0f\xf8\x878C')}, + 'Alakazam': {'id': 149, 'dex': 65, 'hp': 55, 'atk': 50, 'def': 45, 'spd': 120, 'spc': 135, 'type1': 'Psychic', + 'type2': 'Psychic', 'catch rate': 50, 'base exp': 186, 'start move 1': 'Teleport', + 'start move 2': 'Confusion', 'start move 3': 'Disable', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xb1C\x0f\xf8\x878C')}, + 'Machop': {'id': 106, 'dex': 66, 'hp': 70, 'atk': 80, 'def': 50, 'spd': 35, 'spc': 35, 'type1': 'Fighting', + 'type2': 'Fighting', 'catch rate': 180, 'base exp': 88, 'start move 1': 'Karate Chop', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xb1\x03\x0f\xce\xa6\x88"')}, + 'Machoke': {'id': 41, 'dex': 67, 'hp': 80, 'atk': 100, 'def': 70, 'spd': 45, 'spc': 50, 'type1': 'Fighting', + 'type2': 'Fighting', 'catch rate': 90, 'base exp': 146, 'start move 1': 'Karate Chop', + 'start move 2': 'Low Kick', 'start move 3': 'Leer', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xb1\x03\x0f\xce\xa6\x88"')}, + 'Machamp': {'id': 126, 'dex': 68, 'hp': 90, 'atk': 130, 'def': 80, 'spd': 55, 'spc': 65, 'type1': 'Fighting', + 'type2': 'Fighting', 'catch rate': 45, 'base exp': 193, 'start move 1': 'Karate Chop', + 'start move 2': 'Low Kick', 'start move 3': 'Leer', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xb1C\x0f\xce\xa6\x88"')}, + 'Bellsprout': {'id': 188, 'dex': 69, 'hp': 50, 'atk': 75, 'def': 35, 'spd': 40, 'spc': 70, 'type1': 'Grass', + 'type2': 'Poison', 'catch rate': 255, 'base exp': 84, 'start move 1': 'Vine Whip', + 'start move 2': 'Growth', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'$\x038\xc0\x03\x08\x06')}, + 'Weepinbell': {'id': 189, 'dex': 70, 'hp': 65, 'atk': 90, 'def': 50, 'spd': 55, 'spc': 85, 'type1': 'Grass', + 'type2': 'Poison', 'catch rate': 120, 'base exp': 151, 'start move 1': 'Vine Whip', + 'start move 2': 'Growth', 'start move 3': 'Wrap', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'$\x038\xc0\x03\x08\x06')}, + 'Victreebel': {'id': 190, 'dex': 71, 'hp': 80, 'atk': 105, 'def': 65, 'spd': 70, 'spc': 100, 'type1': 'Grass', + 'type2': 'Poison', 'catch rate': 45, 'base exp': 191, 'start move 1': 'Sleep Powder', + 'start move 2': 'Stun Spore', 'start move 3': 'Acid', 'start move 4': 'Razor Leaf', 'growth rate': 3, + 'tms': bytearray(b'\xa4C8\xc0\x03\x08\x06')}, + 'Tentacool': {'id': 24, 'dex': 72, 'hp': 40, 'atk': 40, 'def': 35, 'spd': 70, 'spc': 100, 'type1': 'Water', + 'type2': 'Poison', 'catch rate': 190, 'base exp': 105, 'start move 1': 'Acid', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b'$?\x18\xc0\x83\x08\x16')}, + 'Tentacruel': {'id': 155, 'dex': 73, 'hp': 80, 'atk': 70, 'def': 65, 'spd': 100, 'spc': 120, 'type1': 'Water', + 'type2': 'Poison', 'catch rate': 60, 'base exp': 205, 'start move 1': 'Acid', + 'start move 2': 'Supersonic', 'start move 3': 'Wrap', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b'$\x7f\x18\xc0\x83\x08\x16')}, + 'Geodude': {'id': 169, 'dex': 74, 'hp': 40, 'atk': 80, 'def': 100, 'spd': 20, 'spc': 30, 'type1': 'Rock', + 'type2': 'Ground', 'catch rate': 255, 'base exp': 86, 'start move 1': 'Tackle', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xa1\x03\x0f\xce.\xc8"')}, + 'Graveler': {'id': 39, 'dex': 75, 'hp': 55, 'atk': 95, 'def': 115, 'spd': 35, 'spc': 45, 'type1': 'Rock', + 'type2': 'Ground', 'catch rate': 120, 'base exp': 134, 'start move 1': 'Tackle', + 'start move 2': 'Defense Curl', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xa1\x03\x0f\xce.\xc8"')}, + 'Golem': {'id': 49, 'dex': 76, 'hp': 80, 'atk': 110, 'def': 130, 'spd': 45, 'spc': 55, 'type1': 'Rock', + 'type2': 'Ground', 'catch rate': 45, 'base exp': 177, 'start move 1': 'Tackle', + 'start move 2': 'Defense Curl', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xb1C\x0f\xce.\xc8"')}, + 'Ponyta': {'id': 163, 'dex': 77, 'hp': 50, 'atk': 85, 'def': 55, 'spd': 90, 'spc': 65, 'type1': 'Fire', + 'type2': 'Fire', 'catch rate': 190, 'base exp': 152, 'start move 1': 'Ember', 'start move 2': 'No Move', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xe0\x03\x08\xc0\xe3\x08\x02')}, + 'Rapidash': {'id': 164, 'dex': 78, 'hp': 65, 'atk': 100, 'def': 70, 'spd': 105, 'spc': 80, 'type1': 'Fire', + 'type2': 'Fire', 'catch rate': 60, 'base exp': 192, 'start move 1': 'Ember', + 'start move 2': 'Tail Whip', 'start move 3': 'Stomp', 'start move 4': 'Growl', 'growth rate': 0, + 'tms': bytearray(b'\xe0C\x08\xc0\xe3\x08\x02')}, + 'Slowpoke': {'id': 37, 'dex': 79, 'hp': 90, 'atk': 65, 'def': 65, 'spd': 15, 'spc': 40, 'type1': 'Water', + 'type2': 'Psychic', 'catch rate': 190, 'base exp': 99, 'start move 1': 'Confusion', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa0\xbf\x08\xfe\xe38s')}, + 'Slowbro': {'id': 8, 'dex': 80, 'hp': 95, 'atk': 75, 'def': 110, 'spd': 30, 'spc': 80, 'type1': 'Water', + 'type2': 'Psychic', 'catch rate': 75, 'base exp': 164, 'start move 1': 'Confusion', + 'start move 2': 'Disable', 'start move 3': 'Headbutt', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb1\xff\x0f\xfe\xe38s')}, + 'Magnemite': {'id': 173, 'dex': 81, 'hp': 25, 'atk': 35, 'def': 70, 'spd': 45, 'spc': 95, 'type1': 'Electric', + 'type2': 'Electric', 'catch rate': 190, 'base exp': 89, 'start move 1': 'Tackle', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b' \x03\x88\xe1C\x18B')}, + 'Magneton': {'id': 54, 'dex': 82, 'hp': 50, 'atk': 60, 'def': 95, 'spd': 70, 'spc': 120, 'type1': 'Electric', + 'type2': 'Electric', 'catch rate': 60, 'base exp': 161, 'start move 1': 'Tackle', + 'start move 2': 'Sonicboom', 'start move 3': 'Thundershock', 'start move 4': 'No Move', + 'growth rate': 0, 'tms': bytearray(b' C\x88\xe1C\x18B')}, + 'Farfetchd': {'id': 64, 'dex': 83, 'hp': 52, 'atk': 65, 'def': 55, 'spd': 60, 'spc': 58, 'type1': 'Normal', + 'type2': 'Flying', 'catch rate': 45, 'base exp': 94, 'start move 1': 'Peck', + 'start move 2': 'Sand Attack', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xae\x03\x08\xc0\xc3\x08\x0e')}, + 'Doduo': {'id': 70, 'dex': 84, 'hp': 35, 'atk': 85, 'def': 45, 'spd': 75, 'spc': 35, 'type1': 'Normal', + 'type2': 'Flying', 'catch rate': 190, 'base exp': 96, 'start move 1': 'Peck', 'start move 2': 'No Move', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa8\x03\x08\xc0\x83\x0c\x0b')}, + 'Dodrio': {'id': 116, 'dex': 85, 'hp': 60, 'atk': 110, 'def': 70, 'spd': 100, 'spc': 60, 'type1': 'Normal', + 'type2': 'Flying', 'catch rate': 45, 'base exp': 158, 'start move 1': 'Peck', 'start move 2': 'Growl', + 'start move 3': 'Fury Attack', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa8C\x08\xc0\x83\x0c\x0b')}, + 'Seel': {'id': 58, 'dex': 86, 'hp': 65, 'atk': 45, 'def': 55, 'spd': 45, 'spc': 70, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 190, 'base exp': 100, 'start move 1': 'Headbutt', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xe0\xbf\x08\xc0\x82\x082')}, + 'Dewgong': {'id': 120, 'dex': 87, 'hp': 90, 'atk': 70, 'def': 80, 'spd': 70, 'spc': 95, 'type1': 'Water', + 'type2': 'Ice', 'catch rate': 75, 'base exp': 176, 'start move 1': 'Headbutt', 'start move 2': 'Growl', + 'start move 3': 'Aurora Beam', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xe0\xff\x08\xc0\x82\x082')}, + 'Grimer': {'id': 13, 'dex': 88, 'hp': 80, 'atk': 80, 'def': 50, 'spd': 25, 'spc': 40, 'type1': 'Poison', + 'type2': 'Poison', 'catch rate': 190, 'base exp': 90, 'start move 1': 'Pound', 'start move 2': 'Disable', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa0\x00\x98\xc1*H\x02')}, + 'Muk': {'id': 136, 'dex': 89, 'hp': 105, 'atk': 105, 'def': 75, 'spd': 50, 'spc': 65, 'type1': 'Poison', + 'type2': 'Poison', 'catch rate': 75, 'base exp': 157, 'start move 1': 'Pound', 'start move 2': 'Disable', + 'start move 3': 'Poison Gas', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa0@\x98\xc1*H\x02')}, + 'Shellder': {'id': 23, 'dex': 90, 'hp': 30, 'atk': 65, 'def': 100, 'spd': 40, 'spc': 45, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 190, 'base exp': 97, 'start move 1': 'Tackle', + 'start move 2': 'Withdraw', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b' ?\x08\xe0KH\x13')}, + 'Cloyster': {'id': 139, 'dex': 91, 'hp': 50, 'atk': 95, 'def': 180, 'spd': 70, 'spc': 85, 'type1': 'Water', + 'type2': 'Ice', 'catch rate': 60, 'base exp': 203, 'start move 1': 'Withdraw', + 'start move 2': 'Supersonic', 'start move 3': 'Clamp', 'start move 4': 'Aurora Beam', 'growth rate': 5, + 'tms': bytearray(b' \x7f\x08\xe0KH\x13')}, + 'Gastly': {'id': 25, 'dex': 92, 'hp': 30, 'atk': 35, 'def': 30, 'spd': 80, 'spc': 100, 'type1': 'Ghost', + 'type2': 'Poison', 'catch rate': 190, 'base exp': 95, 'start move 1': 'Lick', + 'start move 2': 'Confuse Ray', 'start move 3': 'Night Shade', 'start move 4': 'No Move', + 'growth rate': 3, 'tms': bytearray(b' \x00\x98\xd1\nj\x02')}, + 'Haunter': {'id': 147, 'dex': 93, 'hp': 45, 'atk': 50, 'def': 45, 'spd': 95, 'spc': 115, 'type1': 'Ghost', + 'type2': 'Poison', 'catch rate': 90, 'base exp': 126, 'start move 1': 'Lick', + 'start move 2': 'Confuse Ray', 'start move 3': 'Night Shade', 'start move 4': 'No Move', + 'growth rate': 3, 'tms': bytearray(b' \x00\x98\xd1\nj\x02')}, + 'Gengar': {'id': 14, 'dex': 94, 'hp': 60, 'atk': 65, 'def': 60, 'spd': 110, 'spc': 130, 'type1': 'Ghost', + 'type2': 'Poison', 'catch rate': 45, 'base exp': 190, 'start move 1': 'Lick', + 'start move 2': 'Confuse Ray', 'start move 3': 'Night Shade', 'start move 4': 'No Move', + 'growth rate': 3, 'tms': bytearray(b'\xb1C\x9f\xd1\x8ej"')}, + 'Onix': {'id': 34, 'dex': 95, 'hp': 35, 'atk': 45, 'def': 160, 'spd': 70, 'spc': 30, 'type1': 'Rock', + 'type2': 'Ground', 'catch rate': 45, 'base exp': 108, 'start move 1': 'Tackle', 'start move 2': 'Screech', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa0\x03\x08\xce\x8a\xc8"')}, + 'Drowzee': {'id': 48, 'dex': 96, 'hp': 60, 'atk': 48, 'def': 45, 'spd': 42, 'spc': 90, 'type1': 'Psychic', + 'type2': 'Psychic', 'catch rate': 190, 'base exp': 102, 'start move 1': 'Pound', + 'start move 2': 'Hypnosis', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb1\x03\x0f\xf0\x87:C')}, + 'Hypno': {'id': 129, 'dex': 97, 'hp': 85, 'atk': 73, 'def': 70, 'spd': 67, 'spc': 115, 'type1': 'Psychic', + 'type2': 'Psychic', 'catch rate': 75, 'base exp': 165, 'start move 1': 'Pound', + 'start move 2': 'Hypnosis', 'start move 3': 'Disable', 'start move 4': 'Confusion', 'growth rate': 0, + 'tms': bytearray(b'\xb1C\x0f\xf0\x87:C')}, + 'Krabby': {'id': 78, 'dex': 98, 'hp': 30, 'atk': 105, 'def': 90, 'spd': 50, 'spc': 25, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 225, 'base exp': 115, 'start move 1': 'Bubble', 'start move 2': 'Leer', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa4?\x08\xc0\x02\x086')}, + 'Kingler': {'id': 138, 'dex': 99, 'hp': 55, 'atk': 130, 'def': 115, 'spd': 75, 'spc': 50, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 60, 'base exp': 206, 'start move 1': 'Bubble', 'start move 2': 'Leer', + 'start move 3': 'Vicegrip', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa4\x7f\x08\xc0\x02\x086')}, + 'Voltorb': {'id': 6, 'dex': 100, 'hp': 40, 'atk': 30, 'def': 50, 'spd': 100, 'spc': 55, 'type1': 'Electric', + 'type2': 'Electric', 'catch rate': 190, 'base exp': 103, 'start move 1': 'Tackle', + 'start move 2': 'Screech', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b' \x01\x88\xe1KXB')}, + 'Electrode': {'id': 141, 'dex': 101, 'hp': 60, 'atk': 50, 'def': 70, 'spd': 140, 'spc': 80, 'type1': 'Electric', + 'type2': 'Electric', 'catch rate': 60, 'base exp': 150, 'start move 1': 'Tackle', + 'start move 2': 'Screech', 'start move 3': 'Sonicboom', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b' A\x88\xe1\xcbXB')}, + 'Exeggcute': {'id': 12, 'dex': 102, 'hp': 60, 'atk': 40, 'def': 80, 'spd': 40, 'spc': 60, 'type1': 'Grass', + 'type2': 'Psychic', 'catch rate': 90, 'base exp': 98, 'start move 1': 'Barrage', + 'start move 2': 'Hypnosis', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b' \x03\x08\xf0\x1bh\x02')}, + 'Exeggutor': {'id': 10, 'dex': 103, 'hp': 95, 'atk': 95, 'def': 85, 'spd': 55, 'spc': 125, 'type1': 'Grass', + 'type2': 'Psychic', 'catch rate': 45, 'base exp': 212, 'start move 1': 'Barrage', + 'start move 2': 'Hypnosis', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b' C8\xf0\x1bh"')}, + 'Cubone': {'id': 17, 'dex': 104, 'hp': 50, 'atk': 50, 'def': 95, 'spd': 35, 'spc': 40, 'type1': 'Ground', + 'type2': 'Ground', 'catch rate': 190, 'base exp': 87, 'start move 1': 'Bone Club', + 'start move 2': 'Growl', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb1?\x0f\xce\xa2\x08"')}, + 'Marowak': {'id': 145, 'dex': 105, 'hp': 60, 'atk': 80, 'def': 110, 'spd': 45, 'spc': 50, 'type1': 'Ground', + 'type2': 'Ground', 'catch rate': 75, 'base exp': 124, 'start move 1': 'Bone Club', + 'start move 2': 'Growl', 'start move 3': 'Leer', 'start move 4': 'Focus Energy', 'growth rate': 0, + 'tms': bytearray(b'\xb1\x7f\x0f\xce\xa2\x08"')}, + 'Hitmonlee': {'id': 43, 'dex': 106, 'hp': 50, 'atk': 120, 'def': 53, 'spd': 87, 'spc': 35, 'type1': 'Fighting', + 'type2': 'Fighting', 'catch rate': 45, 'base exp': 139, 'start move 1': 'Double Kick', + 'start move 2': 'Meditate', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb1\x03\x0f\xc0\xc6\x08"')}, + 'Hitmonchan': {'id': 44, 'dex': 107, 'hp': 50, 'atk': 105, 'def': 79, 'spd': 76, 'spc': 35, 'type1': 'Fighting', + 'type2': 'Fighting', 'catch rate': 45, 'base exp': 140, 'start move 1': 'Comet Punch', + 'start move 2': 'Agility', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb1\x03\x0f\xc0\xc6\x08"')}, + 'Lickitung': {'id': 11, 'dex': 108, 'hp': 90, 'atk': 55, 'def': 75, 'spd': 30, 'spc': 60, 'type1': 'Normal', + 'type2': 'Normal', 'catch rate': 45, 'base exp': 127, 'start move 1': 'Wrap', + 'start move 2': 'Supersonic', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb5\x7f\x8f\xc7\xa2\x086')}, + 'Koffing': {'id': 55, 'dex': 109, 'hp': 40, 'atk': 65, 'def': 95, 'spd': 35, 'spc': 60, 'type1': 'Poison', + 'type2': 'Poison', 'catch rate': 190, 'base exp': 114, 'start move 1': 'Tackle', 'start move 2': 'Smog', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b' \x00\x88\xc1*H\x02')}, + 'Weezing': {'id': 143, 'dex': 110, 'hp': 65, 'atk': 90, 'def': 120, 'spd': 60, 'spc': 85, 'type1': 'Poison', + 'type2': 'Poison', 'catch rate': 60, 'base exp': 173, 'start move 1': 'Tackle', 'start move 2': 'Smog', + 'start move 3': 'Sludge', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b' @\x88\xc1*H\x02')}, + 'Rhyhorn': {'id': 18, 'dex': 111, 'hp': 80, 'atk': 85, 'def': 95, 'spd': 25, 'spc': 30, 'type1': 'Ground', + 'type2': 'Rock', 'catch rate': 120, 'base exp': 135, 'start move 1': 'Horn Attack', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b'\xe0\x03\x88\xcf\xa2\x88"')}, + 'Rhydon': {'id': 1, 'dex': 112, 'hp': 105, 'atk': 130, 'def': 120, 'spd': 40, 'spc': 45, 'type1': 'Ground', + 'type2': 'Rock', 'catch rate': 60, 'base exp': 204, 'start move 1': 'Horn Attack', + 'start move 2': 'Stomp', 'start move 3': 'Tail Whip', 'start move 4': 'Fury Attack', 'growth rate': 5, + 'tms': bytearray(b'\xf1\xff\x8f\xcf\xa2\x882')}, + 'Chansey': {'id': 40, 'dex': 113, 'hp': 250, 'atk': 5, 'def': 5, 'spd': 50, 'spc': 105, 'type1': 'Normal', + 'type2': 'Normal', 'catch rate': 30, 'base exp': 255, 'start move 1': 'Pound', + 'start move 2': 'Doubleslap', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 4, + 'tms': bytearray(b'\xb1\x7f\xaf\xf1\xb79c')}, + 'Tangela': {'id': 30, 'dex': 114, 'hp': 65, 'atk': 55, 'def': 115, 'spd': 60, 'spc': 100, 'type1': 'Grass', + 'type2': 'Grass', 'catch rate': 45, 'base exp': 166, 'start move 1': 'Constrict', + 'start move 2': 'Bind', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa4C8\xc0\x82\x08\x06')}, + 'Kangaskhan': {'id': 2, 'dex': 115, 'hp': 105, 'atk': 95, 'def': 80, 'spd': 90, 'spc': 40, 'type1': 'Normal', + 'type2': 'Normal', 'catch rate': 45, 'base exp': 175, 'start move 1': 'Comet Punch', + 'start move 2': 'Rage', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb1\x7f\x8f\xc7\xa2\x882')}, + 'Horsea': {'id': 92, 'dex': 116, 'hp': 30, 'atk': 40, 'def': 70, 'spd': 60, 'spc': 70, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 225, 'base exp': 83, 'start move 1': 'Bubble', 'start move 2': 'No Move', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b' ?\x08\xc0\xc2\x08\x12')}, + 'Seadra': {'id': 93, 'dex': 117, 'hp': 55, 'atk': 65, 'def': 95, 'spd': 85, 'spc': 95, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 75, 'base exp': 155, 'start move 1': 'Bubble', + 'start move 2': 'Smokescreen', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b' \x7f\x08\xc0\xc2\x08\x12')}, + 'Goldeen': {'id': 157, 'dex': 118, 'hp': 45, 'atk': 67, 'def': 60, 'spd': 63, 'spc': 50, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 225, 'base exp': 111, 'start move 1': 'Peck', + 'start move 2': 'Tail Whip', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'`?\x08\xc0\xc2\x08\x12')}, + 'Seaking': {'id': 158, 'dex': 119, 'hp': 80, 'atk': 92, 'def': 65, 'spd': 68, 'spc': 80, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 60, 'base exp': 170, 'start move 1': 'Peck', + 'start move 2': 'Tail Whip', 'start move 3': 'Supersonic', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'`\x7f\x08\xc0\xc2\x08\x12')}, + 'Staryu': {'id': 27, 'dex': 120, 'hp': 30, 'atk': 45, 'def': 55, 'spd': 85, 'spc': 70, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 225, 'base exp': 106, 'start move 1': 'Tackle', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b' ?\x88\xf1\xc38S')}, + 'Starmie': {'id': 152, 'dex': 121, 'hp': 60, 'atk': 75, 'def': 85, 'spd': 115, 'spc': 100, 'type1': 'Water', + 'type2': 'Psychic', 'catch rate': 60, 'base exp': 207, 'start move 1': 'Tackle', + 'start move 2': 'Water Gun', 'start move 3': 'Harden', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b' \x7f\x88\xf1\xc38S')}, + 'Mr Mime': {'id': 42, 'dex': 122, 'hp': 40, 'atk': 45, 'def': 65, 'spd': 90, 'spc': 100, 'type1': 'Psychic', + 'type2': 'Psychic', 'catch rate': 45, 'base exp': 136, 'start move 1': 'Confusion', + 'start move 2': 'Barrier', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb1C\xaf\xf1\x878B')}, + 'Scyther': {'id': 26, 'dex': 123, 'hp': 70, 'atk': 110, 'def': 80, 'spd': 105, 'spc': 55, 'type1': 'Bug', + 'type2': 'Flying', 'catch rate': 45, 'base exp': 187, 'start move 1': 'Quick Attack', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'$C\x08\xc0\xc2\x08\x06')}, + 'Jynx': {'id': 72, 'dex': 124, 'hp': 65, 'atk': 50, 'def': 35, 'spd': 95, 'spc': 95, 'type1': 'Ice', + 'type2': 'Psychic', 'catch rate': 45, 'base exp': 137, 'start move 1': 'Pound', + 'start move 2': 'Lovely Kiss', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb1\x7f\x0f\xf0\x87(\x02')}, + 'Electabuzz': {'id': 53, 'dex': 125, 'hp': 65, 'atk': 83, 'def': 57, 'spd': 105, 'spc': 85, 'type1': 'Electric', + 'type2': 'Electric', 'catch rate': 45, 'base exp': 156, 'start move 1': 'Quick Attack', + 'start move 2': 'Leer', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb1C\x8f\xf1\xc78b')}, + 'Magmar': {'id': 51, 'dex': 126, 'hp': 65, 'atk': 95, 'def': 57, 'spd': 93, 'spc': 85, 'type1': 'Fire', + 'type2': 'Fire', 'catch rate': 45, 'base exp': 167, 'start move 1': 'Ember', 'start move 2': 'No Move', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb1C\x0f\xf0\xa6("')}, + 'Pinsir': {'id': 29, 'dex': 127, 'hp': 65, 'atk': 125, 'def': 100, 'spd': 85, 'spc': 55, 'type1': 'Bug', + 'type2': 'Bug', 'catch rate': 45, 'base exp': 200, 'start move 1': 'Vicegrip', 'start move 2': 'No Move', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b'\xa4C\r\xc0\x02\x08&')}, + 'Tauros': {'id': 60, 'dex': 128, 'hp': 75, 'atk': 100, 'def': 95, 'spd': 110, 'spc': 70, 'type1': 'Normal', + 'type2': 'Normal', 'catch rate': 45, 'base exp': 211, 'start move 1': 'Tackle', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b'\xe0s\x88\xc7\xa2\x08"')}, + 'Magikarp': {'id': 133, 'dex': 129, 'hp': 20, 'atk': 10, 'def': 55, 'spd': 80, 'spc': 20, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 255, 'base exp': 20, 'start move 1': 'Splash', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b'\x00\x00\x00\x00\x00\x00\x00')}, + 'Gyarados': {'id': 22, 'dex': 130, 'hp': 95, 'atk': 125, 'def': 79, 'spd': 81, 'spc': 100, 'type1': 'Water', + 'type2': 'Flying', 'catch rate': 45, 'base exp': 214, 'start move 1': 'Bite', + 'start move 2': 'Dragon Rage', 'start move 3': 'Leer', 'start move 4': 'Hydro Pump', 'growth rate': 5, + 'tms': bytearray(b'\xa0\x7f\xc8\xc1\xa3\x082')}, + 'Lapras': {'id': 19, 'dex': 131, 'hp': 130, 'atk': 85, 'def': 80, 'spd': 60, 'spc': 95, 'type1': 'Water', + 'type2': 'Ice', 'catch rate': 45, 'base exp': 219, 'start move 1': 'Water Gun', 'start move 2': 'Growl', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b'\xe0\x7f\xe8\xd1\x83(2')}, + 'Ditto': {'id': 76, 'dex': 132, 'hp': 48, 'atk': 48, 'def': 48, 'spd': 48, 'spc': 48, 'type1': 'Normal', + 'type2': 'Normal', 'catch rate': 35, 'base exp': 61, 'start move 1': 'Transform', + 'start move 2': 'No Move', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\x00\x00\x00\x00\x00\x00\x00')}, + 'Eevee': {'id': 102, 'dex': 133, 'hp': 55, 'atk': 55, 'def': 50, 'spd': 55, 'spc': 65, 'type1': 'Normal', + 'type2': 'Normal', 'catch rate': 45, 'base exp': 92, 'start move 1': 'Tackle', + 'start move 2': 'Sand Attack', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa0\x03\x08\xc0\xc3\x08\x02')}, + 'Vaporeon': {'id': 105, 'dex': 134, 'hp': 130, 'atk': 65, 'def': 60, 'spd': 65, 'spc': 110, 'type1': 'Water', + 'type2': 'Water', 'catch rate': 45, 'base exp': 196, 'start move 1': 'Tackle', + 'start move 2': 'Sand Attack', 'start move 3': 'Quick Attack', 'start move 4': 'Water Gun', + 'growth rate': 0, 'tms': bytearray(b'\xa0\x7f\x08\xc0\xc3\x08\x12')}, + 'Jolteon': {'id': 104, 'dex': 135, 'hp': 65, 'atk': 65, 'def': 60, 'spd': 130, 'spc': 110, 'type1': 'Electric', + 'type2': 'Electric', 'catch rate': 45, 'base exp': 197, 'start move 1': 'Tackle', + 'start move 2': 'Sand Attack', 'start move 3': 'Quick Attack', 'start move 4': 'Thundershock', + 'growth rate': 0, 'tms': bytearray(b'\xa0C\x88\xc1\xc3\x18B')}, + 'Flareon': {'id': 103, 'dex': 136, 'hp': 65, 'atk': 130, 'def': 60, 'spd': 65, 'spc': 110, 'type1': 'Fire', + 'type2': 'Fire', 'catch rate': 45, 'base exp': 198, 'start move 1': 'Tackle', + 'start move 2': 'Sand Attack', 'start move 3': 'Quick Attack', 'start move 4': 'Ember', + 'growth rate': 0, 'tms': bytearray(b'\xa0C\x08\xc0\xe3\x08\x02')}, + 'Porygon': {'id': 170, 'dex': 137, 'hp': 65, 'atk': 60, 'def': 70, 'spd': 40, 'spc': 75, 'type1': 'Normal', + 'type2': 'Normal', 'catch rate': 45, 'base exp': 130, 'start move 1': 'Tackle', + 'start move 2': 'Sharpen', 'start move 3': 'Conversion', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b' s\x88\xf1\xc38C')}, + 'Omanyte': {'id': 98, 'dex': 138, 'hp': 35, 'atk': 40, 'def': 100, 'spd': 35, 'spc': 90, 'type1': 'Rock', + 'type2': 'Water', 'catch rate': 45, 'base exp': 120, 'start move 1': 'Water Gun', + 'start move 2': 'Withdraw', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa0?\x08\xc0\x03\x08\x12')}, + 'Omastar': {'id': 99, 'dex': 139, 'hp': 70, 'atk': 60, 'def': 125, 'spd': 55, 'spc': 115, 'type1': 'Rock', + 'type2': 'Water', 'catch rate': 45, 'base exp': 199, 'start move 1': 'Water Gun', + 'start move 2': 'Withdraw', 'start move 3': 'Horn Attack', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xe0\x7f\r\xc0\x83\x08\x12')}, + 'Kabuto': {'id': 90, 'dex': 140, 'hp': 30, 'atk': 80, 'def': 90, 'spd': 55, 'spc': 45, 'type1': 'Rock', + 'type2': 'Water', 'catch rate': 45, 'base exp': 119, 'start move 1': 'Scratch', 'start move 2': 'Harden', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xa0?\x08\xc0\x03\x08\x12')}, + 'Kabutops': {'id': 91, 'dex': 141, 'hp': 60, 'atk': 115, 'def': 105, 'spd': 80, 'spc': 70, 'type1': 'Rock', + 'type2': 'Water', 'catch rate': 45, 'base exp': 201, 'start move 1': 'Scratch', + 'start move 2': 'Harden', 'start move 3': 'Absorb', 'start move 4': 'No Move', 'growth rate': 0, + 'tms': bytearray(b'\xb6\x7f\r\xc0\x83\x08\x12')}, + 'Aerodactyl': {'id': 171, 'dex': 142, 'hp': 80, 'atk': 105, 'def': 65, 'spd': 130, 'spc': 60, 'type1': 'Rock', + 'type2': 'Flying', 'catch rate': 45, 'base exp': 202, 'start move 1': 'Wing Attack', + 'start move 2': 'Agility', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b'*CH\xc0c\x0c\n')}, + 'Snorlax': {'id': 132, 'dex': 143, 'hp': 160, 'atk': 110, 'def': 65, 'spd': 30, 'spc': 65, 'type1': 'Normal', + 'type2': 'Normal', 'catch rate': 25, 'base exp': 154, 'start move 1': 'Headbutt', + 'start move 2': 'Amnesia', 'start move 3': 'Rest', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b'\xb1\xff\xaf\xd7\xaf\xa82')}, + 'Articuno': {'id': 74, 'dex': 144, 'hp': 90, 'atk': 85, 'def': 100, 'spd': 85, 'spc': 125, 'type1': 'Ice', + 'type2': 'Flying', 'catch rate': 3, 'base exp': 215, 'start move 1': 'Peck', + 'start move 2': 'Ice Beam', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b'*\x7f\x08\xc0C\x0c\n')}, + 'Zapdos': {'id': 75, 'dex': 145, 'hp': 90, 'atk': 90, 'def': 85, 'spd': 100, 'spc': 125, 'type1': 'Electric', + 'type2': 'Flying', 'catch rate': 3, 'base exp': 216, 'start move 1': 'Thundershock', + 'start move 2': 'Drill Peck', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b'*C\x88\xc1C\x1cJ')}, + 'Moltres': {'id': 73, 'dex': 146, 'hp': 90, 'atk': 100, 'def': 90, 'spd': 90, 'spc': 125, 'type1': 'Fire', + 'type2': 'Flying', 'catch rate': 3, 'base exp': 217, 'start move 1': 'Peck', + 'start move 2': 'Fire Spin', 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b'*C\x08\xc0c\x0c\n')}, + 'Dratini': {'id': 88, 'dex': 147, 'hp': 41, 'atk': 64, 'def': 45, 'spd': 50, 'spc': 50, 'type1': 'Dragon', + 'type2': 'Dragon', 'catch rate': 45, 'base exp': 67, 'start move 1': 'Wrap', 'start move 2': 'Leer', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b'\xa0?\xc8\xc1\xe3\x18\x12')}, + 'Dragonair': {'id': 89, 'dex': 148, 'hp': 61, 'atk': 84, 'def': 65, 'spd': 70, 'spc': 70, 'type1': 'Dragon', + 'type2': 'Dragon', 'catch rate': 45, 'base exp': 144, 'start move 1': 'Wrap', 'start move 2': 'Leer', + 'start move 3': 'Thunder Wave', 'start move 4': 'No Move', 'growth rate': 5, + 'tms': bytearray(b'\xe0?\xc8\xc1\xe3\x18\x12')}, + 'Dragonite': {'id': 66, 'dex': 149, 'hp': 91, 'atk': 134, 'def': 95, 'spd': 80, 'spc': 100, 'type1': 'Dragon', + 'type2': 'Flying', 'catch rate': 45, 'base exp': 218, 'start move 1': 'Wrap', 'start move 2': 'Leer', + 'start move 3': 'Thunder Wave', 'start move 4': 'Agility', 'growth rate': 5, + 'tms': bytearray(b'\xe2\x7f\xc8\xc1\xe3\x182')}, + 'Mewtwo': {'id': 131, 'dex': 150, 'hp': 106, 'atk': 110, 'def': 90, 'spd': 130, 'spc': 154, 'type1': 'Psychic', + 'type2': 'Psychic', 'catch rate': 3, 'base exp': 220, 'start move 1': 'Confusion', + 'start move 2': 'Disable', 'start move 3': 'Swift', 'start move 4': 'Psychic', 'growth rate': 5, + 'tms': bytearray(b'\xb1\xff\xaf\xf1\xaf8c')}, + 'Mew': {'id': 21, 'dex': 151, 'hp': 100, 'atk': 100, 'def': 100, 'spd': 100, 'spc': 100, 'type1': 'Psychic', + 'type2': 'Psychic', 'catch rate': 45, 'base exp': 64, 'start move 1': 'Pound', 'start move 2': 'No Move', + 'start move 3': 'No Move', 'start move 4': 'No Move', 'growth rate': 3, + 'tms': bytearray(b'\xff\xff\xff\xff\xff\xff\xff')}} + + + +evolves_from = { + "Ivysaur": "Bulbasaur", + "Venusaur": "Ivysaur", + "Charmeleon": "Charmander", + "Charizard": "Charmeleon", + "Wartortle": "Squirtle", + "Blastoise": "Wartortle", + "Metapod": "Caterpie", + "Butterfree": "Metapod", + "Kakuna": "Weedle", + "Beedrill": "Kakuna", + "Pidgeotto": "Pidgey", + "Pidgeot": "Pidgeotto", + "Raticate": "Rattata", + "Fearow": "Spearow", + "Arbok": "Ekans", + "Raichu": "Pikachu", + "Sandslash": "Sandshrew", + "Nidorina": "Nidoran F", + "Nidoqueen": "Nidorina", + "Nidorino": "Nidoran M", + "Nidoking": "Nidorino", + "Clefable": "Clefairy", + "Ninetales": "Vulpix", + "Wigglytuff": "Jigglypuff", + "Golbat": "Zubat", + "Gloom": "Oddish", + "Vileplume": "Gloom", + "Parasect": "Paras", + "Venomoth": "Venonat", + "Dugtrio": "Diglett", + "Persian": "Meowth", + "Golduck": "Psyduck", + "Primeape": "Mankey", + "Arcanine": "Growlithe", + "Poliwhirl": "Poliwag", + "Poliwrath": "Poliwhirl", + "Kadabra": "Abra", + "Alakazam": "Kadabra", + "Machoke": "Machop", + "Machamp": "Machoke", + "Weepinbell": "Bellsprout", + "Victreebel": "Weepinbell", + "Tentacruel": "Tentacool", + "Graveler": "Geodude", + "Golem": "Graveler", + "Rapidash": "Ponyta", + "Slowbro": "Slowpoke", + "Magneton": "Magnemite", + "Dodrio": "Doduo", + "Dewgong": "Seel", + "Muk": "Grimer", + "Cloyster": "Shellder", + "Haunter": "Gastly", + "Gengar": "Haunter", + "Hypno": "Drowzee", + "Kingler": "Krabby", + "Electrode": "Voltorb", + "Exeggutor": "Exeggcute", + "Marowak": "Cubone", + "Weezing": "Koffing", + "Rhydon": "Rhyhorn", + "Seadra": "Horsea", + "Seaking": "Goldeen", + "Starmie": "Staryu", + "Gyarados": "Magikarp", + "Vaporeon": "Eevee", + "Jolteon": "Eevee", + "Flareon": "Eevee", + "Omastar": "Omanyte", + "Kabutops": "Kabuto", + "Dragonair": "Dratini", + "Dragonite": "Dragonair" +} + +evolves_to = {} +for from_mon, to_mon in zip(evolves_from.values(), evolves_from.keys()): + if from_mon != "Eevee": + evolves_to[from_mon] = to_mon + +# basic_three_stage_pokemon = [] +# for mon in evolves_to.keys(): +# if evolves_to[mon] in evolves_to.keys(): +# basic_three_stage_pokemon.append(mon) +# print(basic_three_stage_pokemon) + +learnsets = { + 'Rhydon': ['Stomp', 'Tail Whip', 'Fury Attack', 'Horn Drill', 'Leer', 'Take Down'], + 'Kangaskhan': ['Bite', 'Tail Whip', 'Mega Punch', 'Leer', 'Dizzy Punch'], + 'Nidoran M': ['Horn Attack', 'Poison Sting', 'Focus Energy', 'Fury Attack', 'Horn Drill', 'Double Kick'], + 'Clefairy': ['Sing', 'Doubleslap', 'Minimize', 'Metronome', 'Defense Curl', 'Light Screen'], + 'Spearow': ['Leer', 'Fury Attack', 'Mirror Move', 'Drill Peck', 'Agility'], + 'Voltorb': ['Sonicboom', 'Selfdestruct', 'Light Screen', 'Swift', 'Explosion'], + 'Nidoking': ['Horn Attack', 'Poison Sting', 'Thrash'], + 'Slowbro': ['Disable', 'Headbutt', 'Growl', 'Water Gun', 'Withdraw', 'Amnesia', 'Psychic'], + 'Ivysaur': ['Leech Seed', 'Vine Whip', 'Poisonpowder', 'Razor Leaf', 'Growth', 'Sleep Powder', 'Solarbeam'], + 'Exeggutor': ['Stomp'], 'Lickitung': ['Stomp', 'Disable', 'Defense Curl', 'Slam', 'Screech'], + 'Exeggcute': ['Reflect', 'Leech Seed', 'Stun Spore', 'Poisonpowder', 'Solarbeam', 'Sleep Powder'], + 'Grimer': ['Poison Gas', 'Minimize', 'Sludge', 'Harden', 'Screech', 'Acid Armor'], + 'Gengar': ['Hypnosis', 'Dream Eater'], + 'Nidoran F': ['Scratch', 'Poison Sting', 'Tail Whip', 'Bite', 'Fury Swipes', 'Double Kick'], + 'Nidoqueen': ['Scratch', 'Poison Sting', 'Body Slam'], + 'Cubone': ['Leer', 'Focus Energy', 'Thrash', 'Bonemerang', 'Rage'], + 'Rhyhorn': ['Stomp', 'Tail Whip', 'Fury Attack', 'Horn Drill', 'Leer', 'Take Down'], + 'Lapras': ['Sing', 'Mist', 'Body Slam', 'Confuse Ray', 'Ice Beam', 'Hydro Pump'], + 'Mew': ['Transform', 'Mega Punch', 'Metronome', 'Psychic'], + 'Gyarados': ['Bite', 'Dragon Rage', 'Leer', 'Hydro Pump', 'Hyper Beam'], + 'Shellder': ['Supersonic', 'Clamp', 'Aurora Beam', 'Leer', 'Ice Beam'], + 'Tentacool': ['Supersonic', 'Wrap', 'Poison Sting', 'Water Gun', 'Constrict', 'Barrier', 'Screech', 'Hydro Pump'], + 'Gastly': ['Hypnosis', 'Dream Eater'], + 'Scyther': ['Leer', 'Focus Energy', 'Double Team', 'Slash', 'Swords Dance', 'Agility'], + 'Staryu': ['Water Gun', 'Harden', 'Recover', 'Swift', 'Minimize', 'Light Screen', 'Hydro Pump'], + 'Blastoise': ['Bubble', 'Water Gun', 'Bite', 'Withdraw', 'Skull Bash', 'Hydro Pump'], + 'Pinsir': ['Seismic Toss', 'Guillotine', 'Focus Energy', 'Harden', 'Slash', 'Swords Dance'], + 'Tangela': ['Absorb', 'Poisonpowder', 'Stun Spore', 'Sleep Powder', 'Slam', 'Growth'], + 'Growlithe': ['Ember', 'Leer', 'Take Down', 'Agility', 'Flamethrower'], + 'Onix': ['Bind', 'Rock Throw', 'Rage', 'Slam', 'Harden'], + 'Fearow': ['Leer', 'Fury Attack', 'Mirror Move', 'Drill Peck', 'Agility'], + 'Pidgey': ['Sand Attack', 'Quick Attack', 'Whirlwind', 'Wing Attack', 'Agility', 'Mirror Move'], + 'Slowpoke': ['Disable', 'Headbutt', 'Growl', 'Water Gun', 'Amnesia', 'Psychic'], + 'Kadabra': ['Confusion', 'Disable', 'Psybeam', 'Recover', 'Psychic', 'Reflect'], + 'Graveler': ['Defense Curl', 'Rock Throw', 'Selfdestruct', 'Harden', 'Earthquake', 'Explosion'], + 'Chansey': ['Sing', 'Growl', 'Minimize', 'Defense Curl', 'Light Screen', 'Double Edge'], + 'Machoke': ['Low Kick', 'Leer', 'Focus Energy', 'Seismic Toss', 'Submission'], + 'Mr Mime': ['Confusion', 'Light Screen', 'Doubleslap', 'Meditate', 'Substitute'], + 'Hitmonlee': ['Rolling Kick', 'Jump Kick', 'Focus Energy', 'Hi Jump Kick', 'Mega Kick'], + 'Hitmonchan': ['Fire Punch', 'Ice Punch', 'Thunderpunch', 'Mega Punch', 'Counter'], + 'Arbok': ['Poison Sting', 'Bite', 'Glare', 'Screech', 'Acid'], + 'Parasect': ['Stun Spore', 'Leech Life', 'Spore', 'Slash', 'Growth'], + 'Psyduck': ['Tail Whip', 'Disable', 'Confusion', 'Fury Swipes', 'Hydro Pump'], + 'Drowzee': ['Disable', 'Confusion', 'Headbutt', 'Poison Gas', 'Psychic', 'Meditate'], + 'Golem': ['Defense Curl', 'Rock Throw', 'Selfdestruct', 'Harden', 'Earthquake', 'Explosion'], + 'Magmar': ['Leer', 'Confuse Ray', 'Fire Punch', 'Smokescreen', 'Smog', 'Flamethrower'], + 'Electabuzz': ['Thundershock', 'Screech', 'Thunderpunch', 'Light Screen', 'Thunder'], + 'Magneton': ['Sonicboom', 'Thundershock', 'Supersonic', 'Thunder Wave', 'Swift', 'Screech'], + 'Koffing': ['Sludge', 'Smokescreen', 'Selfdestruct', 'Haze', 'Explosion'], + 'Mankey': ['Karate Chop', 'Fury Swipes', 'Focus Energy', 'Seismic Toss', 'Thrash'], + 'Seel': ['Growl', 'Aurora Beam', 'Rest', 'Take Down', 'Ice Beam'], + 'Diglett': ['Growl', 'Dig', 'Sand Attack', 'Slash', 'Earthquake'], + 'Tauros': ['Stomp', 'Tail Whip', 'Leer', 'Rage', 'Take Down'], + 'Farfetchd': ['Leer', 'Fury Attack', 'Swords Dance', 'Agility', 'Slash'], + 'Venonat': ['Poisonpowder', 'Leech Life', 'Stun Spore', 'Psybeam', 'Sleep Powder', 'Psychic'], + 'Dragonite': ['Thunder Wave', 'Agility', 'Slam', 'Dragon Rage', 'Hyper Beam'], + 'Doduo': ['Growl', 'Fury Attack', 'Drill Peck', 'Rage', 'Tri Attack', 'Agility'], + 'Poliwag': ['Hypnosis', 'Water Gun', 'Doubleslap', 'Body Slam', 'Amnesia', 'Hydro Pump'], + 'Jynx': ['Lick', 'Doubleslap', 'Ice Punch', 'Body Slam', 'Thrash', 'Blizzard'], + 'Moltres': ['Leer', 'Agility', 'Sky Attack'], + 'Articuno': ['Blizzard', 'Agility', 'Mist'], + 'Zapdos': ['Thunder', 'Agility', 'Light Screen'], + 'Meowth': ['Bite', 'Pay Day', 'Screech', 'Fury Swipes', 'Slash'], + 'Krabby': ['Vicegrip', 'Guillotine', 'Stomp', 'Crabhammer', 'Harden'], + 'Vulpix': ['Quick Attack', 'Roar', 'Confuse Ray', 'Flamethrower', 'Fire Spin'], + 'Pikachu': ['Thunder Wave', 'Quick Attack', 'Swift', 'Agility', 'Thunder'], + 'Dratini': ['Thunder Wave', 'Agility', 'Slam', 'Dragon Rage', 'Hyper Beam'], + 'Dragonair': ['Thunder Wave', 'Agility', 'Slam', 'Dragon Rage', 'Hyper Beam'], + 'Kabuto': ['Absorb', 'Slash', 'Leer', 'Hydro Pump'], + 'Kabutops': ['Absorb', 'Slash', 'Leer', 'Hydro Pump'], + 'Horsea': ['Smokescreen', 'Leer', 'Water Gun', 'Agility', 'Hydro Pump'], + 'Seadra': ['Smokescreen', 'Leer', 'Water Gun', 'Agility', 'Hydro Pump'], + 'Sandshrew': ['Sand Attack', 'Slash', 'Poison Sting', 'Swift', 'Fury Swipes'], + 'Sandslash': ['Sand Attack', 'Slash', 'Poison Sting', 'Swift', 'Fury Swipes'], + 'Omanyte': ['Horn Attack', 'Leer', 'Spike Cannon', 'Hydro Pump'], + 'Omastar': ['Horn Attack', 'Leer', 'Spike Cannon', 'Hydro Pump'], + 'Jigglypuff': ['Pound', 'Disable', 'Defense Curl', 'Doubleslap', 'Rest', 'Body Slam', 'Double Edge'], + 'Eevee': ['Quick Attack', 'Tail Whip', 'Bite', 'Take Down'], + 'Flareon': ['Quick Attack', 'Ember', 'Tail Whip', 'Bite', 'Leer', 'Fire Spin', 'Rage', 'Flamethrower'], + 'Jolteon': ['Quick Attack', 'Thundershock', 'Tail Whip', 'Thunder Wave', 'Double Kick', 'Agility', 'Pin Missile', 'Thunder'], + 'Vaporeon': ['Quick Attack', 'Water Gun', 'Tail Whip', 'Bite', 'Acid Armor', 'Haze', 'Mist', 'Hydro Pump'], + 'Machop': ['Low Kick', 'Leer', 'Focus Energy', 'Seismic Toss', 'Submission'], + 'Zubat': ['Supersonic', 'Bite', 'Confuse Ray', 'Wing Attack', 'Haze'], + 'Ekans': ['Poison Sting', 'Bite', 'Glare', 'Screech', 'Acid'], + 'Paras': ['Stun Spore', 'Leech Life', 'Spore', 'Slash', 'Growth'], + 'Poliwhirl': ['Hypnosis', 'Water Gun', 'Doubleslap', 'Body Slam', 'Amnesia', 'Hydro Pump'], + 'Poliwrath': ['Hypnosis', 'Water Gun'], + 'Beedrill': ['Fury Attack', 'Focus Energy', 'Twineedle', 'Rage', 'Pin Missile', 'Agility'], + 'Dodrio': ['Growl', 'Fury Attack', 'Drill Peck', 'Rage', 'Tri Attack', 'Agility'], + 'Primeape': ['Karate Chop', 'Fury Swipes', 'Focus Energy', 'Seismic Toss', 'Thrash'], + 'Dugtrio': ['Growl', 'Dig', 'Sand Attack', 'Slash', 'Earthquake'], + 'Venomoth': ['Poisonpowder', 'Leech Life', 'Stun Spore', 'Psybeam', 'Sleep Powder', 'Psychic'], + 'Dewgong': ['Growl', 'Aurora Beam', 'Rest', 'Take Down', 'Ice Beam'], + 'Butterfree': ['Confusion', 'Poisonpowder', 'Stun Spore', 'Sleep Powder', 'Supersonic', 'Whirlwind', 'Psybeam'], + 'Machamp': ['Low Kick', 'Leer', 'Focus Energy', 'Seismic Toss', 'Submission'], + 'Golduck': ['Tail Whip', 'Disable', 'Confusion', 'Fury Swipes', 'Hydro Pump'], + 'Hypno': ['Disable', 'Confusion', 'Headbutt', 'Poison Gas', 'Psychic', 'Meditate'], + 'Golbat': ['Supersonic', 'Bite', 'Confuse Ray', 'Wing Attack', 'Haze'], + 'Mewtwo': ['Barrier', 'Psychic', 'Recover', 'Mist', 'Amnesia'], + 'Snorlax': ['Body Slam', 'Harden', 'Double Edge', 'Hyper Beam'], + 'Magikarp': ['Tackle'], + 'Muk': ['Poison Gas', 'Minimize', 'Sludge', 'Harden', 'Screech', 'Acid Armor'], + 'Kingler': ['Vicegrip', 'Guillotine', 'Stomp', 'Crabhammer', 'Harden'], + 'Cloyster': ['Spike Cannon'], + 'Electrode': ['Sonicboom', 'Selfdestruct', 'Light Screen', 'Swift', 'Explosion'], + 'Weezing': ['Sludge', 'Smokescreen', 'Selfdestruct', 'Haze', 'Explosion'], + 'Persian': ['Bite', 'Pay Day', 'Screech', 'Fury Swipes', 'Slash'], + 'Marowak': ['Leer', 'Focus Energy', 'Thrash', 'Bonemerang', 'Rage'], + 'Haunter': ['Hypnosis', 'Dream Eater'], + 'Alakazam': ['Confusion', 'Disable', 'Psybeam', 'Recover', 'Psychic', 'Reflect'], + 'Pidgeotto': ['Sand Attack', 'Quick Attack', 'Whirlwind', 'Wing Attack', 'Agility', 'Mirror Move'], + 'Pidgeot': ['Sand Attack', 'Quick Attack', 'Whirlwind', 'Wing Attack', 'Agility', 'Mirror Move'], + 'Bulbasaur': ['Leech Seed', 'Vine Whip', 'Poisonpowder', 'Razor Leaf', 'Growth', 'Sleep Powder', 'Solarbeam'], + 'Venusaur': ['Leech Seed', 'Vine Whip', 'Poisonpowder', 'Razor Leaf', 'Growth', 'Sleep Powder', 'Solarbeam'], + 'Tentacruel': ['Supersonic', 'Wrap', 'Poison Sting', 'Water Gun', 'Constrict', 'Barrier', 'Screech', 'Hydro Pump'], + 'Goldeen': ['Supersonic', 'Horn Attack', 'Fury Attack', 'Waterfall', 'Horn Drill', 'Agility'], + 'Seaking': ['Supersonic', 'Horn Attack', 'Fury Attack', 'Waterfall', 'Horn Drill', 'Agility'], + 'Ponyta': ['Tail Whip', 'Stomp', 'Growl', 'Fire Spin', 'Take Down', 'Agility'], + 'Rapidash': ['Tail Whip', 'Stomp', 'Growl', 'Fire Spin', 'Take Down', 'Agility'], + 'Rattata': ['Quick Attack', 'Hyper Fang', 'Focus Energy', 'Super Fang'], + 'Raticate': ['Quick Attack', 'Hyper Fang', 'Focus Energy', 'Super Fang'], + 'Nidorino': ['Horn Attack', 'Poison Sting', 'Focus Energy', 'Fury Attack', 'Horn Drill', 'Double Kick'], + 'Nidorina': ['Scratch', 'Poison Sting', 'Tail Whip', 'Bite', 'Fury Swipes', 'Double Kick'], + 'Geodude': ['Defense Curl', 'Rock Throw', 'Selfdestruct', 'Harden', 'Earthquake', 'Explosion'], + 'Porygon': ['Psybeam', 'Recover', 'Agility', 'Tri Attack'], + 'Aerodactyl': ['Supersonic', 'Bite', 'Take Down', 'Hyper Beam'], + 'Magnemite': ['Sonicboom', 'Thundershock', 'Supersonic', 'Thunder Wave', 'Swift', 'Screech'], + 'Charmander': ['Ember', 'Leer', 'Rage', 'Slash', 'Flamethrower', 'Fire Spin'], + 'Squirtle': ['Bubble', 'Water Gun', 'Bite', 'Withdraw', 'Skull Bash', 'Hydro Pump'], + 'Charmeleon': ['Ember', 'Leer', 'Rage', 'Slash', 'Flamethrower', 'Fire Spin'], + 'Wartortle': ['Bubble', 'Water Gun', 'Bite', 'Withdraw', 'Skull Bash', 'Hydro Pump'], + 'Charizard': ['Ember', 'Leer', 'Rage', 'Slash', 'Flamethrower', 'Fire Spin'], + 'Oddish': ['Poisonpowder', 'Stun Spore', 'Sleep Powder', 'Acid', 'Petal Dance', 'Solarbeam'], + 'Gloom': ['Poisonpowder', 'Stun Spore', 'Sleep Powder', 'Acid', 'Petal Dance', 'Solarbeam'], + 'Vileplume': ['Poisonpowder', 'Stun Spore', 'Sleep Powder'], + 'Bellsprout': ['Wrap', 'Poisonpowder', 'Sleep Powder', 'Stun Spore', 'Acid', 'Razor Leaf', 'Slam'], + 'Weepinbell': ['Wrap', 'Poisonpowder', 'Sleep Powder', 'Stun Spore', 'Acid', 'Razor Leaf', 'Slam'], + 'Victreebel': ['Wrap', 'Poisonpowder', 'Sleep Powder'] +} + +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} +} + +encounter_tables = {'Wild_Super_Rod_A': 2, 'Wild_Super_Rod_B': 2, 'Wild_Super_Rod_C': 3, 'Wild_Super_Rod_D': 2, + 'Wild_Super_Rod_E': 2, 'Wild_Super_Rod_F': 4, 'Wild_Super_Rod_G': 4, 'Wild_Super_Rod_H': 4, + 'Wild_Super_Rod_I': 4, 'Wild_Super_Rod_J': 4, 'Wild_Route1': 10, 'Wild_Route2': 10, + 'Wild_Route22': 10, 'Wild_ViridianForest': 10, 'Wild_Route3': 10, 'Wild_MtMoon1F': 10, + 'Wild_MtMoonB1F': 10, 'Wild_MtMoonB2F': 10, 'Wild_Route4': 10, 'Wild_Route24': 10, + 'Wild_Route25': 10, 'Wild_Route9': 10, 'Wild_Route5': 10, 'Wild_Route6': 10, + 'Wild_Route11': 10, 'Wild_RockTunnel1F': 10, 'Wild_RockTunnelB1F': 10, 'Wild_Route10': 10, + 'Wild_Route12': 10, 'Wild_Route8': 10, 'Wild_Route7': 10, 'Wild_PokemonTower3F': 10, + 'Wild_PokemonTower4F': 10, 'Wild_PokemonTower5F': 10, 'Wild_PokemonTower6F': 10, + 'Wild_PokemonTower7F': 10, 'Wild_Route13': 10, 'Wild_Route14': 10, 'Wild_Route15': 10, + 'Wild_Route16': 10, 'Wild_Route17': 10, 'Wild_Route18': 10, 'Wild_SafariZoneCenter': 10, + 'Wild_SafariZoneEast': 10, 'Wild_SafariZoneNorth': 10, 'Wild_SafariZoneWest': 10, + 'Wild_SeaRoutes': 10, 'Wild_SeafoamIslands1F': 10, 'Wild_SeafoamIslandsB1F': 10, + 'Wild_SeafoamIslandsB2F': 10, 'Wild_SeafoamIslandsB3F': 10, 'Wild_SeafoamIslandsB4F': 10, + 'Wild_PokemonMansion1F': 10, 'Wild_PokemonMansion2F': 10, 'Wild_PokemonMansion3F': 10, + 'Wild_PokemonMansionB1F': 10, 'Wild_Route21': 10, 'Wild_CeruleanCave1F': 10, + 'Wild_CeruleanCave2F': 10, 'Wild_CeruleanCaveB1F': 10, 'Wild_PowerPlant': 10, + 'Wild_Route23': 10, 'Wild_VictoryRoad2F': 10, 'Wild_VictoryRoad3F': 10, + 'Wild_VictoryRoad1F': 10, 'Wild_DiglettsCave': 10, 'Wild_Good_Rod': 2} + +hm_moves = ["Cut", "Fly", "Surf", "Strength", "Flash"] + +tm_moves = [ + 'Mega Punch', 'Razor Wind', 'Swords Dance', 'Whirlwind', 'Mega Kick', 'Toxic', 'Horn Drill', 'Body Slam', + 'Take Down', 'Double Edge', 'Bubblebeam', 'Water Gun', 'Ice Beam', 'Blizzard', 'Hyper Beam', 'Pay Day', + 'Submission', 'Counter', 'Seismic Toss', 'Rage', 'Mega Drain', 'Solarbeam', 'Dragon Rage', 'Thunderbolt', 'Thunder', + 'Earthquake', 'Fissure', 'Dig', 'Psychic', 'Teleport', 'Mimic', 'Double Team', 'Reflect', 'Bide', 'Metronome', + 'Selfdestruct', 'Egg Bomb', 'Fire Blast', 'Swift', 'Skull Bash', 'Softboiled', 'Dream Eater', 'Sky Attack', 'Rest', + 'Thunder Wave', 'Psywave', 'Explosion', 'Rock Slide', 'Tri Attack', 'Substitute' +] + + + +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 new file mode 100644 index 00000000..1650e640 --- /dev/null +++ b/worlds/pokemon_rb/regions.py @@ -0,0 +1,305 @@ + +from BaseClasses import MultiWorld, Region, Entrance, RegionType, LocationProgressType +from worlds.generic.Rules import add_item_rule +from .locations import location_data, PokemonRBLocation + + +def create_region(world: MultiWorld, player: int, name: str, locations_per_region=None, exits=None): + ret = Region(name, RegionType.Generic, name, player, world) + for location in locations_per_region.get(name, []): + if (world.randomize_hidden_items[player].value or "Hidden" not in location.name) and \ + (world.extra_key_items[player].value or name != "Rock Tunnel B1F" or "Item" not in location.name) and \ + (world.tea[player].value or location.name != "Celadon City - Mansion Lady"): + location.parent_region = ret + ret.locations.append(location) + if world.randomize_hidden_items[player].value == 2 and "Hidden" in location.name: + location.progress_type = LocationProgressType.EXCLUDED + add_item_rule(location, lambda i: not (i.advancement or i.useful)) + if exits: + for exit in exits: + ret.exits.append(Entrance(player, exit, ret)) + locations_per_region[name] = [] + return ret + + +def create_regions(world: MultiWorld, player: int): + locations_per_region = {} + for location in location_data: + locations_per_region.setdefault(location.region, []) + locations_per_region[location.region].append(PokemonRBLocation(player, location.name, location.address, + location.rom_address)) + regions = [ + create_region(world, player, "Menu", locations_per_region), + create_region(world, player, "Anywhere", locations_per_region), + create_region(world, player, "Fossil", locations_per_region), + create_region(world, player, "Pallet Town", locations_per_region), + create_region(world, player, "Route 1", locations_per_region), + create_region(world, player, "Viridian City", locations_per_region), + create_region(world, player, "Viridian City North", locations_per_region), + create_region(world, player, "Viridian Gym", locations_per_region), + create_region(world, player, "Route 2", locations_per_region), + create_region(world, player, "Route 2 East", locations_per_region), + create_region(world, player, "Diglett's Cave", locations_per_region), + create_region(world, player, "Route 22", locations_per_region), + create_region(world, player, "Route 23 South", locations_per_region), + create_region(world, player, "Route 23 North", locations_per_region), + create_region(world, player, "Viridian Forest", locations_per_region), + create_region(world, player, "Pewter City", locations_per_region), + create_region(world, player, "Pewter Gym", locations_per_region), + create_region(world, player, "Route 3", locations_per_region), + create_region(world, player, "Mt Moon 1F", locations_per_region), + create_region(world, player, "Mt Moon B1F", locations_per_region), + create_region(world, player, "Mt Moon B2F", locations_per_region), + create_region(world, player, "Route 4", locations_per_region), + create_region(world, player, "Cerulean City", locations_per_region), + create_region(world, player, "Cerulean Gym", locations_per_region), + create_region(world, player, "Route 24", locations_per_region), + create_region(world, player, "Route 25", locations_per_region), + create_region(world, player, "Route 9", locations_per_region), + create_region(world, player, "Route 10 North", locations_per_region), + create_region(world, player, "Rock Tunnel 1F", locations_per_region), + create_region(world, player, "Rock Tunnel B1F", locations_per_region), + create_region(world, player, "Power Plant", locations_per_region), + create_region(world, player, "Route 10 South", locations_per_region), + create_region(world, player, "Lavender Town", locations_per_region), + create_region(world, player, "Pokemon Tower 1F", locations_per_region), + create_region(world, player, "Pokemon Tower 2F", locations_per_region), + create_region(world, player, "Pokemon Tower 3F", locations_per_region), + create_region(world, player, "Pokemon Tower 4F", locations_per_region), + create_region(world, player, "Pokemon Tower 5F", locations_per_region), + create_region(world, player, "Pokemon Tower 6F", locations_per_region), + create_region(world, player, "Pokemon Tower 7F", locations_per_region), + create_region(world, player, "Route 5", locations_per_region), + create_region(world, player, "Saffron City", locations_per_region), + create_region(world, player, "Saffron Gym", locations_per_region), + create_region(world, player, "Copycat's House", locations_per_region), + create_region(world, player, "Underground Tunnel North-South", locations_per_region), + create_region(world, player, "Route 6", locations_per_region), + create_region(world, player, "Vermilion City", locations_per_region), + create_region(world, player, "Vermilion Gym", locations_per_region), + create_region(world, player, "S.S. Anne 1F", locations_per_region), + create_region(world, player, "S.S. Anne B1F", locations_per_region), + create_region(world, player, "S.S. Anne 2F", locations_per_region), + create_region(world, player, "Route 11", locations_per_region), + create_region(world, player, "Route 11 East", locations_per_region), + create_region(world, player, "Route 12 North", locations_per_region), + create_region(world, player, "Route 12 South", locations_per_region), + create_region(world, player, "Route 12 Grass", locations_per_region), + create_region(world, player, "Route 12 West", locations_per_region), + create_region(world, player, "Route 7", locations_per_region), + create_region(world, player, "Underground Tunnel West-East", locations_per_region), + create_region(world, player, "Route 8", locations_per_region), + create_region(world, player, "Route 8 Grass", locations_per_region), + create_region(world, player, "Celadon City", locations_per_region), + create_region(world, player, "Celadon Prize Corner", locations_per_region), + create_region(world, player, "Celadon Gym", locations_per_region), + create_region(world, player, "Route 16", locations_per_region), + create_region(world, player, "Route 16 North", locations_per_region), + create_region(world, player, "Route 17", locations_per_region), + create_region(world, player, "Route 18", locations_per_region), + create_region(world, player, "Fuchsia City", locations_per_region), + create_region(world, player, "Fuchsia Gym", locations_per_region), + create_region(world, player, "Safari Zone Gate", locations_per_region), + create_region(world, player, "Safari Zone Center", locations_per_region), + create_region(world, player, "Safari Zone East", locations_per_region), + create_region(world, player, "Safari Zone North", locations_per_region), + create_region(world, player, "Safari Zone West", locations_per_region), + create_region(world, player, "Route 15", locations_per_region), + create_region(world, player, "Route 14", locations_per_region), + create_region(world, player, "Route 13", locations_per_region), + create_region(world, player, "Route 19", locations_per_region), + create_region(world, player, "Route 20 East", locations_per_region), + create_region(world, player, "Route 20 West", locations_per_region), + create_region(world, player, "Seafoam Islands 1F", locations_per_region), + create_region(world, player, "Seafoam Islands B1F", locations_per_region), + create_region(world, player, "Seafoam Islands B2F", locations_per_region), + create_region(world, player, "Seafoam Islands B3F", locations_per_region), + create_region(world, player, "Seafoam Islands B4F", locations_per_region), + create_region(world, player, "Cinnabar Island", locations_per_region), + create_region(world, player, "Cinnabar Gym", locations_per_region), + create_region(world, player, "Route 21", locations_per_region), + create_region(world, player, "Silph Co 1F", locations_per_region), + create_region(world, player, "Silph Co 2F", locations_per_region), + create_region(world, player, "Silph Co 3F", locations_per_region), + create_region(world, player, "Silph Co 4F", locations_per_region), + create_region(world, player, "Silph Co 5F", locations_per_region), + create_region(world, player, "Silph Co 6F", locations_per_region), + create_region(world, player, "Silph Co 7F", locations_per_region), + create_region(world, player, "Silph Co 8F", locations_per_region), + create_region(world, player, "Silph Co 9F", locations_per_region), + create_region(world, player, "Silph Co 10F", locations_per_region), + create_region(world, player, "Silph Co 11F", locations_per_region), + create_region(world, player, "Rocket Hideout B1F", locations_per_region), + create_region(world, player, "Rocket Hideout B2F", locations_per_region), + create_region(world, player, "Rocket Hideout B3F", locations_per_region), + create_region(world, player, "Rocket Hideout B4F", locations_per_region), + create_region(world, player, "Pokemon Mansion 1F", locations_per_region), + create_region(world, player, "Pokemon Mansion 2F", locations_per_region), + create_region(world, player, "Pokemon Mansion 3F", locations_per_region), + create_region(world, player, "Pokemon Mansion B1F", locations_per_region), + create_region(world, player, "Victory Road 1F", locations_per_region), + create_region(world, player, "Victory Road 2F", locations_per_region), + create_region(world, player, "Victory Road 3F", locations_per_region), + create_region(world, player, "Indigo Plateau", locations_per_region), + create_region(world, player, "Cerulean Cave 1F", locations_per_region), + create_region(world, player, "Cerulean Cave 2F", locations_per_region), + create_region(world, player, "Cerulean Cave B1F", locations_per_region), + create_region(world, player, "Evolution", locations_per_region), + ] + world.regions += regions + connect(world, player, "Menu", "Anywhere", one_way=True) + connect(world, player, "Menu", "Pallet Town", one_way=True) + connect(world, player, "Menu", "Fossil", lambda state: state.pokemon_rb_fossil_checks( + state.world.second_fossil_check_condition[player].value, player), one_way=True) + connect(world, player, "Pallet Town", "Route 1") + connect(world, player, "Route 1", "Viridian City") + connect(world, player, "Viridian City", "Route 22") + connect(world, player, "Route 22", "Route 23 South", + lambda state: state.pokemon_rb_has_badges(state.world.victory_road_condition[player].value, player)) + connect(world, player, "Route 23 South", "Route 23 North", lambda state: state.pokemon_rb_can_surf(player)) + connect(world, player, "Viridian City North", "Viridian Gym", lambda state: + state.pokemon_rb_has_badges(state.world.viridian_gym_condition[player].value, player), one_way=True) + connect(world, player, "Route 2", "Route 2 East", lambda state: state.pokemon_rb_can_cut(player)) + connect(world, player, "Route 2 East", "Diglett's Cave", lambda state: state.pokemon_rb_can_cut(player)) + connect(world, player, "Route 2", "Viridian City North") + connect(world, player, "Route 2", "Viridian Forest") + connect(world, player, "Route 2", "Pewter City") + connect(world, player, "Pewter City", "Pewter Gym", one_way=True) + connect(world, player, "Pewter City", "Route 3") + connect(world, player, "Route 4", "Route 3", one_way=True) + connect(world, player, "Mt Moon 1F", "Mt Moon B1F", one_way=True) + connect(world, player, "Mt Moon B1F", "Mt Moon B2F", one_way=True) + connect(world, player, "Mt Moon B1F", "Route 4", one_way=True) + connect(world, player, "Route 4", "Cerulean City") + connect(world, player, "Cerulean City", "Cerulean Gym", one_way=True) + connect(world, player, "Cerulean City", "Route 24", one_way=True) + connect(world, player, "Route 24", "Route 25", one_way=True) + connect(world, player, "Cerulean City", "Route 9", lambda state: state.pokemon_rb_can_cut(player)) + connect(world, player, "Route 9", "Route 10 North") + connect(world, player, "Route 10 North", "Rock Tunnel 1F", lambda state: state.pokemon_rb_can_flash(player)) + connect(world, player, "Route 10 North", "Power Plant", lambda state: state.pokemon_rb_can_surf(player) and + (state.has("Plant Key", player) or not state.world.extra_key_items[player].value), one_way=True) + connect(world, player, "Rock Tunnel 1F", "Route 10 South", lambda state: state.pokemon_rb_can_flash(player)) + connect(world, player, "Rock Tunnel 1F", "Rock Tunnel B1F") + connect(world, player, "Lavender Town", "Pokemon Tower 1F", one_way=True) + connect(world, player, "Lavender Town", "Pokemon Tower 1F", one_way=True) + connect(world, player, "Pokemon Tower 1F", "Pokemon Tower 2F", one_way=True) + connect(world, player, "Pokemon Tower 2F", "Pokemon Tower 3F", one_way=True) + connect(world, player, "Pokemon Tower 3F", "Pokemon Tower 4F", one_way=True) + connect(world, player, "Pokemon Tower 4F", "Pokemon Tower 5F", one_way=True) + connect(world, player, "Pokemon Tower 5F", "Pokemon Tower 6F", one_way=True) + connect(world, player, "Pokemon Tower 6F", "Pokemon Tower 7F", lambda state: state.has("Silph Scope", player)) + connect(world, player, "Cerulean City", "Route 5") + connect(world, player, "Route 5", "Saffron City", lambda state: state.pokemon_rb_can_pass_guards(player)) + connect(world, player, "Route 5", "Underground Tunnel North-South") + connect(world, player, "Route 6", "Underground Tunnel North-South") + connect(world, player, "Route 6", "Saffron City", lambda state: state.pokemon_rb_can_pass_guards(player)) + connect(world, player, "Route 7", "Saffron City", lambda state: state.pokemon_rb_can_pass_guards(player)) + connect(world, player, "Route 8", "Saffron City", lambda state: state.pokemon_rb_can_pass_guards(player)) + connect(world, player, "Saffron City", "Copycat's House", lambda state: state.has("Silph Co Liberated", player), one_way=True) + connect(world, player, "Saffron City", "Saffron Gym", lambda state: state.has("Silph Co Liberated", player), one_way=True) + connect(world, player, "Route 6", "Vermilion City") + connect(world, player, "Vermilion City", "Vermilion Gym", lambda state: state.pokemon_rb_can_surf(player) or state.pokemon_rb_can_cut(player), one_way=True) + connect(world, player, "Vermilion City", "S.S. Anne 1F", lambda state: state.has("S.S. Ticket", player), one_way=True) + connect(world, player, "S.S. Anne 1F", "S.S. Anne 2F", one_way=True) + connect(world, player, "S.S. Anne 1F", "S.S. Anne B1F", one_way=True) + connect(world, player, "Vermilion City", "Route 11") + connect(world, player, "Vermilion City", "Diglett's Cave") + connect(world, player, "Route 12 West", "Route 11 East", lambda state: state.pokemon_rb_can_strength(player) or not state.world.extra_strength_boulders[player].value) + connect(world, player, "Route 12 North", "Route 12 South", lambda state: state.has("Poke Flute", player) or state.pokemon_rb_can_surf( player)) + connect(world, player, "Route 12 West", "Route 12 North", lambda state: state.has("Poke Flute", player)) + connect(world, player, "Route 12 West", "Route 12 South", lambda state: state.has("Poke Flute", player)) + connect(world, player, "Route 12 South", "Route 12 Grass", lambda state: state.pokemon_rb_can_cut(player)) + connect(world, player, "Route 12 North", "Lavender Town") + connect(world, player, "Route 7", "Lavender Town") + connect(world, player, "Route 10 South", "Lavender Town") + connect(world, player, "Route 7", "Underground Tunnel West-East") + connect(world, player, "Route 8", "Underground Tunnel West-East") + connect(world, player, "Route 8", "Celadon City") + connect(world, player, "Route 8", "Route 8 Grass", lambda state: state.pokemon_rb_can_cut(player), one_way=True) + connect(world, player, "Route 7", "Celadon City") + connect(world, player, "Celadon City", "Celadon Gym", lambda state: state.pokemon_rb_can_cut(player), one_way=True) + connect(world, player, "Celadon City", "Celadon Prize Corner") + connect(world, player, "Celadon City", "Route 16") + connect(world, player, "Route 16", "Route 16 North", lambda state: state.pokemon_rb_can_cut(player), one_way=True) + connect(world, player, "Route 16", "Route 17", lambda state: state.has("Poke Flute", player) and state.has("Bicycle", player)) + connect(world, player, "Route 17", "Route 18", lambda state: state.has("Bicycle", player)) + connect(world, player, "Fuchsia City", "Fuchsia Gym", one_way=True) + connect(world, player, "Fuchsia City", "Route 18") + connect(world, player, "Fuchsia City", "Safari Zone Gate", one_way=True) + connect(world, player, "Safari Zone Gate", "Safari Zone Center", lambda state: state.has("Safari Pass", player) or not state.world.extra_key_items[player].value, one_way=True) + connect(world, player, "Safari Zone Center", "Safari Zone East", one_way=True) + connect(world, player, "Safari Zone Center", "Safari Zone West", one_way=True) + connect(world, player, "Safari Zone Center", "Safari Zone North", one_way=True) + connect(world, player, "Fuchsia City", "Route 15") + connect(world, player, "Route 15", "Route 14") + connect(world, player, "Route 14", "Route 13") + connect(world, player, "Route 13", "Route 12 South", lambda state: state.pokemon_rb_can_strength(player) or state.pokemon_rb_can_surf(player) or not state.world.extra_strength_boulders[player].value) + connect(world, player, "Fuchsia City", "Route 19", lambda state: state.pokemon_rb_can_surf(player)) + connect(world, player, "Route 20 East", "Route 19") + connect(world, player, "Route 20 West", "Cinnabar Island", lambda state: state.pokemon_rb_can_surf(player)) + connect(world, player, "Route 20 West", "Seafoam Islands 1F") + connect(world, player, "Route 20 East", "Seafoam Islands 1F", one_way=True) + connect(world, player, "Seafoam Islands 1F", "Route 20 East", lambda state: state.pokemon_rb_can_strength(player), one_way=True) + connect(world, player, "Viridian City", "Viridian City North", lambda state: state.has("Oak's Parcel", player) or state.world.old_man[player].value == 2 or state.pokemon_rb_can_cut(player)) + connect(world, player, "Route 3", "Mt Moon 1F", one_way=True) + connect(world, player, "Route 11", "Route 11 East", lambda state: state.pokemon_rb_can_strength(player)) + connect(world, player, "Cinnabar Island", "Cinnabar Gym", lambda state: state.has("Secret Key", player), one_way=True) + connect(world, player, "Cinnabar Island", "Pokemon Mansion 1F", lambda state: state.has("Mansion Key", player) or not state.world.extra_key_items[player].value, one_way=True) + connect(world, player, "Seafoam Islands 1F", "Seafoam Islands B1F", one_way=True) + connect(world, player, "Seafoam Islands B1F", "Seafoam Islands B2F", one_way=True) + connect(world, player, "Seafoam Islands B2F", "Seafoam Islands B3F", one_way=True) + connect(world, player, "Seafoam Islands B3F", "Seafoam Islands B4F", one_way=True) + connect(world, player, "Route 21", "Cinnabar Island", lambda state: state.pokemon_rb_can_surf(player)) + connect(world, player, "Pallet Town", "Route 21", lambda state: state.pokemon_rb_can_surf(player)) + connect(world, player, "Saffron City", "Silph Co 1F", lambda state: state.has("Fuji Saved", player), one_way=True) + connect(world, player, "Silph Co 1F", "Silph Co 2F", one_way=True) + connect(world, player, "Silph Co 2F", "Silph Co 3F", one_way=True) + connect(world, player, "Silph Co 3F", "Silph Co 4F", one_way=True) + connect(world, player, "Silph Co 4F", "Silph Co 5F", one_way=True) + connect(world, player, "Silph Co 5F", "Silph Co 6F", one_way=True) + connect(world, player, "Silph Co 6F", "Silph Co 7F", one_way=True) + connect(world, player, "Silph Co 7F", "Silph Co 8F", one_way=True) + connect(world, player, "Silph Co 8F", "Silph Co 9F", one_way=True) + connect(world, player, "Silph Co 9F", "Silph Co 10F", one_way=True) + connect(world, player, "Silph Co 10F", "Silph Co 11F", one_way=True) + connect(world, player, "Celadon City", "Rocket Hideout B1F", lambda state: state.has("Hideout Key", player) or not state.world.extra_key_items[player].value, one_way=True) + connect(world, player, "Rocket Hideout B1F", "Rocket Hideout B2F", one_way=True) + connect(world, player, "Rocket Hideout B2F", "Rocket Hideout B3F", one_way=True) + connect(world, player, "Rocket Hideout B3F", "Rocket Hideout B4F", one_way=True) + connect(world, player, "Pokemon Mansion 1F", "Pokemon Mansion 2F", one_way=True) + connect(world, player, "Pokemon Mansion 2F", "Pokemon Mansion 3F", one_way=True) + connect(world, player, "Pokemon Mansion 1F", "Pokemon Mansion B1F", one_way=True) + connect(world, player, "Route 23 North", "Victory Road 1F", lambda state: state.pokemon_rb_can_strength(player), one_way=True) + connect(world, player, "Victory Road 1F", "Victory Road 2F", one_way=True) + connect(world, player, "Victory Road 2F", "Victory Road 3F", one_way=True) + connect(world, player, "Victory Road 2F", "Indigo Plateau", lambda state: state.pokemon_rb_has_badges(state.world.elite_four_condition[player], player), one_way=True) + connect(world, player, "Cerulean City", "Cerulean Cave 1F", lambda state: + state.pokemon_rb_cerulean_cave(state.world.cerulean_cave_condition[player].value + (state.world.extra_key_items[player].value * 4), player) and + state.pokemon_rb_can_surf(player), one_way=True) + connect(world, player, "Cerulean Cave 1F", "Cerulean Cave 2F", one_way=True) + connect(world, player, "Cerulean Cave 1F", "Cerulean Cave B1F", lambda state: state.pokemon_rb_can_surf(player), one_way=True) + if world.worlds[player].fly_map != "Pallet Town": + connect(world, player, "Menu", world.worlds[player].fly_map, lambda state: state.pokemon_rb_can_fly(player), one_way=True, + name="Fly to " + world.worlds[player].fly_map) + + +def connect(world: MultiWorld, player: int, source: str, target: str, rule: callable = lambda state: True, one_way=False, name=None): + source_region = world.get_region(source, player) + target_region = world.get_region(target, player) + + if name is None: + name = source + " to " + target + + connection = Entrance( + player, + name, + source_region + ) + + connection.access_rule = rule + + source_region.exits.append(connection) + connection.connect(target_region) + if not one_way: + connect(world, player, target, source, rule, True) diff --git a/worlds/pokemon_rb/rom.py b/worlds/pokemon_rb/rom.py new file mode 100644 index 00000000..370bd6af --- /dev/null +++ b/worlds/pokemon_rb/rom.py @@ -0,0 +1,614 @@ +import os +import hashlib +import Utils +import bsdiff4 +from copy import deepcopy +from Patch import APDeltaPatch +from .text import encode_text +from .rom_addresses import rom_addresses +from .locations import location_data +import worlds.pokemon_rb.poke_data as poke_data + + +def choose_forced_type(chances, random): + n = random.randint(1, 100) + for chance in chances: + if chance[0] >= n: + return chance[1] + return None + + +def filter_moves(moves, type, random): + ret = [] + for move in moves: + if poke_data.moves[move]["type"] == type or type is None: + ret.append(move) + random.shuffle(ret) + return ret + + +def get_move(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: + moves.remove(move) + return move + else: + return get_move(moves, [], random, starting_move) + + +def get_encounter_slots(self): + encounter_slots = [location for location in location_data if location.type == "Wild Encounter"] + + for location in encounter_slots: + if isinstance(location.original_item, list): + location.original_item = location.original_item[not self.world.game_version[self.player].value] + return encounter_slots + + +def get_base_stat_total(mon): + return (poke_data.pokemon_data[mon]["atk"] + poke_data.pokemon_data[mon]["def"] + + poke_data.pokemon_data[mon]["hp"] + poke_data.pokemon_data[mon]["spd"] + + poke_data.pokemon_data[mon]["spc"]) + + +def randomize_pokemon(self, mon, mons_list, randomize_type): + if randomize_type in [1, 3]: + type_mons = [pokemon for pokemon in mons_list if any([poke_data.pokemon_data[mon][ + "type1"] in [self.local_poke_data[pokemon]["type1"], self.local_poke_data[pokemon]["type2"]], + poke_data.pokemon_data[mon]["type2"] in [self.local_poke_data[pokemon]["type1"], + self.local_poke_data[pokemon]["type2"]]])] + if not type_mons: + type_mons = mons_list.copy() + if randomize_type == 3: + stat_base = get_base_stat_total(mon) + type_mons.sort(key=lambda mon: abs(get_base_stat_total(mon) - stat_base)) + mon = type_mons[round(self.world.random.triangular(0, len(type_mons) - 1, 0))] + if randomize_type == 2: + stat_base = get_base_stat_total(mon) + mons_list.sort(key=lambda mon: abs(get_base_stat_total(mon) - stat_base)) + mon = mons_list[round(self.world.random.triangular(0, 50, 0))] + elif randomize_type == 4: + mon = self.world.random.choice(mons_list) + return mon + + +def process_trainer_data(self, data): + mons_list = [pokemon for pokemon in poke_data.pokemon_data.keys() if pokemon not in poke_data.legendary_pokemon + or self.world.trainer_legendaries[self.player].value] + address = rom_addresses["Trainer_Data"] + while address < rom_addresses["Trainer_Data_End"]: + if data[address] == 255: + mode = 1 + else: + mode = 0 + while True: + address += 1 + if data[address] == 0: + address += 1 + break + address += mode + mon = None + for i in range(1, 4): + for l in ["A", "B", "C", "D", "E", "F", "G", "H"]: + if rom_addresses[f"Rival_Starter{i}_{l}"] == address: + mon = " ".join(self.world.get_location(f"Pallet Town - Starter {i}", self.player).item.name.split()[1:]) + if l in ["D", "E", "F", "G", "H"] and mon in poke_data.evolves_to: + mon = poke_data.evolves_to[mon] + if l in ["F", "G", "H"] and mon in poke_data.evolves_to: + mon = poke_data.evolves_to[mon] + if mon is None and self.world.randomize_trainer_parties[self.player].value: + mon = poke_data.id_to_mon[data[address]] + mon = randomize_pokemon(self, mon, mons_list, self.world.randomize_trainer_parties[self.player].value) + if mon is not None: + data[address] = poke_data.pokemon_data[mon]["id"] + + +def process_static_pokemon(self): + starter_slots = [location for location in location_data if location.type == "Starter Pokemon"] + legendary_slots = [location for location in location_data if location.type == "Legendary Pokemon"] + static_slots = [location for location in location_data if location.type in + ["Static Pokemon", "Missable Pokemon"]] + legendary_mons = [slot.original_item for slot in legendary_slots] + + mons_list = [pokemon for pokemon in poke_data.first_stage_pokemon if pokemon not in poke_data.legendary_pokemon + or self.world.randomize_legendary_pokemon[self.player].value == 3] + if self.world.randomize_legendary_pokemon[self.player].value == 0: + for slot in legendary_slots: + location = self.world.get_location(slot.name, self.player) + location.place_locked_item(self.create_item("Missable " + slot.original_item)) + elif self.world.randomize_legendary_pokemon[self.player].value == 1: + self.world.random.shuffle(legendary_mons) + for slot in legendary_slots: + location = self.world.get_location(slot.name, self.player) + location.place_locked_item(self.create_item("Missable " + legendary_mons.pop())) + elif self.world.randomize_legendary_pokemon[self.player].value == 2: + static_slots = static_slots + legendary_slots + self.world.random.shuffle(static_slots) + while legendary_slots: + swap_slot = legendary_slots.pop() + slot = static_slots.pop() + slot_type = slot.type.split()[0] + if slot_type == "Legendary": + slot_type = "Missable" + location = self.world.get_location(slot.name, self.player) + location.place_locked_item(self.create_item(slot_type + " " + swap_slot.original_item)) + swap_slot.original_item = slot.original_item + elif self.world.randomize_legendary_pokemon[self.player].value == 3: + static_slots = static_slots + legendary_slots + + for slot in static_slots: + location = self.world.get_location(slot.name, self.player) + randomize_type = self.world.randomize_static_pokemon[self.player].value + slot_type = slot.type.split()[0] + if slot_type == "Legendary": + slot_type = "Missable" + 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))) + + for slot in starter_slots: + location = self.world.get_location(slot.name, self.player) + randomize_type = self.world.randomize_starter_pokemon[self.player].value + slot_type = "Missable" + 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))) + +def process_wild_pokemon(self): + + encounter_slots = get_encounter_slots(self) + + placed_mons = {pokemon: 0 for pokemon in poke_data.pokemon_data.keys()} + if self.world.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.world.randomize_legendary_pokemon[self.player].value == 3] + self.world.random.shuffle(encounter_slots) + locations = [] + for slot in encounter_slots: + mon = randomize_pokemon(self, slot.original_item, mons_list, self.world.randomize_wild_pokemon[self.player].value) + placed_mons[mon] += 1 + location = self.world.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) + + mons_to_add = [] + remaining_pokemon = [pokemon for pokemon in poke_data.pokemon_data.keys() if placed_mons[pokemon] == 0 and + (pokemon not in poke_data.legendary_pokemon or self.world.randomize_legendary_pokemon[self.player].value == 3)] + if self.world.catch_em_all[self.player].value == 1: + mons_to_add = [pokemon for pokemon in poke_data.first_stage_pokemon if placed_mons[pokemon] == 0 and + (pokemon not in poke_data.legendary_pokemon or self.world.randomize_legendary_pokemon[self.player].value == 3)] + elif self.world.catch_em_all[self.player].value == 2: + mons_to_add = remaining_pokemon.copy() + logic_needed_mons = max(self.world.oaks_aide_rt_2[self.player].value, + self.world.oaks_aide_rt_11[self.player].value, + self.world.oaks_aide_rt_15[self.player].value) + if self.world.accessibility[self.player] == "minimal": + logic_needed_mons = 0 + + self.world.random.shuffle(remaining_pokemon) + while (len([pokemon for pokemon in placed_mons if placed_mons[pokemon] > 0]) + + len(mons_to_add) < logic_needed_mons): + mons_to_add.append(remaining_pokemon.pop()) + for mon in mons_to_add: + stat_base = get_base_stat_total(mon) + candidate_locations = get_encounter_slots(self) + if self.world.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 = location_data + candidate_locations = [self.world.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)) + 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 + placed_mons[mon] += 1 + break + + else: + for slot in encounter_slots: + location = self.world.get_location(slot.name, self.player) + location.item = self.create_item(slot.original_item) + location.event = True + location.locked = True + location.item.location = location + placed_mons[location.item.name] += 1 + + +def process_pokemon_data(self): + + local_poke_data = deepcopy(poke_data.pokemon_data) + learnsets = deepcopy(poke_data.learnsets) + + for mon, mon_data in local_poke_data.items(): + if self.world.randomize_pokemon_stats[self.player].value == 1: + stats = [mon_data["hp"], mon_data["atk"], mon_data["def"], mon_data["spd"], mon_data["spc"]] + self.world.random.shuffle(stats) + 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] + elif self.world.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.world.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] + if self.world.randomize_pokemon_types[self.player].value: + if self.world.randomize_pokemon_types[self.player].value == 1 and mon in poke_data.evolves_from: + type1 = local_poke_data[poke_data.evolves_from[mon]]["type1"] + type2 = local_poke_data[poke_data.evolves_from[mon]]["type2"] + if type1 == type2: + if self.world.secondary_type_chance[self.player].value == -1: + if mon_data["type1"] != mon_data["type2"]: + while type2 == type1: + type2 = self.world.random.choice(list(poke_data.type_names.values())) + elif self.world.random.randint(1, 100) <= self.world.secondary_type_chance[self.player].value: + type2 = self.world.random.choice(list(poke_data.type_names.values())) + else: + type1 = self.world.random.choice(list(poke_data.type_names.values())) + type2 = type1 + if ((self.world.secondary_type_chance[self.player].value == -1 and mon_data["type1"] + != mon_data["type2"]) or self.world.random.randint(1, 100) + <= self.world.secondary_type_chance[self.player].value): + while type2 == type1: + type2 = self.world.random.choice(list(poke_data.type_names.values())) + + mon_data["type1"] = type1 + mon_data["type2"] = type2 + if self.world.randomize_pokemon_movesets[self.player].value: + if self.world.randomize_pokemon_movesets[self.player].value == 1: + if mon_data["type1"] == "Normal" and mon_data["type2"] == "Normal": + chances = [[75, "Normal"]] + elif mon_data["type1"] == "Normal" or mon_data["type2"] == "Normal": + if mon_data["type1"] == "Normal": + second_type = mon_data["type2"] + else: + second_type = mon_data["type1"] + chances = [[30, "Normal"], [85, second_type]] + elif mon_data["type1"] == mon_data["type2"]: + chances = [[60, mon_data["type1"]], [80, "Normal"]] + else: + chances = [[50, mon_data["type1"]], [80, mon_data["type2"]], [85, "Normal"]] + else: + chances = [] + moves = set(poke_data.moves.keys()) + moves -= set(["No Move"] + poke_data.hm_moves) + mon_data["start move 1"] = get_move(moves, chances, self.world.random, True) + for i in range(2, 5): + if mon_data[f"start move {i}"] != "No Move" or self.world.start_with_four_moves[ + self.player].value == 1: + mon_data[f"start move {i}"] = get_move(moves, chances, self.world.random) + if mon in learnsets: + for move_num in range(0, len(learnsets[mon])): + learnsets[mon][move_num] = get_move(moves, chances, self.world.random) + if self.world.randomize_pokemon_catch_rates[self.player].value: + mon_data["catch rate"] = self.world.random.randint(self.world.minimum_catch_rate[self.player], 255) + else: + mon_data["catch rate"] = max(self.world.minimum_catch_rate[self.player], mon_data["catch rate"]) + + 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"]: + mon_data["tms"] = local_poke_data[poke_data.evolves_from[mon]]["tms"] + elif mon != "Mew": + tms_hms = poke_data.tm_moves + poke_data.hm_moves + for flag, tm_move in enumerate(tms_hms): + if (flag < 50 and self.world.tm_compatibility[self.player].value == 1) or (flag >= 50 and self.world.hm_compatibility[self.player].value == 1): + type_match = poke_data.moves[tm_move]["type"] in [mon_data["type1"], mon_data["type2"]] + bit = int(self.world.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.world.tm_compatibility[self.player].value == 2) or (flag >= 50 and self.world.hm_compatibility[self.player].value == 2): + bit = [0, 1][self.world.random.randint(0, 1)] + elif (flag < 50 and self.world.tm_compatibility[self.player].value == 3) or (flag >= 50 and self.world.hm_compatibility[self.player].value == 3): + 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)) + + self.local_poke_data = local_poke_data + self.learnsets = learnsets + + + +def generate_output(self, output_directory: str): + random = self.world.slot_seeds[self.player] + game_version = self.world.game_version[self.player].current_key + data = bytearray(get_base_rom_bytes(game_version)) + + basemd5 = hashlib.md5() + basemd5.update(data) + + for location in self.world.get_locations(): + if location.player != self.player or location.rom_address is None: + continue + if location.item and location.item.player == self.player: + if location.rom_address: + rom_address = location.rom_address + if not isinstance(rom_address, list): + rom_address = [rom_address] + for address in rom_address: + if location.item.name in poke_data.pokemon_data.keys(): + data[address] = poke_data.pokemon_data[location.item.name]["id"] + 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 + + else: + data[location.rom_address] = 0x2C # AP Item + data[rom_addresses['Fly_Location']] = self.fly_map_code + + if self.world.tea[self.player].value: + data[rom_addresses["Option_Tea"]] = 1 + data[rom_addresses["Guard_Drink_List"]] = 0x54 + data[rom_addresses["Guard_Drink_List"] + 1] = 0 + data[rom_addresses["Guard_Drink_List"] + 2] = 0 + + if self.world.extra_key_items[self.player].value: + data[rom_addresses['Options']] |= 4 + data[rom_addresses["Option_Blind_Trainers"]] = round(self.world.blind_trainers[self.player].value * 2.55) + data[rom_addresses['Option_Cerulean_Cave_Condition']] = self.world.cerulean_cave_condition[self.player].value + data[rom_addresses['Option_Encounter_Minimum_Steps']] = self.world.minimum_steps_between_encounters[self.player].value + data[rom_addresses['Option_Victory_Road_Badges']] = self.world.victory_road_condition[self.player].value + data[rom_addresses['Option_Pokemon_League_Badges']] = self.world.elite_four_condition[self.player].value + data[rom_addresses['Option_Viridian_Gym_Badges']] = self.world.viridian_gym_condition[self.player].value + data[rom_addresses['Option_EXP_Modifier']] = self.world.exp_modifier[self.player].value + if not self.world.require_item_finder[self.player].value: + data[rom_addresses['Option_Itemfinder']] = 0 + if self.world.extra_strength_boulders[self.player].value: + for i in range(0, 3): + data[rom_addresses['Option_Boulders'] + (i * 3)] = 0x15 + if self.world.extra_key_items[self.player].value: + for i in range(0, 4): + data[rom_addresses['Option_Rock_Tunnel_Extra_Items'] + (i * 3)] = 0x15 + if self.world.old_man[self.player].value == 2: + data[rom_addresses['Option_Old_Man']] = 0x11 + data[rom_addresses['Option_Old_Man_Lying']] = 0x15 + money = str(self.world.starting_money[self.player].value) + while len(money) < 6: + money = "0" + money + data[rom_addresses["Starting_Money_High"]] = int(money[:2], 16) + data[rom_addresses["Starting_Money_Middle"]] = int(money[2:4], 16) + data[rom_addresses["Starting_Money_Low"]] = int(money[4:], 16) + data[rom_addresses["Text_Badges_Needed"]] = encode_text( + str(max(self.world.victory_road_condition[self.player].value, + self.world.elite_four_condition[self.player].value)))[0] + if self.world.badges_needed_for_hm_moves[self.player].value == 0: + for hm_move in poke_data.hm_moves: + write_bytes(data, bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), + rom_addresses["HM_" + hm_move + "_Badge_a"]) + elif self.extra_badges: + written_badges = {} + for hm_move, badge in self.extra_badges.items(): + data[rom_addresses["HM_" + hm_move + "_Badge_b"]] = {"Boulder Badge": 0x47, "Cascade Badge": 0x4F, + "Thunder Badge": 0x57, "Rainbow Badge": 0x5F, + "Soul Badge": 0x67, "Marsh Badge": 0x6F, + "Volcano Badge": 0x77, "Earth Badge": 0x7F}[badge] + move_text = hm_move + if badge not in ["Marsh Badge", "Volcano Badge", "Earth Badge"]: + move_text = ", " + move_text + rom_address = rom_addresses["Badge_Text_" + badge.replace(" ", "_")] + if badge in written_badges: + rom_address += len(written_badges[badge]) + move_text = ", " + move_text + write_bytes(data, encode_text(move_text.upper()), rom_address) + written_badges[badge] = move_text + for badge in ["Marsh Badge", "Volcano Badge", "Earth Badge"]: + if badge not in written_badges: + write_bytes(data, encode_text("Nothing"), rom_addresses["Badge_Text_" + badge.replace(" ", "_")]) + + chart = deepcopy(poke_data.type_chart) + if self.world.randomize_type_matchup_types[self.player].value == 1: + attacking_types = [] + defending_types = [] + for matchup in chart: + attacking_types.append(matchup[0]) + defending_types.append(matchup[1]) + random.shuffle(attacking_types) + random.shuffle(defending_types) + matchups = [] + while len(attacking_types) > 0: + if [attacking_types[0], defending_types[0]] not in matchups: + matchups.append([attacking_types.pop(0), defending_types.pop(0)]) + else: + matchup = matchups.pop(0) + attacking_types.append(matchup[0]) + defending_types.append(matchup[1]) + random.shuffle(attacking_types) + random.shuffle(defending_types) + for matchup, chart_row in zip(matchups, chart): + chart_row[0] = matchup[0] + chart_row[1] = matchup[1] + elif self.world.randomize_type_matchup_types[self.player].value == 2: + used_matchups = [] + for matchup in chart: + matchup[0] = random.choice(list(poke_data.type_names.values())) + matchup[1] = random.choice(list(poke_data.type_names.values())) + while [matchup[0], matchup[1]] in used_matchups: + matchup[0] = random.choice(list(poke_data.type_names.values())) + matchup[1] = random.choice(list(poke_data.type_names.values())) + used_matchups.append([matchup[0], matchup[1]]) + if self.world.randomize_type_matchup_type_effectiveness[self.player].value == 1: + effectiveness_list = [] + for matchup in chart: + effectiveness_list.append(matchup[2]) + random.shuffle(effectiveness_list) + for (matchup, effectiveness) in zip(chart, effectiveness_list): + matchup[2] = effectiveness + elif self.world.randomize_type_matchup_type_effectiveness[self.player].value == 2: + for matchup in chart: + matchup[2] = random.choice([0] + ([5, 20] * 5)) + elif self.world.randomize_type_matchup_type_effectiveness[self.player].value == 3: + for matchup in chart: + matchup[2] = self.world.random.choice([i for i in range(0, 21) if i != 10]) + type_loc = rom_addresses["Type_Chart"] + for matchup in chart: + data[type_loc] = poke_data.type_ids[matchup[0]] + data[type_loc + 1] = poke_data.type_ids[matchup[1]] + data[type_loc + 2] = matchup[2] + type_loc += 3 + # sort so that super-effective matchups occur first, to prevent dual "not very effective" / "super effective" + # matchups from leading to damage being ultimately divided by 2 and then multiplied by 2, which can lead to + # damage being reduced by 1 which leads to a "not very effective" message appearing due to my changes + # to the way effectiveness messages are generated. + self.type_chart = sorted(chart, key=lambda matchup: 0 - matchup[2]) + + if self.world.normalize_encounter_chances[self.player].value: + chances = [25, 51, 77, 103, 129, 155, 180, 205, 230, 255] + for i, chance in enumerate(chances): + data[rom_addresses['Encounter_Chances'] + (i * 2)] = chance + + for mon, mon_data in self.local_poke_data.items(): + if mon == "Mew": + address = rom_addresses["Base_Stats_Mew"] + else: + address = rom_addresses["Base_Stats"] + (28 * (mon_data["dex"] - 1)) + data[address + 1] = self.local_poke_data[mon]["hp"] + data[address + 2] = self.local_poke_data[mon]["atk"] + data[address + 3] = self.local_poke_data[mon]["def"] + data[address + 4] = self.local_poke_data[mon]["spd"] + data[address + 5] = self.local_poke_data[mon]["spc"] + data[address + 6] = poke_data.type_ids[self.local_poke_data[mon]["type1"]] + data[address + 7] = poke_data.type_ids[self.local_poke_data[mon]["type2"]] + data[address + 8] = self.local_poke_data[mon]["catch rate"] + data[address + 15] = poke_data.moves[self.local_poke_data[mon]["start move 1"]]["id"] + data[address + 16] = poke_data.moves[self.local_poke_data[mon]["start move 2"]]["id"] + data[address + 17] = poke_data.moves[self.local_poke_data[mon]["start move 3"]]["id"] + data[address + 18] = poke_data.moves[self.local_poke_data[mon]["start move 4"]]["id"] + write_bytes(data, self.local_poke_data[mon]["tms"], address + 20) + if mon in self.learnsets: + 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.world.oaks_aide_rt_2[self.player] + data[rom_addresses["Option_Aide_Rt11"]] = self.world.oaks_aide_rt_11[self.player] + data[rom_addresses["Option_Aide_Rt15"]] = self.world.oaks_aide_rt_15[self.player] + + if self.world.safari_zone_normal_battles[self.player].value == 1: + data[rom_addresses["Option_Safari_Zone_Battle_Type"]] = 255 + + if self.world.reusable_tms[self.player].value: + data[rom_addresses["Option_Reusable_TMs"]] = 0xC9 + + process_trainer_data(self, data) + + mons = [mon["id"] for mon in poke_data.pokemon_data.values()] + random.shuffle(mons) + data[rom_addresses['Title_Mon_First']] = mons.pop() + for mon in range(0, 16): + data[rom_addresses['Title_Mons'] + mon] = mons.pop() + if self.world.game_version[self.player].value: + mons.sort(key=lambda mon: 0 if mon == self.world.get_location("Pallet Town - Starter 1", self.player).item.name + else 1 if mon == self.world.get_location("Pallet Town - Starter 2", self.player).item.name else + 2 if mon == self.world.get_location("Pallet Town - Starter 3", self.player).item.name else 3) + else: + mons.sort(key=lambda mon: 0 if mon == self.world.get_location("Pallet Town - Starter 2", self.player).item.name + else 1 if mon == self.world.get_location("Pallet Town - Starter 1", self.player).item.name else + 2 if mon == self.world.get_location("Pallet Town - Starter 3", self.player).item.name else 3) + write_bytes(data, encode_text(self.world.seed_name, 20, True), rom_addresses['Title_Seed']) + + slot_name = self.world.player_name[self.player] + slot_name.replace("@", " ") + slot_name.replace("<", " ") + slot_name.replace(">", " ") + write_bytes(data, encode_text(slot_name, 16, True, True), rom_addresses['Title_Slot_Name']) + + write_bytes(data, self.trainer_name, rom_addresses['Player_Name']) + write_bytes(data, self.rival_name, rom_addresses['Rival_Name']) + + write_bytes(data, basemd5.digest(), 0xFFCC) + write_bytes(data, self.world.seed_name.encode(), 0xFFDC) + write_bytes(data, self.world.player_name[self.player].encode(), 0xFFF0) + + + + outfilepname = f'_P{self.player}' + outfilepname += f"_{self.world.get_file_safe_player_name(self.player).replace(' ', '_')}" \ + if self.world.player_name[self.player] != 'Player%d' % self.player else '' + rompath = os.path.join(output_directory, f'AP_{self.world.seed_name}{outfilepname}.gb') + with open(rompath, 'wb') as outfile: + outfile.write(data) + if self.world.game_version[self.player].current_key == "red": + patch = RedDeltaPatch(os.path.splitext(rompath)[0] + RedDeltaPatch.patch_file_ending, player=self.player, + player_name=self.world.player_name[self.player], patched_path=rompath) + else: + patch = BlueDeltaPatch(os.path.splitext(rompath)[0] + BlueDeltaPatch.patch_file_ending, player=self.player, + player_name=self.world.player_name[self.player], patched_path=rompath) + + patch.write() + os.unlink(rompath) + + +def write_bytes(data, byte_array, address): + for byte in byte_array: + data[address] = byte + address += 1 + + +def get_base_rom_bytes(game_version: str, hash: str="") -> bytes: + file_name = get_base_rom_path(game_version) + with open(file_name, "rb") as file: + base_rom_bytes = bytes(file.read()) + if hash: + basemd5 = hashlib.md5() + basemd5.update(base_rom_bytes) + if hash != basemd5.hexdigest(): + raise Exception('Supplied Base Rom does not match known MD5 for US(1.0) release. ' + 'Get the correct game and version, then dump it') + with open(os.path.join(os.path.dirname(__file__), f'basepatch_{game_version}.bsdiff4'), 'rb') as stream: + base_patch = bytes(stream.read()) + base_rom_bytes = bsdiff4.patch(base_rom_bytes, base_patch) + return base_rom_bytes + + +def get_base_rom_path(game_version: str) -> str: + options = Utils.get_options() + file_name = options["pokemon_rb_options"][f"{game_version}_rom_file"] + if not os.path.exists(file_name): + file_name = Utils.local_path(file_name) + return file_name + + +class BlueDeltaPatch(APDeltaPatch): + patch_file_ending = ".apblue" + hash = "50927e843568814f7ed45ec4f944bd8b" + game_version = "blue" + game = "Pokemon Red and Blue" + result_file_ending = ".gb" + @classmethod + def get_source_data(cls) -> bytes: + return get_base_rom_bytes(cls.game_version, cls.hash) + + +class RedDeltaPatch(APDeltaPatch): + patch_file_ending = ".apred" + hash = "3d45c1ee9abd5738df46d2bdda8b57dc" + game_version = "red" + game = "Pokemon Red and Blue" + result_file_ending = ".gb" + @classmethod + def get_source_data(cls) -> bytes: + return get_base_rom_bytes(cls.game_version, cls.hash) diff --git a/worlds/pokemon_rb/rom_addresses.py b/worlds/pokemon_rb/rom_addresses.py new file mode 100644 index 00000000..c04a75bc --- /dev/null +++ b/worlds/pokemon_rb/rom_addresses.py @@ -0,0 +1,588 @@ +rom_addresses = { + "Option_Encounter_Minimum_Steps": 0x3c3, + "Option_Blind_Trainers": 0x317e, + "Base_Stats_Mew": 0x425b, + "Title_Mon_First": 0x436e, + "Title_Mons": 0x4547, + "Player_Name": 0x4569, + "Rival_Name": 0x4571, + "Title_Seed": 0x5dfe, + "Title_Slot_Name": 0x5e1e, + "PC_Item": 0x61ec, + "PC_Item_Quantity": 0x61f1, + "Options": 0x61f9, + "Fly_Location": 0x61fe, + "Option_Old_Man": 0xcaef, + "Option_Old_Man_Lying": 0xcaf2, + "Option_Boulders": 0xcd98, + "Option_Rock_Tunnel_Extra_Items": 0xcda1, + "Wild_Route1": 0xd0fb, + "Wild_Route2": 0xd111, + "Wild_Route22": 0xd127, + "Wild_ViridianForest": 0xd13d, + "Wild_Route3": 0xd153, + "Wild_MtMoon1F": 0xd169, + "Wild_MtMoonB1F": 0xd17f, + "Wild_MtMoonB2F": 0xd195, + "Wild_Route4": 0xd1ab, + "Wild_Route24": 0xd1c1, + "Wild_Route25": 0xd1d7, + "Wild_Route9": 0xd1ed, + "Wild_Route5": 0xd203, + "Wild_Route6": 0xd219, + "Wild_Route11": 0xd22f, + "Wild_RockTunnel1F": 0xd245, + "Wild_RockTunnelB1F": 0xd25b, + "Wild_Route10": 0xd271, + "Wild_Route12": 0xd287, + "Wild_Route8": 0xd29d, + "Wild_Route7": 0xd2b3, + "Wild_PokemonTower3F": 0xd2cd, + "Wild_PokemonTower4F": 0xd2e3, + "Wild_PokemonTower5F": 0xd2f9, + "Wild_PokemonTower6F": 0xd30f, + "Wild_PokemonTower7F": 0xd325, + "Wild_Route13": 0xd33b, + "Wild_Route14": 0xd351, + "Wild_Route15": 0xd367, + "Wild_Route16": 0xd37d, + "Wild_Route17": 0xd393, + "Wild_Route18": 0xd3a9, + "Wild_SafariZoneCenter": 0xd3bf, + "Wild_SafariZoneEast": 0xd3d5, + "Wild_SafariZoneNorth": 0xd3eb, + "Wild_SafariZoneWest": 0xd401, + "Wild_SeaRoutes": 0xd418, + "Wild_SeafoamIslands1F": 0xd42d, + "Wild_SeafoamIslandsB1F": 0xd443, + "Wild_SeafoamIslandsB2F": 0xd459, + "Wild_SeafoamIslandsB3F": 0xd46f, + "Wild_SeafoamIslandsB4F": 0xd485, + "Wild_PokemonMansion1F": 0xd49b, + "Wild_PokemonMansion2F": 0xd4b1, + "Wild_PokemonMansion3F": 0xd4c7, + "Wild_PokemonMansionB1F": 0xd4dd, + "Wild_Route21": 0xd4f3, + "Wild_Surf_Route21": 0xd508, + "Wild_CeruleanCave1F": 0xd51d, + "Wild_CeruleanCave2F": 0xd533, + "Wild_CeruleanCaveB1F": 0xd549, + "Wild_PowerPlant": 0xd55f, + "Wild_Route23": 0xd575, + "Wild_VictoryRoad2F": 0xd58b, + "Wild_VictoryRoad3F": 0xd5a1, + "Wild_VictoryRoad1F": 0xd5b7, + "Wild_DiglettsCave": 0xd5cd, + "Ghost_Battle5": 0xd723, + "HM_Surf_Badge_a": 0xda11, + "HM_Surf_Badge_b": 0xda16, + "Wild_Old_Rod": 0xe313, + "Wild_Good_Rod": 0xe340, + "Option_Reusable_TMs": 0xe60c, + "Wild_Super_Rod_A": 0xea40, + "Wild_Super_Rod_B": 0xea45, + "Wild_Super_Rod_C": 0xea4a, + "Wild_Super_Rod_D": 0xea51, + "Wild_Super_Rod_E": 0xea56, + "Wild_Super_Rod_F": 0xea5b, + "Wild_Super_Rod_G": 0xea64, + "Wild_Super_Rod_H": 0xea6d, + "Wild_Super_Rod_I": 0xea76, + "Wild_Super_Rod_J": 0xea7f, + "Starting_Money_High": 0xf949, + "Starting_Money_Middle": 0xf94c, + "Starting_Money_Low": 0xf94f, + "HM_Fly_Badge_a": 0x1318e, + "HM_Fly_Badge_b": 0x13193, + "HM_Cut_Badge_a": 0x131c4, + "HM_Cut_Badge_b": 0x131c9, + "HM_Strength_Badge_a": 0x131f4, + "HM_Strength_Badge_b": 0x131f9, + "HM_Flash_Badge_a": 0x13208, + "HM_Flash_Badge_b": 0x1320d, + "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": 0x19b2b, + "Event_Rivals_Sister": 0x19cf9, + "Option_Pokemon_League_Badges": 0x19e16, + "Missable_Silph_Co_4F_Item_1": 0x1a0d7, + "Missable_Silph_Co_4F_Item_2": 0x1a0de, + "Missable_Silph_Co_4F_Item_3": 0x1a0e5, + "Missable_Silph_Co_5F_Item_1": 0x1a337, + "Missable_Silph_Co_5F_Item_2": 0x1a33e, + "Missable_Silph_Co_5F_Item_3": 0x1a345, + "Missable_Silph_Co_6F_Item_1": 0x1a5ad, + "Missable_Silph_Co_6F_Item_2": 0x1a5b4, + "Event_Free_Sample": 0x1cade, + "Starter1_F": 0x1cca5, + "Starter2_F": 0x1cca9, + "Starter2_G": 0x1cde2, + "Starter3_G": 0x1cdea, + "Starter2_H": 0x1d0e5, + "Starter1_H": 0x1d0ef, + "Starter3_I": 0x1d0f6, + "Starter2_I": 0x1d100, + "Starter1_D": 0x1d107, + "Starter3_D": 0x1d111, + "Starter2_E": 0x1d2eb, + "Starter3_E": 0x1d2f3, + "Event_Oaks_Gift": 0x1d373, + "Event_Pokemart_Quest": 0x1d566, + "Event_Bicycle_Shop": 0x1d805, + "Text_Bicycle": 0x1d898, + "Event_Fuji": 0x1d9cd, + "Static_Encounter_Mew": 0x1dc4e, + "Gift_Eevee": 0x1dcc7, + "Event_Mr_Psychic": 0x1ddcf, + "Static_Encounter_Voltorb_A": 0x1e397, + "Static_Encounter_Voltorb_B": 0x1e39f, + "Static_Encounter_Voltorb_C": 0x1e3a7, + "Static_Encounter_Electrode_A": 0x1e3af, + "Static_Encounter_Voltorb_D": 0x1e3b7, + "Static_Encounter_Voltorb_E": 0x1e3bf, + "Static_Encounter_Electrode_B": 0x1e3c7, + "Static_Encounter_Voltorb_F": 0x1e3cf, + "Static_Encounter_Zapdos": 0x1e3d7, + "Missable_Power_Plant_Item_1": 0x1e3df, + "Missable_Power_Plant_Item_2": 0x1e3e6, + "Missable_Power_Plant_Item_3": 0x1e3ed, + "Missable_Power_Plant_Item_4": 0x1e3f4, + "Missable_Power_Plant_Item_5": 0x1e3fb, + "Event_Rt16_House_Woman": 0x1e5d4, + "Option_Victory_Road_Badges": 0x1e6a5, + "Event_Bill": 0x1e8d6, + "Starter1_O": 0x372b0, + "Starter2_O": 0x372b4, + "Starter3_O": 0x372b8, + "Base_Stats": 0x383de, + "Starter3_C": 0x39cf2, + "Starter1_C": 0x39cf8, + "Trainer_Data": 0x39d99, + "Rival_Starter2_A": 0x3a1e5, + "Rival_Starter3_A": 0x3a1e8, + "Rival_Starter1_A": 0x3a1eb, + "Rival_Starter2_B": 0x3a1f1, + "Rival_Starter3_B": 0x3a1f7, + "Rival_Starter1_B": 0x3a1fd, + "Rival_Starter2_C": 0x3a207, + "Rival_Starter3_C": 0x3a211, + "Rival_Starter1_C": 0x3a21b, + "Rival_Starter2_D": 0x3a409, + "Rival_Starter3_D": 0x3a413, + "Rival_Starter1_D": 0x3a41d, + "Rival_Starter2_E": 0x3a429, + "Rival_Starter3_E": 0x3a435, + "Rival_Starter1_E": 0x3a441, + "Rival_Starter2_F": 0x3a44d, + "Rival_Starter3_F": 0x3a459, + "Rival_Starter1_F": 0x3a465, + "Rival_Starter2_G": 0x3a473, + "Rival_Starter3_G": 0x3a481, + "Rival_Starter1_G": 0x3a48f, + "Rival_Starter2_H": 0x3a49d, + "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, + "Type_Chart": 0x3e4b6, + "Type_Chart_Divider": 0x3e5ac, + "Ghost_Battle3": 0x3efd9, + "Missable_Pokemon_Mansion_1F_Item_1": 0x443d6, + "Missable_Pokemon_Mansion_1F_Item_2": 0x443dd, + "Map_Rock_TunnelF": 0x44676, + "Missable_Victory_Road_3F_Item_1": 0x44b07, + "Missable_Victory_Road_3F_Item_2": 0x44b0e, + "Missable_Rocket_Hideout_B1F_Item_1": 0x44d2d, + "Missable_Rocket_Hideout_B1F_Item_2": 0x44d34, + "Missable_Rocket_Hideout_B2F_Item_1": 0x4511d, + "Missable_Rocket_Hideout_B2F_Item_2": 0x45124, + "Missable_Rocket_Hideout_B2F_Item_3": 0x4512b, + "Missable_Rocket_Hideout_B2F_Item_4": 0x45132, + "Missable_Rocket_Hideout_B3F_Item_1": 0x4536f, + "Missable_Rocket_Hideout_B3F_Item_2": 0x45376, + "Missable_Rocket_Hideout_B4F_Item_1": 0x45627, + "Missable_Rocket_Hideout_B4F_Item_2": 0x4562e, + "Missable_Rocket_Hideout_B4F_Item_3": 0x45635, + "Missable_Rocket_Hideout_B4F_Item_4": 0x4563c, + "Missable_Rocket_Hideout_B4F_Item_5": 0x45643, + "Missable_Safari_Zone_East_Item_1": 0x458b2, + "Missable_Safari_Zone_East_Item_2": 0x458b9, + "Missable_Safari_Zone_East_Item_3": 0x458c0, + "Missable_Safari_Zone_East_Item_4": 0x458c7, + "Missable_Safari_Zone_North_Item_1": 0x45a12, + "Missable_Safari_Zone_North_Item_2": 0x45a19, + "Missable_Safari_Zone_Center_Item": 0x45bf9, + "Missable_Cerulean_Cave_2F_Item_1": 0x45e36, + "Missable_Cerulean_Cave_2F_Item_2": 0x45e3d, + "Missable_Cerulean_Cave_2F_Item_3": 0x45e44, + "Static_Encounter_Mewtwo": 0x45f44, + "Missable_Cerulean_Cave_B1F_Item_1": 0x45f4c, + "Missable_Cerulean_Cave_B1F_Item_2": 0x45f53, + "Missable_Rock_Tunnel_B1F_Item_1": 0x4619f, + "Missable_Rock_Tunnel_B1F_Item_2": 0x461a6, + "Missable_Rock_Tunnel_B1F_Item_3": 0x461ad, + "Missable_Rock_Tunnel_B1F_Item_4": 0x461b4, + "Static_Encounter_Articuno": 0x4690c, + "Hidden_Item_Viridian_Forest_1": 0x46e6d, + "Hidden_Item_Viridian_Forest_2": 0x46e73, + "Hidden_Item_MtMoonB2F_1": 0x46e7a, + "Hidden_Item_MtMoonB2F_2": 0x46e80, + "Hidden_Item_Route_25_1": 0x46e94, + "Hidden_Item_Route_25_2": 0x46e9a, + "Hidden_Item_Route_9": 0x46ea1, + "Hidden_Item_SS_Anne_Kitchen": 0x46eb4, + "Hidden_Item_SS_Anne_B1F": 0x46ebb, + "Hidden_Item_Route_10_1": 0x46ec2, + "Hidden_Item_Route_10_2": 0x46ec8, + "Hidden_Item_Rocket_Hideout_B1F": 0x46ecf, + "Hidden_Item_Rocket_Hideout_B3F": 0x46ed6, + "Hidden_Item_Rocket_Hideout_B4F": 0x46edd, + "Hidden_Item_Pokemon_Tower_5F": 0x46ef1, + "Hidden_Item_Route_13_1": 0x46ef8, + "Hidden_Item_Route_13_2": 0x46efe, + "Hidden_Item_Safari_Zone_West": 0x46f0c, + "Hidden_Item_Silph_Co_5F": 0x46f13, + "Hidden_Item_Silph_Co_9F": 0x46f1a, + "Hidden_Item_Copycats_House": 0x46f21, + "Hidden_Item_Cerulean_Cave_1F": 0x46f28, + "Hidden_Item_Cerulean_Cave_B1F": 0x46f2f, + "Hidden_Item_Power_Plant_1": 0x46f36, + "Hidden_Item_Power_Plant_2": 0x46f3c, + "Hidden_Item_Seafoam_Islands_B2F": 0x46f43, + "Hidden_Item_Seafoam_Islands_B4F": 0x46f4a, + "Hidden_Item_Pokemon_Mansion_1F": 0x46f51, + "Hidden_Item_Pokemon_Mansion_3F": 0x46f65, + "Hidden_Item_Pokemon_Mansion_B1F": 0x46f72, + "Hidden_Item_Route_23_1": 0x46f85, + "Hidden_Item_Route_23_2": 0x46f8b, + "Hidden_Item_Route_23_3": 0x46f91, + "Hidden_Item_Victory_Road_2F_1": 0x46f98, + "Hidden_Item_Victory_Road_2F_2": 0x46f9e, + "Hidden_Item_Unused_6F": 0x46fa5, + "Hidden_Item_Viridian_City": 0x46fb3, + "Hidden_Item_Route_11": 0x47060, + "Hidden_Item_Route_12": 0x47067, + "Hidden_Item_Route_17_1": 0x47075, + "Hidden_Item_Route_17_2": 0x4707b, + "Hidden_Item_Route_17_3": 0x47081, + "Hidden_Item_Route_17_4": 0x47087, + "Hidden_Item_Route_17_5": 0x4708d, + "Hidden_Item_Underground_Path_NS_1": 0x47094, + "Hidden_Item_Underground_Path_NS_2": 0x4709a, + "Hidden_Item_Underground_Path_WE_1": 0x470a1, + "Hidden_Item_Underground_Path_WE_2": 0x470a7, + "Hidden_Item_Celadon_City": 0x470ae, + "Hidden_Item_Seafoam_Islands_B3F": 0x470b5, + "Hidden_Item_Vermilion_City": 0x470bc, + "Hidden_Item_Cerulean_City": 0x470c3, + "Hidden_Item_Route_4": 0x470ca, + "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, + "Event_Gambling_Addict": 0x49293, + "Gift_Magikarp": 0x49430, + "Option_Aide_Rt11": 0x4958d, + "Event_Rt11_Oaks_Aide": 0x49591, + "Event_Mourning_Girl": 0x4968b, + "Option_Aide_Rt15": 0x49776, + "Event_Rt_15_Oaks_Aide": 0x4977a, + "Missable_Mt_Moon_1F_Item_1": 0x49c75, + "Missable_Mt_Moon_1F_Item_2": 0x49c7c, + "Missable_Mt_Moon_1F_Item_3": 0x49c83, + "Missable_Mt_Moon_1F_Item_4": 0x49c8a, + "Missable_Mt_Moon_1F_Item_5": 0x49c91, + "Missable_Mt_Moon_1F_Item_6": 0x49c98, + "Dome_Fossil_Text": 0x4a001, + "Event_Dome_Fossil": 0x4a021, + "Helix_Fossil_Text": 0x4a05d, + "Event_Helix_Fossil": 0x4a07d, + "Missable_Mt_Moon_B2F_Item_1": 0x4a166, + "Missable_Mt_Moon_B2F_Item_2": 0x4a16d, + "Missable_Safari_Zone_West_Item_1": 0x4a34f, + "Missable_Safari_Zone_West_Item_2": 0x4a356, + "Missable_Safari_Zone_West_Item_3": 0x4a35d, + "Missable_Safari_Zone_West_Item_4": 0x4a364, + "Event_Safari_Zone_Secret_House": 0x4a469, + "Missable_Route_24_Item": 0x506e6, + "Missable_Route_25_Item": 0x5080b, + "Starter2_B": 0x50fce, + "Starter3_B": 0x50fd0, + "Starter1_B": 0x50fd2, + "Starter2_A": 0x510f1, + "Starter3_A": 0x510f3, + "Starter1_A": 0x510f5, + "Option_Badge_Goal": 0x51317, + "Event_Nugget_Bridge": 0x5148f, + "Static_Encounter_Moltres": 0x51939, + "Missable_Victory_Road_2F_Item_1": 0x51941, + "Missable_Victory_Road_2F_Item_2": 0x51948, + "Missable_Victory_Road_2F_Item_3": 0x5194f, + "Missable_Victory_Road_2F_Item_4": 0x51956, + "Starter2_L": 0x51c85, + "Starter3_L": 0x51c8d, + "Gift_Lapras": 0x51d83, + "Missable_Silph_Co_7F_Item_1": 0x51f0d, + "Missable_Silph_Co_7F_Item_2": 0x51f14, + "Missable_Pokemon_Mansion_2F_Item": 0x520c9, + "Missable_Pokemon_Mansion_3F_Item_1": 0x522e2, + "Missable_Pokemon_Mansion_3F_Item_2": 0x522e9, + "Missable_Pokemon_Mansion_B1F_Item_1": 0x5248c, + "Missable_Pokemon_Mansion_B1F_Item_2": 0x52493, + "Missable_Pokemon_Mansion_B1F_Item_3": 0x5249a, + "Missable_Pokemon_Mansion_B1F_Item_4": 0x524a1, + "Missable_Pokemon_Mansion_B1F_Item_5": 0x524ae, + "Option_Safari_Zone_Battle_Type": 0x525c3, + "Prize_Mon_A2": 0x5282f, + "Prize_Mon_B2": 0x52830, + "Prize_Mon_C2": 0x52831, + "Prize_Mon_D2": 0x5283a, + "Prize_Mon_E2": 0x5283b, + "Prize_Mon_F2": 0x5283c, + "Prize_Mon_A": 0x52960, + "Prize_Mon_B": 0x52962, + "Prize_Mon_C": 0x52964, + "Prize_Mon_D": 0x52966, + "Prize_Mon_E": 0x52968, + "Prize_Mon_F": 0x5296a, + "Missable_Route_2_Item_1": 0x5404a, + "Missable_Route_2_Item_2": 0x54051, + "Missable_Route_4_Item": 0x543df, + "Missable_Route_9_Item": 0x546fd, + "Option_EXP_Modifier": 0x552c5, + "Rod_Vermilion_City_Fishing_Guru": 0x560df, + "Rod_Fuchsia_City_Fishing_Brother": 0x561eb, + "Rod_Route12_Fishing_Brother": 0x564ee, + "Missable_Route_12_Item_1": 0x58704, + "Missable_Route_12_Item_2": 0x5870b, + "Missable_Route_15_Item": 0x589c7, + "Ghost_Battle6": 0x58df0, + "Static_Encounter_Snorlax_A": 0x5969b, + "Static_Encounter_Snorlax_B": 0x599db, + "Event_Pokemon_Fan_Club": 0x59c8b, + "Event_Scared_Woman": 0x59e1f, + "Missable_Silph_Co_3F_Item": 0x5a0cb, + "Missable_Silph_Co_10F_Item_1": 0x5a281, + "Missable_Silph_Co_10F_Item_2": 0x5a288, + "Missable_Silph_Co_10F_Item_3": 0x5a28f, + "Guard_Drink_List": 0x5a600, + "Event_Museum": 0x5c266, + "Badge_Pewter_Gym": 0x5c3ed, + "Event_Pewter_Gym": 0x5c401, + "Badge_Cerulean_Gym": 0x5c716, + "Event_Cerulean_Gym": 0x5c72a, + "Badge_Vermilion_Gym": 0x5caba, + "Event_Vermillion_Gym": 0x5cace, + "Event_Copycat": 0x5cca9, + "Gift_Hitmonlee": 0x5cf1a, + "Gift_Hitmonchan": 0x5cf62, + "Badge_Saffron_Gym": 0x5d079, + "Event_Saffron_Gym": 0x5d08d, + "Option_Aide_Rt2": 0x5d5f2, + "Event_Route_2_Oaks_Aide": 0x5d5f6, + "Missable_Victory_Road_1F_Item_1": 0x5dae6, + "Missable_Victory_Road_1F_Item_2": 0x5daed, + "Starter2_J": 0x6060e, + "Starter3_J": 0x60616, + "Missable_Pokemon_Tower_3F_Item": 0x60787, + "Missable_Pokemon_Tower_4F_Item_1": 0x608b5, + "Missable_Pokemon_Tower_4F_Item_2": 0x608bc, + "Missable_Pokemon_Tower_4F_Item_3": 0x608c3, + "Missable_Pokemon_Tower_5F_Item": 0x60a80, + "Ghost_Battle1": 0x60b33, + "Ghost_Battle2": 0x60c0a, + "Missable_Pokemon_Tower_6F_Item_1": 0x60c85, + "Missable_Pokemon_Tower_6F_Item_2": 0x60c8c, + "Gift_Aerodactyl": 0x61064, + "Gift_Omanyte": 0x61068, + "Gift_Kabuto": 0x6106c, + "Missable_Viridian_Forest_Item_1": 0x6122c, + "Missable_Viridian_Forest_Item_2": 0x61233, + "Missable_Viridian_Forest_Item_3": 0x6123a, + "Starter2_M": 0x61450, + "Starter3_M": 0x61458, + "Event_SS_Anne_Captain": 0x618c3, + "Missable_SS_Anne_1F_Item": 0x61ac0, + "Missable_SS_Anne_2F_Item_1": 0x61ced, + "Missable_SS_Anne_2F_Item_2": 0x61d00, + "Missable_SS_Anne_B1F_Item_1": 0x61ee3, + "Missable_SS_Anne_B1F_Item_2": 0x61eea, + "Missable_SS_Anne_B1F_Item_3": 0x61ef1, + "Event_Silph_Co_President": 0x622ed, + "Ghost_Battle4": 0x708e1, + "Badge_Viridian_Gym": 0x749ca, + "Event_Viridian_Gym": 0x749de, + "Missable_Viridian_Gym_Item": 0x74c63, + "Missable_Cerulean_Cave_1F_Item_1": 0x74d68, + "Missable_Cerulean_Cave_1F_Item_2": 0x74d6f, + "Missable_Cerulean_Cave_1F_Item_3": 0x74d76, + "Event_Warden": 0x7512a, + "Missable_Wardens_House_Item": 0x751b7, + "Badge_Fuchsia_Gym": 0x755cd, + "Event_Fuschia_Gym": 0x755e1, + "Badge_Cinnabar_Gym": 0x75995, + "Event_Cinnabar_Gym": 0x759a9, + "Event_Lab_Scientist": 0x75dd6, + "Fossils_Needed_For_Second_Item": 0x75ea3, + "Event_Dome_Fossil_B": 0x75f20, + "Event_Helix_Fossil_B": 0x75f40, + "Starter2_N": 0x76169, + "Starter3_N": 0x76171, + "Option_Itemfinder": 0x76864, + "Text_Badges_Needed": 0x92304, + "Badge_Text_Boulder_Badge": 0x990b3, + "Badge_Text_Cascade_Badge": 0x990cb, + "Badge_Text_Thunder_Badge": 0x99111, + "Badge_Text_Rainbow_Badge": 0x9912e, + "Badge_Text_Soul_Badge": 0x99177, + "Badge_Text_Marsh_Badge": 0x9918c, + "Badge_Text_Volcano_Badge": 0x991d6, + "Badge_Text_Earth_Badge": 0x991f3, +} diff --git a/worlds/pokemon_rb/rules.py b/worlds/pokemon_rb/rules.py new file mode 100644 index 00000000..0e97b705 --- /dev/null +++ b/worlds/pokemon_rb/rules.py @@ -0,0 +1,165 @@ +from ..generic.Rules import add_item_rule, add_rule + +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) + + 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_has_pokemon(state.world.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), + "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_has_pokemon(state.world.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), + "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 - Item": lambda state: state.pokemon_rb_can_cut(player), + "Route 25 - Item": lambda state: state.pokemon_rb_can_cut(player), + "Fuchsia City - Warden's House Item": lambda state: state.pokemon_rb_can_strength(player), + "Rocket Hideout B4F - Southwest Item (Lift Key)": lambda state: state.has("Lift Key", player), + "Rocket Hideout B4F - Giovanni Item (Lift Key)": lambda state: state.has("Lift Key", player), + "Silph Co 3F - Item (Card Key)": lambda state: state.has("Card Key", player), + "Silph Co 4F - Left Item (Card Key)": lambda state: state.has("Card Key", player), + "Silph Co 4F - Middle Item (Card Key)": lambda state: state.has("Card Key", player), + "Silph Co 4F - Right Item (Card Key)": lambda state: state.has("Card Key", player), + "Silph Co 5F - Northwest Item (Card Key)": lambda state: state.has("Card Key", player), + "Silph Co 6F - West Item (Card Key)": lambda state: state.has("Card Key", 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), + + "Silph Co 11F - Silph Co Liberated": lambda state: state.has("Card Key", player), + + "Pallet Town - Super Rod Pokemon - 1": lambda state: state.has("Super Rod", player), + "Pallet Town - Super Rod Pokemon - 2": lambda state: state.has("Super Rod", player), + "Route 22 - Super Rod Pokemon - 1": lambda state: state.has("Super Rod", player), + "Route 22 - Super Rod Pokemon - 2": lambda state: state.has("Super Rod", player), + "Route 24 - Super Rod Pokemon - 1": lambda state: state.has("Super Rod", player), + "Route 24 - Super Rod Pokemon - 2": lambda state: state.has("Super Rod", player), + "Route 24 - Super Rod Pokemon - 3": lambda state: state.has("Super Rod", player), + "Route 6 - Super Rod Pokemon - 1": lambda state: state.has("Super Rod", player), + "Route 6 - Super Rod Pokemon - 2": lambda state: state.has("Super Rod", player), + "Route 10 - Super Rod Pokemon - 1": lambda state: state.has("Super Rod", player), + "Route 10 - Super Rod Pokemon - 2": lambda state: state.has("Super Rod", player), + "Safari Zone Center - Super Rod Pokemon - 1": lambda state: state.has("Super Rod", player), + "Safari Zone Center - Super Rod Pokemon - 2": lambda state: state.has("Super Rod", player), + "Safari Zone Center - Super Rod Pokemon - 3": lambda state: state.has("Super Rod", player), + "Safari Zone Center - Super Rod Pokemon - 4": lambda state: state.has("Super Rod", player), + "Route 12 - Super Rod Pokemon - 1": lambda state: state.has("Super Rod", player), + "Route 12 - Super Rod Pokemon - 2": lambda state: state.has("Super Rod", player), + "Route 12 - Super Rod Pokemon - 3": lambda state: state.has("Super Rod", player), + "Route 12 - Super Rod Pokemon - 4": lambda state: state.has("Super Rod", player), + "Route 19 - Super Rod Pokemon - 1": lambda state: state.has("Super Rod", player), + "Route 19 - Super Rod Pokemon - 2": lambda state: state.has("Super Rod", player), + "Route 19 - Super Rod Pokemon - 3": lambda state: state.has("Super Rod", player), + "Route 19 - Super Rod Pokemon - 4": lambda state: state.has("Super Rod", player), + "Route 23 - Super Rod Pokemon - 1": lambda state: state.has("Super Rod", player), + "Route 23 - Super Rod Pokemon - 2": lambda state: state.has("Super Rod", player), + "Route 23 - Super Rod Pokemon - 3": lambda state: state.has("Super Rod", player), + "Route 23 - Super Rod Pokemon - 4": lambda state: state.has("Super Rod", player), + "Fuchsia City - Super Rod Pokemon - 1": lambda state: state.has("Super Rod", player), + "Fuchsia City - Super Rod Pokemon - 2": lambda state: state.has("Super Rod", player), + "Fuchsia City - Super Rod Pokemon - 3": lambda state: state.has("Super Rod", player), + "Fuchsia City - Super Rod Pokemon - 4": lambda state: state.has("Super Rod", player), + "Anywhere - Good Rod Pokemon - 1": lambda state: state.has("Good Rod", player), + "Anywhere - Good Rod Pokemon - 2": lambda state: state.has("Good Rod", player), + "Anywhere - Old Rod Pokemon": lambda state: state.has("Old Rod", player), + "Celadon Prize Corner - Pokemon Prize - 1": lambda state: state.has("Coin Case", player), + "Celadon Prize Corner - Pokemon Prize - 2": lambda state: state.has("Coin Case", player), + "Celadon Prize Corner - Pokemon Prize - 3": lambda state: state.has("Coin Case", player), + "Celadon Prize Corner - Pokemon Prize - 4": lambda state: state.has("Coin Case", player), + "Celadon Prize Corner - Pokemon Prize - 5": lambda state: state.has("Coin Case", player), + "Celadon Prize Corner - Pokemon Prize - 6": lambda state: state.has("Coin Case", player), + "Cinnabar Island - Old Amber Pokemon": lambda state: state.has("Old Amber", player), + "Cinnabar Island - Helix Fossil Pokemon": lambda state: state.has("Helix Fossil", player), + "Cinnabar Island - Dome Fossil Pokemon": lambda state: state.has("Dome Fossil", player), + "Route 12 - Sleeping Pokemon": lambda state: state.has("Poke Flute", player), + "Route 16 - Sleeping Pokemon": lambda state: state.has("Poke Flute", player), + "Seafoam Islands B4F - Legendary Pokemon": lambda state: 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) + } + + hidden_item_access_rules = { + "Viridian Forest - Hidden Item Northwest by Trainer": lambda state: state.pokemon_rb_can_get_hidden_items( + player), + "Viridian Forest - Hidden Item Entrance Tree": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Mt Moon B2F - Hidden Item Dead End Before Fossils": lambda state: state.pokemon_rb_can_get_hidden_items( + player), + "Route 25 - Hidden Item Fence Outside Bill's House": lambda state: state.pokemon_rb_can_get_hidden_items( + player), + "Route 9 - Hidden Item Rock By Grass": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "S.S. Anne 1F - Hidden Item Kitchen Trash": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "S.S. Anne B1F - Hidden Item Under Pillow": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Route 10 - Hidden Item Behind Rock Tunnel Entrance Tree": lambda + state: state.pokemon_rb_can_get_hidden_items(player), + "Route 10 - Hidden Item Rock": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Rocket Hideout B1F - Hidden Item Pot Plant": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Rocket Hideout B3F - Hidden Item Near East Item": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Rocket Hideout B4F - Hidden Item Behind Giovanni": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Pokemon Tower 5F - Hidden Item Near West Staircase": lambda state: state.pokemon_rb_can_get_hidden_items( + player), + "Route 13 - Hidden Item Dead End Boulder": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Route 13 - Hidden Item Dead End By Water Corner": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Pokemon Mansion B1F - Hidden Item Secret Key Room Corner": lambda state: state.pokemon_rb_can_get_hidden_items( + player), + "Safari Zone West - Hidden Item Secret House Statue": lambda state: state.pokemon_rb_can_get_hidden_items( + player), + "Silph Co 5F - Hidden Item Pot Plant": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Silph Co 9F - Hidden Item Nurse Bed": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Copycat's House - Hidden Item Desk": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Cerulean Cave 1F - Hidden Item Center Rocks": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Cerulean Cave B1F - Hidden Item Northeast Rocks": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Power Plant - Hidden Item Central Dead End": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Power Plant - Hidden Item Before Zapdos": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Seafoam Islands B2F - Hidden Item Rock": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Seafoam Islands B4F - Hidden Item Corner Island": lambda state: state.pokemon_rb_can_get_hidden_items(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( + player), + "Route 23 - Hidden Item East Tree After Water": lambda state: state.pokemon_rb_can_get_hidden_items( + player), + "Route 23 - Hidden Item On Island": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Victory Road 2F - Hidden Item Rock Before Moltres": lambda state: state.pokemon_rb_can_get_hidden_items( + player), + "Victory Road 2F - Hidden Item Rock In Final Room": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Viridian City - Hidden Item Cuttable Tree": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Route 11 - Hidden Item Isolated Tree Near Gate": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Route 12 - Hidden Item Tree Near Gate": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Route 17 - Hidden Item In Grass": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Route 17 - Hidden Item Near Northernmost Sign": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Route 17 - Hidden Item East Center": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Route 17 - Hidden Item West Center": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Route 17 - Hidden Item Before Final Bridge": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Underground Tunnel North-South - Hidden Item Near Northern Stairs": lambda + state: state.pokemon_rb_can_get_hidden_items(player), + "Underground Tunnel North-South - Hidden Item Near Southern Stairs": lambda + state: state.pokemon_rb_can_get_hidden_items(player), + "Underground Tunnel West-East - Hidden Item West": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Underground Tunnel West-East - Hidden Item East": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Celadon City - Hidden Item Dead End Near Cuttable Tree": lambda state: state.pokemon_rb_can_get_hidden_items( + player), + "Route 25 - Hidden Item Northeast Of Grass": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Mt Moon B2F - Hidden Item Lone Rock": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Seafoam Islands B3F - Hidden Item Rock": lambda state: state.pokemon_rb_can_get_hidden_items(player), + "Vermilion City - Hidden Item In Water Near Fan Club": lambda state: state.pokemon_rb_can_get_hidden_items( + player), + "Cerulean City - Hidden Item Gym Badge Guy's Backyard": lambda state: state.pokemon_rb_can_get_hidden_items( + player), + "Route 4 - Hidden Item Plateau East Of Mt Moon": lambda state: state.pokemon_rb_can_get_hidden_items(player), + } + for loc, rule in access_rules.items(): + add_rule(world.get_location(loc, player), rule) + if world.randomize_hidden_items[player].value != 0: + for loc, rule in hidden_item_access_rules.items(): + add_rule(world.get_location(loc, player), rule) diff --git a/worlds/pokemon_rb/text.py b/worlds/pokemon_rb/text.py new file mode 100644 index 00000000..e15623d4 --- /dev/null +++ b/worlds/pokemon_rb/text.py @@ -0,0 +1,147 @@ +special_chars = { + "PKMN": 0x4A, + "'d": 0xBB, + "'l": 0xBC, + "'t": 0xBE, + "'v": 0xBF, + "PK": 0xE1, + "MN": 0xE2, + "'r": 0xE4, + "'m": 0xE5, + "MALE": 0xEF, + "FEMALE": 0xF5, +} + +char_map = { + "@": 0x50, # String terminator + "#": 0x54, # Poké + "‘": 0x70, + "’": 0x71, + "“": 0x72, + "”": 0x73, + "·": 0x74, + "…": 0x75, + " ": 0x7F, + "A": 0x80, + "B": 0x81, + "C": 0x82, + "D": 0x83, + "E": 0x84, + "F": 0x85, + "G": 0x86, + "H": 0x87, + "I": 0x88, + "J": 0x89, + "K": 0x8A, + "L": 0x8B, + "M": 0x8C, + "N": 0x8D, + "O": 0x8E, + "P": 0x8F, + "Q": 0x90, + "R": 0x91, + "S": 0x92, + "T": 0x93, + "U": 0x94, + "V": 0x95, + "W": 0x96, + "X": 0x97, + "Y": 0x98, + "Z": 0x99, + "(": 0x9A, + ")": 0x9B, + ":": 0x9C, + ";": 0x9D, + "[": 0x9E, + "]": 0x9F, + "a": 0xA0, + "b": 0xA1, + "c": 0xA2, + "d": 0xA3, + "e": 0xA4, + "f": 0xA5, + "g": 0xA6, + "h": 0xA7, + "i": 0xA8, + "j": 0xA9, + "k": 0xAA, + "l": 0xAB, + "m": 0xAC, + "n": 0xAD, + "o": 0xAE, + "p": 0xAF, + "q": 0xB0, + "r": 0xB1, + "s": 0xB2, + "t": 0xB3, + "u": 0xB4, + "v": 0xB5, + "w": 0xB6, + "x": 0xB7, + "y": 0xB8, + "z": 0xB9, + "é": 0xBA, + "'": 0xE0, + "-": 0xE3, + "?": 0xE6, + "!": 0xE7, + ".": 0xE8, + "♂": 0xEF, + "¥": 0xF0, + "$": 0xF0, + "×": 0xF1, + "/": 0xF3, + ",": 0xF4, + "♀": 0xF5, + "0": 0xF6, + "1": 0xF7, + "2": 0xF8, + "3": 0xF9, + "4": 0xFA, + "5": 0xFB, + "6": 0xFC, + "7": 0xFD, + "8": 0xFE, + "9": 0xFF, +} + +unsafe_chars = ["@", "#", "PKMN"] + + +def encode_text(text: str, length: int=0, whitespace=False, force=False, safety=False): + encoded_text = bytearray() + spec_char = "" + special = False + for char in text: + if char == ">": + if spec_char in unsafe_chars and safety: + raise KeyError(f"Disallowed Pokemon text special character '<{spec_char}>'") + try: + encoded_text.append(special_chars[spec_char]) + except KeyError: + if force: + encoded_text.append(char_map[" "]) + else: + raise KeyError(f"Invalid Pokemon text special character '<{spec_char}>'") + spec_char = "" + special = False + elif char == "<": + spec_char = "" + special = True + elif special is True: + spec_char += char + else: + if char in unsafe_chars and safety: + raise KeyError(f"Disallowed Pokemon text character '{char}'") + try: + encoded_text.append(char_map[char]) + except KeyError: + if force: + encoded_text.append(char_map[" "]) + else: + raise KeyError(f"Invalid Pokemon text character '{char}'") + if length > 0: + encoded_text = encoded_text[:length] + while whitespace and len(encoded_text) < length: + encoded_text.append(char_map[" " if whitespace is True else whitespace]) + return encoded_text