""" Pulls data from JSON files in worlds/pokemon_emerald/data/ into classes. This also includes marrying automatically extracted data with manually defined data (like location labels or usable pokemon species), some cleanup and sorting, and Warp methods. """ from dataclasses import dataclass import copy from enum import IntEnum import orjson from typing import Dict, List, NamedTuple, Optional, Set, FrozenSet, Tuple, Any, Union import pkgutil import pkg_resources from BaseClasses import ItemClassification BASE_OFFSET = 3860000 class Warp: """ Represents warp events in the game like doorways or warp pads """ is_one_way: bool source_map: str source_ids: List[int] dest_map: str dest_ids: List[int] parent_region: Optional[str] def __init__(self, encoded_string: Optional[str] = None, parent_region: Optional[str] = None) -> None: if encoded_string is not None: decoded_warp = Warp.decode(encoded_string) self.is_one_way = decoded_warp.is_one_way self.source_map = decoded_warp.source_map self.source_ids = decoded_warp.source_ids self.dest_map = decoded_warp.dest_map self.dest_ids = decoded_warp.dest_ids self.parent_region = parent_region def encode(self) -> str: """ Returns a string encoding of this warp """ source_ids_string = "" for source_id in self.source_ids: source_ids_string += str(source_id) + "," source_ids_string = source_ids_string[:-1] # Remove last "," dest_ids_string = "" for dest_id in self.dest_ids: dest_ids_string += str(dest_id) + "," dest_ids_string = dest_ids_string[:-1] # Remove last "," return f"{self.source_map}:{source_ids_string}/{self.dest_map}:{dest_ids_string}{'!' if self.is_one_way else ''}" def connects_to(self, other: 'Warp') -> bool: """ Returns true if this warp sends the player to `other` """ return self.dest_map == other.source_map and set(self.dest_ids) <= set(other.source_ids) @staticmethod def decode(encoded_string: str) -> 'Warp': """ Create a Warp object from an encoded string """ warp = Warp() warp.is_one_way = encoded_string.endswith("!") if warp.is_one_way: encoded_string = encoded_string[:-1] warp_source, warp_dest = encoded_string.split("/") warp_source_map, warp_source_indices = warp_source.split(":") warp_dest_map, warp_dest_indices = warp_dest.split(":") warp.source_map = warp_source_map warp.dest_map = warp_dest_map warp.source_ids = [int(index) for index in warp_source_indices.split(",")] warp.dest_ids = [int(index) for index in warp_dest_indices.split(",")] return warp class ItemData(NamedTuple): label: str item_id: int classification: ItemClassification tags: FrozenSet[str] class LocationData(NamedTuple): name: str label: str parent_region: str default_item: int rom_address: int flag: int tags: FrozenSet[str] class EventData(NamedTuple): name: str parent_region: str class RegionData: name: str exits: List[str] warps: List[str] locations: List[str] events: List[EventData] def __init__(self, name: str): self.name = name self.exits = [] self.warps = [] self.locations = [] self.events = [] class BaseStats(NamedTuple): hp: int attack: int defense: int speed: int special_attack: int special_defense: int class LearnsetMove(NamedTuple): level: int move_id: int class EvolutionMethodEnum(IntEnum): LEVEL = 0 LEVEL_ATK_LT_DEF = 1 LEVEL_ATK_EQ_DEF = 2 LEVEL_ATK_GT_DEF = 3 LEVEL_SILCOON = 4 LEVEL_CASCOON = 5 LEVEL_NINJASK = 6 LEVEL_SHEDINJA = 7 ITEM = 8 FRIENDSHIP = 9 FRIENDSHIP_DAY = 10 FRIENDSHIP_NIGHT = 11 def _str_to_evolution_method(string: str) -> EvolutionMethodEnum: if string == "LEVEL": return EvolutionMethodEnum.LEVEL if string == "LEVEL_ATK_LT_DEF": return EvolutionMethodEnum.LEVEL_ATK_LT_DEF if string == "LEVEL_ATK_EQ_DEF": return EvolutionMethodEnum.LEVEL_ATK_EQ_DEF if string == "LEVEL_ATK_GT_DEF": return EvolutionMethodEnum.LEVEL_ATK_GT_DEF if string == "LEVEL_SILCOON": return EvolutionMethodEnum.LEVEL_SILCOON if string == "LEVEL_CASCOON": return EvolutionMethodEnum.LEVEL_CASCOON if string == "LEVEL_NINJASK": return EvolutionMethodEnum.LEVEL_NINJASK if string == "LEVEL_SHEDINJA": return EvolutionMethodEnum.LEVEL_SHEDINJA if string == "FRIENDSHIP": return EvolutionMethodEnum.FRIENDSHIP if string == "FRIENDSHIP_DAY": return EvolutionMethodEnum.FRIENDSHIP_DAY if string == "FRIENDSHIP_NIGHT": return EvolutionMethodEnum.FRIENDSHIP_NIGHT class EvolutionData(NamedTuple): method: EvolutionMethodEnum param: int species_id: int class StaticEncounterData(NamedTuple): species_id: int rom_address: int @dataclass class SpeciesData: name: str label: str species_id: int base_stats: BaseStats types: Tuple[int, int] abilities: Tuple[int, int] evolutions: List[EvolutionData] pre_evolution: Optional[int] catch_rate: int learnset: List[LearnsetMove] tm_hm_compatibility: int learnset_rom_address: int rom_address: int class AbilityData(NamedTuple): ability_id: int label: str class EncounterTableData(NamedTuple): slots: List[int] rom_address: int @dataclass class MapData: name: str land_encounters: Optional[EncounterTableData] water_encounters: Optional[EncounterTableData] fishing_encounters: Optional[EncounterTableData] class TrainerPokemonDataTypeEnum(IntEnum): NO_ITEM_DEFAULT_MOVES = 0 ITEM_DEFAULT_MOVES = 1 NO_ITEM_CUSTOM_MOVES = 2 ITEM_CUSTOM_MOVES = 3 def _str_to_pokemon_data_type(string: str) -> TrainerPokemonDataTypeEnum: if string == "NO_ITEM_DEFAULT_MOVES": return TrainerPokemonDataTypeEnum.NO_ITEM_DEFAULT_MOVES if string == "ITEM_DEFAULT_MOVES": return TrainerPokemonDataTypeEnum.ITEM_DEFAULT_MOVES if string == "NO_ITEM_CUSTOM_MOVES": return TrainerPokemonDataTypeEnum.NO_ITEM_CUSTOM_MOVES if string == "ITEM_CUSTOM_MOVES": return TrainerPokemonDataTypeEnum.ITEM_CUSTOM_MOVES @dataclass class TrainerPokemonData: species_id: int level: int moves: Optional[Tuple[int, int, int, int]] @dataclass class TrainerPartyData: pokemon: List[TrainerPokemonData] pokemon_data_type: TrainerPokemonDataTypeEnum rom_address: int @dataclass class TrainerData: trainer_id: int party: TrainerPartyData rom_address: int battle_script_rom_address: int class PokemonEmeraldData: starters: Tuple[int, int, int] constants: Dict[str, int] ram_addresses: Dict[str, int] rom_addresses: Dict[str, int] regions: Dict[str, RegionData] locations: Dict[str, LocationData] items: Dict[int, ItemData] species: List[Optional[SpeciesData]] static_encounters: List[StaticEncounterData] tmhm_moves: List[int] abilities: List[AbilityData] maps: List[MapData] warps: Dict[str, Warp] warp_map: Dict[str, Optional[str]] trainers: List[TrainerData] def __init__(self) -> None: self.starters = (277, 280, 283) self.constants = {} self.ram_addresses = {} self.rom_addresses = {} self.regions = {} self.locations = {} self.items = {} self.species = [] self.static_encounters = [] self.tmhm_moves = [] self.abilities = [] self.maps = [] self.warps = {} self.warp_map = {} self.trainers = [] def load_json_data(data_name: str) -> Union[List[Any], Dict[str, Any]]: return orjson.loads(pkgutil.get_data(__name__, "data/" + data_name).decode('utf-8-sig')) data = PokemonEmeraldData() def create_data_copy() -> PokemonEmeraldData: new_copy = PokemonEmeraldData() new_copy.species = copy.deepcopy(data.species) new_copy.tmhm_moves = copy.deepcopy(data.tmhm_moves) new_copy.maps = copy.deepcopy(data.maps) new_copy.static_encounters = copy.deepcopy(data.static_encounters) new_copy.trainers = copy.deepcopy(data.trainers) def _init() -> None: extracted_data: Dict[str, Any] = load_json_data("extracted_data.json") data.constants = extracted_data["constants"] data.ram_addresses = extracted_data["misc_ram_addresses"] data.rom_addresses = extracted_data["misc_rom_addresses"] location_attributes_json = load_json_data("locations.json") # Load/merge region json files region_json_list = [] for file in pkg_resources.resource_listdir(__name__, "data/regions"): if not pkg_resources.resource_isdir(__name__, "data/regions/" + file): region_json_list.append(load_json_data("regions/" + file)) regions_json = {} for region_subset in region_json_list: for region_name, region_json in region_subset.items(): if region_name in regions_json: raise AssertionError("Region [{region_name}] was defined multiple times") regions_json[region_name] = region_json # Create region data claimed_locations: Set[str] = set() claimed_warps: Set[str] = set() data.regions = {} for region_name, region_json in regions_json.items(): new_region = RegionData(region_name) # Locations for location_name in region_json["locations"]: if location_name in claimed_locations: raise AssertionError(f"Location [{location_name}] was claimed by multiple regions") location_json = extracted_data["locations"][location_name] new_location = LocationData( location_name, location_attributes_json[location_name]["label"], region_name, location_json["default_item"], location_json["rom_address"], location_json["flag"], frozenset(location_attributes_json[location_name]["tags"]) ) new_region.locations.append(location_name) data.locations[location_name] = new_location claimed_locations.add(location_name) new_region.locations.sort() # Events for event in region_json["events"]: new_region.events.append(EventData(event, region_name)) # Exits for region_exit in region_json["exits"]: new_region.exits.append(region_exit) # Warps for encoded_warp in region_json["warps"]: if encoded_warp in claimed_warps: raise AssertionError(f"Warp [{encoded_warp}] was claimed by multiple regions") new_region.warps.append(encoded_warp) data.warps[encoded_warp] = Warp(encoded_warp, region_name) claimed_warps.add(encoded_warp) new_region.warps.sort() data.regions[region_name] = new_region # Create item data items_json = load_json_data("items.json") data.items = {} for item_constant_name, attributes in items_json.items(): item_classification = None if attributes["classification"] == "PROGRESSION": item_classification = ItemClassification.progression elif attributes["classification"] == "USEFUL": item_classification = ItemClassification.useful elif attributes["classification"] == "FILLER": item_classification = ItemClassification.filler elif attributes["classification"] == "TRAP": item_classification = ItemClassification.trap else: raise ValueError(f"Unknown classification {attributes['classification']} for item {item_constant_name}") data.items[data.constants[item_constant_name]] = ItemData( attributes["label"], data.constants[item_constant_name], item_classification, frozenset(attributes["tags"]) ) # Create species data # Excludes extras like copies of Unown and special species values like SPECIES_EGG. all_species: List[Tuple[str, str]] = [ ("SPECIES_BULBASAUR", "Bulbasaur"), ("SPECIES_IVYSAUR", "Ivysaur"), ("SPECIES_VENUSAUR", "Venusaur"), ("SPECIES_CHARMANDER", "Charmander"), ("SPECIES_CHARMELEON", "Charmeleon"), ("SPECIES_CHARIZARD", "Charizard"), ("SPECIES_SQUIRTLE", "Squirtle"), ("SPECIES_WARTORTLE", "Wartortle"), ("SPECIES_BLASTOISE", "Blastoise"), ("SPECIES_CATERPIE", "Caterpie"), ("SPECIES_METAPOD", "Metapod"), ("SPECIES_BUTTERFREE", "Butterfree"), ("SPECIES_WEEDLE", "Weedle"), ("SPECIES_KAKUNA", "Kakuna"), ("SPECIES_BEEDRILL", "Beedrill"), ("SPECIES_PIDGEY", "Pidgey"), ("SPECIES_PIDGEOTTO", "Pidgeotto"), ("SPECIES_PIDGEOT", "Pidgeot"), ("SPECIES_RATTATA", "Rattata"), ("SPECIES_RATICATE", "Raticate"), ("SPECIES_SPEAROW", "Spearow"), ("SPECIES_FEAROW", "Fearow"), ("SPECIES_EKANS", "Ekans"), ("SPECIES_ARBOK", "Arbok"), ("SPECIES_PIKACHU", "Pikachu"), ("SPECIES_RAICHU", "Raichu"), ("SPECIES_SANDSHREW", "Sandshrew"), ("SPECIES_SANDSLASH", "Sandslash"), ("SPECIES_NIDORAN_F", "Nidoran Female"), ("SPECIES_NIDORINA", "Nidorina"), ("SPECIES_NIDOQUEEN", "Nidoqueen"), ("SPECIES_NIDORAN_M", "Nidoran Male"), ("SPECIES_NIDORINO", "Nidorino"), ("SPECIES_NIDOKING", "Nidoking"), ("SPECIES_CLEFAIRY", "Clefairy"), ("SPECIES_CLEFABLE", "Clefable"), ("SPECIES_VULPIX", "Vulpix"), ("SPECIES_NINETALES", "Ninetales"), ("SPECIES_JIGGLYPUFF", "Jigglypuff"), ("SPECIES_WIGGLYTUFF", "Wigglytuff"), ("SPECIES_ZUBAT", "Zubat"), ("SPECIES_GOLBAT", "Golbat"), ("SPECIES_ODDISH", "Oddish"), ("SPECIES_GLOOM", "Gloom"), ("SPECIES_VILEPLUME", "Vileplume"), ("SPECIES_PARAS", "Paras"), ("SPECIES_PARASECT", "Parasect"), ("SPECIES_VENONAT", "Venonat"), ("SPECIES_VENOMOTH", "Venomoth"), ("SPECIES_DIGLETT", "Diglett"), ("SPECIES_DUGTRIO", "Dugtrio"), ("SPECIES_MEOWTH", "Meowth"), ("SPECIES_PERSIAN", "Persian"), ("SPECIES_PSYDUCK", "Psyduck"), ("SPECIES_GOLDUCK", "Golduck"), ("SPECIES_MANKEY", "Mankey"), ("SPECIES_PRIMEAPE", "Primeape"), ("SPECIES_GROWLITHE", "Growlithe"), ("SPECIES_ARCANINE", "Arcanine"), ("SPECIES_POLIWAG", "Poliwag"), ("SPECIES_POLIWHIRL", "Poliwhirl"), ("SPECIES_POLIWRATH", "Poliwrath"), ("SPECIES_ABRA", "Abra"), ("SPECIES_KADABRA", "Kadabra"), ("SPECIES_ALAKAZAM", "Alakazam"), ("SPECIES_MACHOP", "Machop"), ("SPECIES_MACHOKE", "Machoke"), ("SPECIES_MACHAMP", "Machamp"), ("SPECIES_BELLSPROUT", "Bellsprout"), ("SPECIES_WEEPINBELL", "Weepinbell"), ("SPECIES_VICTREEBEL", "Victreebel"), ("SPECIES_TENTACOOL", "Tentacool"), ("SPECIES_TENTACRUEL", "Tentacruel"), ("SPECIES_GEODUDE", "Geodude"), ("SPECIES_GRAVELER", "Graveler"), ("SPECIES_GOLEM", "Golem"), ("SPECIES_PONYTA", "Ponyta"), ("SPECIES_RAPIDASH", "Rapidash"), ("SPECIES_SLOWPOKE", "Slowpoke"), ("SPECIES_SLOWBRO", "Slowbro"), ("SPECIES_MAGNEMITE", "Magnemite"), ("SPECIES_MAGNETON", "Magneton"), ("SPECIES_FARFETCHD", "Farfetch'd"), ("SPECIES_DODUO", "Doduo"), ("SPECIES_DODRIO", "Dodrio"), ("SPECIES_SEEL", "Seel"), ("SPECIES_DEWGONG", "Dewgong"), ("SPECIES_GRIMER", "Grimer"), ("SPECIES_MUK", "Muk"), ("SPECIES_SHELLDER", "Shellder"), ("SPECIES_CLOYSTER", "Cloyster"), ("SPECIES_GASTLY", "Gastly"), ("SPECIES_HAUNTER", "Haunter"), ("SPECIES_GENGAR", "Gengar"), ("SPECIES_ONIX", "Onix"), ("SPECIES_DROWZEE", "Drowzee"), ("SPECIES_HYPNO", "Hypno"), ("SPECIES_KRABBY", "Krabby"), ("SPECIES_KINGLER", "Kingler"), ("SPECIES_VOLTORB", "Voltorb"), ("SPECIES_ELECTRODE", "Electrode"), ("SPECIES_EXEGGCUTE", "Exeggcute"), ("SPECIES_EXEGGUTOR", "Exeggutor"), ("SPECIES_CUBONE", "Cubone"), ("SPECIES_MAROWAK", "Marowak"), ("SPECIES_HITMONLEE", "Hitmonlee"), ("SPECIES_HITMONCHAN", "Hitmonchan"), ("SPECIES_LICKITUNG", "Lickitung"), ("SPECIES_KOFFING", "Koffing"), ("SPECIES_WEEZING", "Weezing"), ("SPECIES_RHYHORN", "Rhyhorn"), ("SPECIES_RHYDON", "Rhydon"), ("SPECIES_CHANSEY", "Chansey"), ("SPECIES_TANGELA", "Tangela"), ("SPECIES_KANGASKHAN", "Kangaskhan"), ("SPECIES_HORSEA", "Horsea"), ("SPECIES_SEADRA", "Seadra"), ("SPECIES_GOLDEEN", "Goldeen"), ("SPECIES_SEAKING", "Seaking"), ("SPECIES_STARYU", "Staryu"), ("SPECIES_STARMIE", "Starmie"), ("SPECIES_MR_MIME", "Mr. Mime"), ("SPECIES_SCYTHER", "Scyther"), ("SPECIES_JYNX", "Jynx"), ("SPECIES_ELECTABUZZ", "Electabuzz"), ("SPECIES_MAGMAR", "Magmar"), ("SPECIES_PINSIR", "Pinsir"), ("SPECIES_TAUROS", "Tauros"), ("SPECIES_MAGIKARP", "Magikarp"), ("SPECIES_GYARADOS", "Gyarados"), ("SPECIES_LAPRAS", "Lapras"), ("SPECIES_DITTO", "Ditto"), ("SPECIES_EEVEE", "Eevee"), ("SPECIES_VAPOREON", "Vaporeon"), ("SPECIES_JOLTEON", "Jolteon"), ("SPECIES_FLAREON", "Flareon"), ("SPECIES_PORYGON", "Porygon"), ("SPECIES_OMANYTE", "Omanyte"), ("SPECIES_OMASTAR", "Omastar"), ("SPECIES_KABUTO", "Kabuto"), ("SPECIES_KABUTOPS", "Kabutops"), ("SPECIES_AERODACTYL", "Aerodactyl"), ("SPECIES_SNORLAX", "Snorlax"), ("SPECIES_ARTICUNO", "Articuno"), ("SPECIES_ZAPDOS", "Zapdos"), ("SPECIES_MOLTRES", "Moltres"), ("SPECIES_DRATINI", "Dratini"), ("SPECIES_DRAGONAIR", "Dragonair"), ("SPECIES_DRAGONITE", "Dragonite"), ("SPECIES_MEWTWO", "Mewtwo"), ("SPECIES_MEW", "Mew"), ("SPECIES_CHIKORITA", "Chikorita"), ("SPECIES_BAYLEEF", "Bayleaf"), ("SPECIES_MEGANIUM", "Meganium"), ("SPECIES_CYNDAQUIL", "Cindaquil"), ("SPECIES_QUILAVA", "Quilava"), ("SPECIES_TYPHLOSION", "Typhlosion"), ("SPECIES_TOTODILE", "Totodile"), ("SPECIES_CROCONAW", "Croconaw"), ("SPECIES_FERALIGATR", "Feraligatr"), ("SPECIES_SENTRET", "Sentret"), ("SPECIES_FURRET", "Furret"), ("SPECIES_HOOTHOOT", "Hoothoot"), ("SPECIES_NOCTOWL", "Noctowl"), ("SPECIES_LEDYBA", "Ledyba"), ("SPECIES_LEDIAN", "Ledian"), ("SPECIES_SPINARAK", "Spinarak"), ("SPECIES_ARIADOS", "Ariados"), ("SPECIES_CROBAT", "Crobat"), ("SPECIES_CHINCHOU", "Chinchou"), ("SPECIES_LANTURN", "Lanturn"), ("SPECIES_PICHU", "Pichu"), ("SPECIES_CLEFFA", "Cleffa"), ("SPECIES_IGGLYBUFF", "Igglybuff"), ("SPECIES_TOGEPI", "Togepi"), ("SPECIES_TOGETIC", "Togetic"), ("SPECIES_NATU", "Natu"), ("SPECIES_XATU", "Xatu"), ("SPECIES_MAREEP", "Mareep"), ("SPECIES_FLAAFFY", "Flaafy"), ("SPECIES_AMPHAROS", "Ampharos"), ("SPECIES_BELLOSSOM", "Bellossom"), ("SPECIES_MARILL", "Marill"), ("SPECIES_AZUMARILL", "Azumarill"), ("SPECIES_SUDOWOODO", "Sudowoodo"), ("SPECIES_POLITOED", "Politoed"), ("SPECIES_HOPPIP", "Hoppip"), ("SPECIES_SKIPLOOM", "Skiploom"), ("SPECIES_JUMPLUFF", "Jumpluff"), ("SPECIES_AIPOM", "Aipom"), ("SPECIES_SUNKERN", "Sunkern"), ("SPECIES_SUNFLORA", "Sunflora"), ("SPECIES_YANMA", "Yanma"), ("SPECIES_WOOPER", "Wooper"), ("SPECIES_QUAGSIRE", "Quagsire"), ("SPECIES_ESPEON", "Espeon"), ("SPECIES_UMBREON", "Umbreon"), ("SPECIES_MURKROW", "Murkrow"), ("SPECIES_SLOWKING", "Slowking"), ("SPECIES_MISDREAVUS", "Misdreavus"), ("SPECIES_UNOWN", "Unown"), ("SPECIES_WOBBUFFET", "Wobbuffet"), ("SPECIES_GIRAFARIG", "Girafarig"), ("SPECIES_PINECO", "Pineco"), ("SPECIES_FORRETRESS", "Forretress"), ("SPECIES_DUNSPARCE", "Dunsparce"), ("SPECIES_GLIGAR", "Gligar"), ("SPECIES_STEELIX", "Steelix"), ("SPECIES_SNUBBULL", "Snubbull"), ("SPECIES_GRANBULL", "Granbull"), ("SPECIES_QWILFISH", "Qwilfish"), ("SPECIES_SCIZOR", "Scizor"), ("SPECIES_SHUCKLE", "Shuckle"), ("SPECIES_HERACROSS", "Heracross"), ("SPECIES_SNEASEL", "Sneasel"), ("SPECIES_TEDDIURSA", "Teddiursa"), ("SPECIES_URSARING", "Ursaring"), ("SPECIES_SLUGMA", "Slugma"), ("SPECIES_MAGCARGO", "Magcargo"), ("SPECIES_SWINUB", "Swinub"), ("SPECIES_PILOSWINE", "Piloswine"), ("SPECIES_CORSOLA", "Corsola"), ("SPECIES_REMORAID", "Remoraid"), ("SPECIES_OCTILLERY", "Octillery"), ("SPECIES_DELIBIRD", "Delibird"), ("SPECIES_MANTINE", "Mantine"), ("SPECIES_SKARMORY", "Skarmory"), ("SPECIES_HOUNDOUR", "Houndour"), ("SPECIES_HOUNDOOM", "Houndoom"), ("SPECIES_KINGDRA", "Kingdra"), ("SPECIES_PHANPY", "Phanpy"), ("SPECIES_DONPHAN", "Donphan"), ("SPECIES_PORYGON2", "Porygon2"), ("SPECIES_STANTLER", "Stantler"), ("SPECIES_SMEARGLE", "Smeargle"), ("SPECIES_TYROGUE", "Tyrogue"), ("SPECIES_HITMONTOP", "Hitmontop"), ("SPECIES_SMOOCHUM", "Smoochum"), ("SPECIES_ELEKID", "Elekid"), ("SPECIES_MAGBY", "Magby"), ("SPECIES_MILTANK", "Miltank"), ("SPECIES_BLISSEY", "Blissey"), ("SPECIES_RAIKOU", "Raikou"), ("SPECIES_ENTEI", "Entei"), ("SPECIES_SUICUNE", "Suicune"), ("SPECIES_LARVITAR", "Larvitar"), ("SPECIES_PUPITAR", "Pupitar"), ("SPECIES_TYRANITAR", "Tyranitar"), ("SPECIES_LUGIA", "Lugia"), ("SPECIES_HO_OH", "Ho-oh"), ("SPECIES_CELEBI", "Celebi"), ("SPECIES_TREECKO", "Treecko"), ("SPECIES_GROVYLE", "Grovyle"), ("SPECIES_SCEPTILE", "Sceptile"), ("SPECIES_TORCHIC", "Torchic"), ("SPECIES_COMBUSKEN", "Combusken"), ("SPECIES_BLAZIKEN", "Blaziken"), ("SPECIES_MUDKIP", "Mudkip"), ("SPECIES_MARSHTOMP", "Marshtomp"), ("SPECIES_SWAMPERT", "Swampert"), ("SPECIES_POOCHYENA", "Poochyena"), ("SPECIES_MIGHTYENA", "Mightyena"), ("SPECIES_ZIGZAGOON", "Zigzagoon"), ("SPECIES_LINOONE", "Linoon"), ("SPECIES_WURMPLE", "Wurmple"), ("SPECIES_SILCOON", "Silcoon"), ("SPECIES_BEAUTIFLY", "Beautifly"), ("SPECIES_CASCOON", "Cascoon"), ("SPECIES_DUSTOX", "Dustox"), ("SPECIES_LOTAD", "Lotad"), ("SPECIES_LOMBRE", "Lombre"), ("SPECIES_LUDICOLO", "Ludicolo"), ("SPECIES_SEEDOT", "Seedot"), ("SPECIES_NUZLEAF", "Nuzleaf"), ("SPECIES_SHIFTRY", "Shiftry"), ("SPECIES_NINCADA", "Nincada"), ("SPECIES_NINJASK", "Ninjask"), ("SPECIES_SHEDINJA", "Shedinja"), ("SPECIES_TAILLOW", "Taillow"), ("SPECIES_SWELLOW", "Swellow"), ("SPECIES_SHROOMISH", "Shroomish"), ("SPECIES_BRELOOM", "Breloom"), ("SPECIES_SPINDA", "Spinda"), ("SPECIES_WINGULL", "Wingull"), ("SPECIES_PELIPPER", "Pelipper"), ("SPECIES_SURSKIT", "Surskit"), ("SPECIES_MASQUERAIN", "Masquerain"), ("SPECIES_WAILMER", "Wailmer"), ("SPECIES_WAILORD", "Wailord"), ("SPECIES_SKITTY", "Skitty"), ("SPECIES_DELCATTY", "Delcatty"), ("SPECIES_KECLEON", "Kecleon"), ("SPECIES_BALTOY", "Baltoy"), ("SPECIES_CLAYDOL", "Claydol"), ("SPECIES_NOSEPASS", "Nosepass"), ("SPECIES_TORKOAL", "Torkoal"), ("SPECIES_SABLEYE", "Sableye"), ("SPECIES_BARBOACH", "Barboach"), ("SPECIES_WHISCASH", "Whiscash"), ("SPECIES_LUVDISC", "Luvdisc"), ("SPECIES_CORPHISH", "Corphish"), ("SPECIES_CRAWDAUNT", "Crawdaunt"), ("SPECIES_FEEBAS", "Feebas"), ("SPECIES_MILOTIC", "Milotic"), ("SPECIES_CARVANHA", "Carvanha"), ("SPECIES_SHARPEDO", "Sharpedo"), ("SPECIES_TRAPINCH", "Trapinch"), ("SPECIES_VIBRAVA", "Vibrava"), ("SPECIES_FLYGON", "Flygon"), ("SPECIES_MAKUHITA", "Makuhita"), ("SPECIES_HARIYAMA", "Hariyama"), ("SPECIES_ELECTRIKE", "Electrike"), ("SPECIES_MANECTRIC", "Manectric"), ("SPECIES_NUMEL", "Numel"), ("SPECIES_CAMERUPT", "Camerupt"), ("SPECIES_SPHEAL", "Spheal"), ("SPECIES_SEALEO", "Sealeo"), ("SPECIES_WALREIN", "Walrein"), ("SPECIES_CACNEA", "Cacnea"), ("SPECIES_CACTURNE", "Cacturne"), ("SPECIES_SNORUNT", "Snorunt"), ("SPECIES_GLALIE", "Glalie"), ("SPECIES_LUNATONE", "Lunatone"), ("SPECIES_SOLROCK", "Solrock"), ("SPECIES_AZURILL", "Azurill"), ("SPECIES_SPOINK", "Spoink"), ("SPECIES_GRUMPIG", "Grumpig"), ("SPECIES_PLUSLE", "Plusle"), ("SPECIES_MINUN", "Minun"), ("SPECIES_MAWILE", "Mawile"), ("SPECIES_MEDITITE", "Meditite"), ("SPECIES_MEDICHAM", "Medicham"), ("SPECIES_SWABLU", "Swablu"), ("SPECIES_ALTARIA", "Altaria"), ("SPECIES_WYNAUT", "Wynaut"), ("SPECIES_DUSKULL", "Duskull"), ("SPECIES_DUSCLOPS", "Dusclops"), ("SPECIES_ROSELIA", "Roselia"), ("SPECIES_SLAKOTH", "Slakoth"), ("SPECIES_VIGOROTH", "Vigoroth"), ("SPECIES_SLAKING", "Slaking"), ("SPECIES_GULPIN", "Gulpin"), ("SPECIES_SWALOT", "Swalot"), ("SPECIES_TROPIUS", "Tropius"), ("SPECIES_WHISMUR", "Whismur"), ("SPECIES_LOUDRED", "Loudred"), ("SPECIES_EXPLOUD", "Exploud"), ("SPECIES_CLAMPERL", "Clamperl"), ("SPECIES_HUNTAIL", "Huntail"), ("SPECIES_GOREBYSS", "Gorebyss"), ("SPECIES_ABSOL", "Absol"), ("SPECIES_SHUPPET", "Shuppet"), ("SPECIES_BANETTE", "Banette"), ("SPECIES_SEVIPER", "Seviper"), ("SPECIES_ZANGOOSE", "Zangoose"), ("SPECIES_RELICANTH", "Relicanth"), ("SPECIES_ARON", "Aron"), ("SPECIES_LAIRON", "Lairon"), ("SPECIES_AGGRON", "Aggron"), ("SPECIES_CASTFORM", "Castform"), ("SPECIES_VOLBEAT", "Volbeat"), ("SPECIES_ILLUMISE", "Illumise"), ("SPECIES_LILEEP", "Lileep"), ("SPECIES_CRADILY", "Cradily"), ("SPECIES_ANORITH", "Anorith"), ("SPECIES_ARMALDO", "Armaldo"), ("SPECIES_RALTS", "Ralts"), ("SPECIES_KIRLIA", "Kirlia"), ("SPECIES_GARDEVOIR", "Gardevoir"), ("SPECIES_BAGON", "Bagon"), ("SPECIES_SHELGON", "Shelgon"), ("SPECIES_SALAMENCE", "Salamence"), ("SPECIES_BELDUM", "Beldum"), ("SPECIES_METANG", "Metang"), ("SPECIES_METAGROSS", "Metagross"), ("SPECIES_REGIROCK", "Regirock"), ("SPECIES_REGICE", "Regice"), ("SPECIES_REGISTEEL", "Registeel"), ("SPECIES_KYOGRE", "Kyogre"), ("SPECIES_GROUDON", "Groudon"), ("SPECIES_RAYQUAZA", "Rayquaza"), ("SPECIES_LATIAS", "Latias"), ("SPECIES_LATIOS", "Latios"), ("SPECIES_JIRACHI", "Jirachi"), ("SPECIES_DEOXYS", "Deoxys"), ("SPECIES_CHIMECHO", "Chimecho") ] species_list: List[SpeciesData] = [] max_species_id = 0 for species_name, species_label in all_species: species_id = data.constants[species_name] max_species_id = max(species_id, max_species_id) species_data = extracted_data["species"][species_id] learnset = [LearnsetMove(item["level"], item["move_id"]) for item in species_data["learnset"]["moves"]] species_list.append(SpeciesData( species_name, species_label, species_id, BaseStats( species_data["base_stats"][0], species_data["base_stats"][1], species_data["base_stats"][2], species_data["base_stats"][3], species_data["base_stats"][4], species_data["base_stats"][5] ), (species_data["types"][0], species_data["types"][1]), (species_data["abilities"][0], species_data["abilities"][1]), [EvolutionData( _str_to_evolution_method(evolution_json["method"]), evolution_json["param"], evolution_json["species"], ) for evolution_json in species_data["evolutions"]], None, species_data["catch_rate"], learnset, int(species_data["tmhm_learnset"], 16), species_data["learnset"]["rom_address"], species_data["rom_address"] )) data.species = [None for i in range(max_species_id + 1)] for species_data in species_list: data.species[species_data.species_id] = species_data for species in data.species: if species is not None: for evolution in species.evolutions: data.species[evolution.species_id].pre_evolution = species.species_id # Create static encounter data for static_encounter_json in extracted_data["static_encounters"]: data.static_encounters.append(StaticEncounterData( static_encounter_json["species"], static_encounter_json["rom_address"] )) # TM moves data.tmhm_moves = extracted_data["tmhm_moves"] # Create ability data data.abilities = [AbilityData(data.constants[ability_data[0]], ability_data[1]) for ability_data in [ ("ABILITY_STENCH", "Stench"), ("ABILITY_DRIZZLE", "Drizzle"), ("ABILITY_SPEED_BOOST", "Speed Boost"), ("ABILITY_BATTLE_ARMOR", "Battle Armor"), ("ABILITY_STURDY", "Sturdy"), ("ABILITY_DAMP", "Damp"), ("ABILITY_LIMBER", "Limber"), ("ABILITY_SAND_VEIL", "Sand Veil"), ("ABILITY_STATIC", "Static"), ("ABILITY_VOLT_ABSORB", "Volt Absorb"), ("ABILITY_WATER_ABSORB", "Water Absorb"), ("ABILITY_OBLIVIOUS", "Oblivious"), ("ABILITY_CLOUD_NINE", "Cloud Nine"), ("ABILITY_COMPOUND_EYES", "Compound Eyes"), ("ABILITY_INSOMNIA", "Insomnia"), ("ABILITY_COLOR_CHANGE", "Color Change"), ("ABILITY_IMMUNITY", "Immunity"), ("ABILITY_FLASH_FIRE", "Flash Fire"), ("ABILITY_SHIELD_DUST", "Shield Dust"), ("ABILITY_OWN_TEMPO", "Own Tempo"), ("ABILITY_SUCTION_CUPS", "Suction Cups"), ("ABILITY_INTIMIDATE", "Intimidate"), ("ABILITY_SHADOW_TAG", "Shadow Tag"), ("ABILITY_ROUGH_SKIN", "Rough Skin"), ("ABILITY_WONDER_GUARD", "Wonder Guard"), ("ABILITY_LEVITATE", "Levitate"), ("ABILITY_EFFECT_SPORE", "Effect Spore"), ("ABILITY_SYNCHRONIZE", "Synchronize"), ("ABILITY_CLEAR_BODY", "Clear Body"), ("ABILITY_NATURAL_CURE", "Natural Cure"), ("ABILITY_LIGHTNING_ROD", "Lightning Rod"), ("ABILITY_SERENE_GRACE", "Serene Grace"), ("ABILITY_SWIFT_SWIM", "Swift Swim"), ("ABILITY_CHLOROPHYLL", "Chlorophyll"), ("ABILITY_ILLUMINATE", "Illuminate"), ("ABILITY_TRACE", "Trace"), ("ABILITY_HUGE_POWER", "Huge Power"), ("ABILITY_POISON_POINT", "Poison Point"), ("ABILITY_INNER_FOCUS", "Inner Focus"), ("ABILITY_MAGMA_ARMOR", "Magma Armor"), ("ABILITY_WATER_VEIL", "Water Veil"), ("ABILITY_MAGNET_PULL", "Magnet Pull"), ("ABILITY_SOUNDPROOF", "Soundproof"), ("ABILITY_RAIN_DISH", "Rain Dish"), ("ABILITY_SAND_STREAM", "Sand Stream"), ("ABILITY_PRESSURE", "Pressure"), ("ABILITY_THICK_FAT", "Thick Fat"), ("ABILITY_EARLY_BIRD", "Early Bird"), ("ABILITY_FLAME_BODY", "Flame Body"), ("ABILITY_RUN_AWAY", "Run Away"), ("ABILITY_KEEN_EYE", "Keen Eye"), ("ABILITY_HYPER_CUTTER", "Hyper Cutter"), ("ABILITY_PICKUP", "Pickup"), ("ABILITY_TRUANT", "Truant"), ("ABILITY_HUSTLE", "Hustle"), ("ABILITY_CUTE_CHARM", "Cute Charm"), ("ABILITY_PLUS", "Plus"), ("ABILITY_MINUS", "Minus"), ("ABILITY_FORECAST", "Forecast"), ("ABILITY_STICKY_HOLD", "Sticky Hold"), ("ABILITY_SHED_SKIN", "Shed Skin"), ("ABILITY_GUTS", "Guts"), ("ABILITY_MARVEL_SCALE", "Marvel Scale"), ("ABILITY_LIQUID_OOZE", "Liquid Ooze"), ("ABILITY_OVERGROW", "Overgrow"), ("ABILITY_BLAZE", "Blaze"), ("ABILITY_TORRENT", "Torrent"), ("ABILITY_SWARM", "Swarm"), ("ABILITY_ROCK_HEAD", "Rock Head"), ("ABILITY_DROUGHT", "Drought"), ("ABILITY_ARENA_TRAP", "Arena Trap"), ("ABILITY_VITAL_SPIRIT", "Vital Spirit"), ("ABILITY_WHITE_SMOKE", "White Smoke"), ("ABILITY_PURE_POWER", "Pure Power"), ("ABILITY_SHELL_ARMOR", "Shell Armor"), ("ABILITY_CACOPHONY", "Cacophony"), ("ABILITY_AIR_LOCK", "Air Lock") ]] # Create map data for map_name, map_json in extracted_data["maps"].items(): land_encounters = None water_encounters = None fishing_encounters = None if map_json["land_encounters"] is not None: land_encounters = EncounterTableData( map_json["land_encounters"]["encounter_slots"], map_json["land_encounters"]["rom_address"] ) if map_json["water_encounters"] is not None: water_encounters = EncounterTableData( map_json["water_encounters"]["encounter_slots"], map_json["water_encounters"]["rom_address"] ) if map_json["fishing_encounters"] is not None: fishing_encounters = EncounterTableData( map_json["fishing_encounters"]["encounter_slots"], map_json["fishing_encounters"]["rom_address"] ) data.maps.append(MapData( map_name, land_encounters, water_encounters, fishing_encounters )) data.maps.sort(key=lambda map: map.name) # Create warp map for warp, destination in extracted_data["warps"].items(): data.warp_map[warp] = None if destination == "" else destination if encoded_warp not in data.warp_map: data.warp_map[encoded_warp] = None # Create trainer data for i, trainer_json in enumerate(extracted_data["trainers"]): party_json = trainer_json["party"] pokemon_data_type = _str_to_pokemon_data_type(trainer_json["pokemon_data_type"]) data.trainers.append(TrainerData( i, TrainerPartyData( [TrainerPokemonData( p["species"], p["level"], (p["moves"][0], p["moves"][1], p["moves"][2], p["moves"][3]) ) for p in party_json], pokemon_data_type, trainer_json["party_rom_address"] ), trainer_json["rom_address"], trainer_json["battle_script_rom_address"] )) _init()