996 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			996 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | """
 | ||
|  | 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() |