diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/constants.py | 740 | ||||
-rwxr-xr-x | tools/script_extractor.py | 6 | ||||
-rwxr-xr-x | tools/script_extractor2.py | 393 |
3 files changed, 1136 insertions, 3 deletions
diff --git a/tools/constants.py b/tools/constants.py new file mode 100644 index 0000000..ee3069e --- /dev/null +++ b/tools/constants.py @@ -0,0 +1,740 @@ +boosters = { + 0x00: "BOOSTER_COLOSSEUM_NEUTRAL", + 0x01: "BOOSTER_COLOSSEUM_GRASS", + 0x02: "BOOSTER_COLOSSEUM_FIRE", + 0x03: "BOOSTER_COLOSSEUM_WATER", + 0x04: "BOOSTER_COLOSSEUM_LIGHTNING", + 0x05: "BOOSTER_COLOSSEUM_FIGHTING", + 0x06: "BOOSTER_COLOSSEUM_TRAINER", + 0x07: "BOOSTER_EVOLUTION_NEUTRAL", + 0x08: "BOOSTER_EVOLUTION_GRASS", + 0x09: "BOOSTER_EVOLUTION_FIRE", + 0x0a: "BOOSTER_EVOLUTION_WATER", + 0x0b: "BOOSTER_EVOLUTION_FIGHTING", + 0x0c: "BOOSTER_EVOLUTION_PSYCHIC", + 0x0d: "BOOSTER_EVOLUTION_TRAINER", + 0x0e: "BOOSTER_MYSTERY_NEUTRAL", + 0x0f: "BOOSTER_MYSTERY_GRASS_COLORLESS", + 0x10: "BOOSTER_MYSTERY_WATER_COLORLESS", + 0x11: "BOOSTER_MYSTERY_LIGHTNING_COLORLESS", + 0x12: "BOOSTER_MYSTERY_FIGHTING_COLORLESS", + 0x13: "BOOSTER_MYSTERY_TRAINER_COLORLESS", + 0x14: "BOOSTER_LABORATORY_NEUTRAL", + 0x15: "BOOSTER_LABORATORY_GRASS", + 0x16: "BOOSTER_LABORATORY_WATER", + 0x17: "BOOSTER_LABORATORY_PSYCHIC", + 0x18: "BOOSTER_LABORATORY_TRAINER", + 0x19: "BOOSTER_ENERGY_LIGHTNING_FIRE", + 0x1a: "BOOSTER_ENERGY_WATER_FIGHTING", + 0x1b: "BOOSTER_ENERGY_GRASS_PSYCHIC", + 0x1c: "BOOSTER_ENERGY_RANDOM", + 0xff: "NO_BOOSTER", +} + +cards = { + 0x00: "VARIABLE_CARD", + 0x01: "GRASS_ENERGY", + 0x02: "FIRE_ENERGY", + 0x03: "WATER_ENERGY", + 0x04: "LIGHTNING_ENERGY", + 0x05: "FIGHTING_ENERGY", + 0x06: "PSYCHIC_ENERGY", + 0x07: "DOUBLE_COLORLESS_ENERGY", + 0x08: "BULBASAUR", + 0x09: "IVYSAUR", + 0x0a: "VENUSAUR1", + 0x0b: "VENUSAUR2", + 0x0c: "CATERPIE", + 0x0d: "METAPOD", + 0x0e: "BUTTERFREE", + 0x0f: "WEEDLE", + 0x10: "KAKUNA", + 0x11: "BEEDRILL", + 0x12: "EKANS", + 0x13: "ARBOK", + 0x14: "NIDORANF", + 0x15: "NIDORINA", + 0x16: "NIDOQUEEN", + 0x17: "NIDORANM", + 0x18: "NIDORINO", + 0x19: "NIDOKING", + 0x1a: "ZUBAT", + 0x1b: "GOLBAT", + 0x1c: "ODDISH", + 0x1d: "GLOOM", + 0x1e: "VILEPLUME", + 0x1f: "PARAS", + 0x20: "PARASECT", + 0x21: "VENONAT", + 0x22: "VENOMOTH", + 0x23: "BELLSPROUT", + 0x24: "WEEPINBELL", + 0x25: "VICTREEBEL", + 0x26: "GRIMER", + 0x27: "MUK", + 0x28: "EXEGGCUTE", + 0x29: "EXEGGUTOR", + 0x2a: "KOFFING", + 0x2b: "WEEZING", + 0x2c: "TANGELA1", + 0x2d: "TANGELA2", + 0x2e: "SCYTHER", + 0x2f: "PINSIR", + 0x30: "CHARMANDER", + 0x31: "CHARMELEON", + 0x32: "CHARIZARD", + 0x33: "VULPIX", + 0x34: "NINETAILS1", + 0x35: "NINETAILS2", + 0x36: "GROWLITHE", + 0x37: "ARCANINE1", + 0x38: "ARCANINE2", + 0x39: "PONYTA", + 0x3a: "RAPIDASH", + 0x3b: "MAGMAR1", + 0x3c: "MAGMAR2", + 0x3d: "FLAREON1", + 0x3e: "FLAREON2", + 0x3f: "MOLTRES1", + 0x40: "MOLTRES2", + 0x41: "SQUIRTLE", + 0x42: "WARTORTLE", + 0x43: "BLASTOISE", + 0x44: "PSYDUCK", + 0x45: "GOLDUCK", + 0x46: "POLIWAG", + 0x47: "POLIWHIRL", + 0x48: "POLIWRATH", + 0x49: "TENTACOOL", + 0x4a: "TENTACRUEL", + 0x4b: "SEEL", + 0x4c: "DEWGONG", + 0x4d: "SHELLDER", + 0x4e: "CLOYSTER", + 0x4f: "KRABBY", + 0x50: "KINGLER", + 0x51: "HORSEA", + 0x52: "SEADRA", + 0x53: "GOLDEEN", + 0x54: "SEAKING", + 0x55: "STARYU", + 0x56: "STARMIE", + 0x57: "MAGIKARP", + 0x58: "GYARADOS", + 0x59: "LAPRAS", + 0x5a: "VAPOREON1", + 0x5b: "VAPOREON2", + 0x5c: "OMANYTE", + 0x5d: "OMASTAR", + 0x5e: "ARTICUNO1", + 0x5f: "ARTICUNO2", + 0x60: "PIKACHU1", + 0x61: "PIKACHU2", + 0x62: "PIKACHU3", + 0x63: "PIKACHU4", + 0x64: "FLYING_PIKACHU", + 0x65: "SURFING_PIKACHU1", + 0x66: "SURFING_PIKACHU2", + 0x67: "RAICHU1", + 0x68: "RAICHU2", + 0x69: "MAGNEMITE1", + 0x6a: "MAGNEMITE2", + 0x6b: "MAGNETON1", + 0x6c: "MAGNETON2", + 0x6d: "VOLTORB", + 0x6e: "ELECTRODE1", + 0x6f: "ELECTRODE2", + 0x70: "ELECTABUZZ1", + 0x71: "ELECTABUZZ2", + 0x72: "JOLTEON1", + 0x73: "JOLTEON2", + 0x74: "ZAPDOS1", + 0x75: "ZAPDOS2", + 0x76: "ZAPDOS3", + 0x77: "SANDSHREW", + 0x78: "SANDSLASH", + 0x79: "DIGLETT", + 0x7a: "DUGTRIO", + 0x7b: "MANKEY", + 0x7c: "PRIMEAPE", + 0x7d: "MACHOP", + 0x7e: "MACHOKE", + 0x7f: "MACHAMP", + 0x80: "GEODUDE", + 0x81: "GRAVELER", + 0x82: "GOLEM", + 0x83: "ONIX", + 0x84: "CUBONE", + 0x85: "MAROWAK1", + 0x86: "MAROWAK2", + 0x87: "HITMONLEE", + 0x88: "HITMONCHAN", + 0x89: "RHYHORN", + 0x8a: "RHYDON", + 0x8b: "KABUTO", + 0x8c: "KABUTOPS", + 0x8d: "AERODACTYL", + 0x8e: "ABRA", + 0x8f: "KADABRA", + 0x90: "ALAKAZAM", + 0x91: "SLOWPOKE1", + 0x92: "SLOWPOKE2", + 0x93: "SLOWBRO", + 0x94: "GASTLY1", + 0x95: "GASTLY2", + 0x96: "HAUNTER1", + 0x97: "HAUNTER2", + 0x98: "GENGAR", + 0x99: "DROWZEE", + 0x9a: "HYPNO", + 0x9b: "MR_MIME", + 0x9c: "JYNX", + 0x9d: "MEWTWO1", + 0x9e: "MEWTWO2", + 0x9f: "MEWTWO3", + 0xa0: "MEW1", + 0xa1: "MEW2", + 0xa2: "MEW3", + 0xa3: "PIDGEY", + 0xa4: "PIDGEOTTO", + 0xa5: "PIDGEOT1", + 0xa6: "PIDGEOT2", + 0xa7: "RATTATA", + 0xa8: "RATICATE", + 0xa9: "SPEAROW", + 0xaa: "FEAROW", + 0xab: "CLEFAIRY", + 0xac: "CLEFABLE", + 0xad: "JIGGLYPUFF1", + 0xae: "JIGGLYPUFF2", + 0xaf: "JIGGLYPUFF3", + 0xb0: "WIGGLYTUFF", + 0xb1: "MEOWTH1", + 0xb2: "MEOWTH2", + 0xb3: "PERSIAN", + 0xb4: "FARFETCHD", + 0xb5: "DODUO", + 0xb6: "DODRIO", + 0xb7: "LICKITUNG", + 0xb8: "CHANSEY", + 0xb9: "KANGASKHAN", + 0xba: "TAUROS", + 0xbb: "DITTO", + 0xbc: "EEVEE", + 0xbd: "PORYGON", + 0xbe: "SNORLAX", + 0xbf: "DRATINI", + 0xc0: "DRAGONAIR", + 0xc1: "DRAGONITE1", + 0xc2: "DRAGONITE2", + 0xc3: "PROFESSOR_OAK", + 0xc4: "IMPOSTER_PROFESSOR_OAK", + 0xc5: "BILL", + 0xc6: "MR_FUJI", + 0xc7: "LASS", + 0xc8: "IMAKUNI_CARD", + 0xc9: "POKEMON_TRADER", + 0xca: "POKEMON_BREEDER", + 0xcb: "CLEFAIRY_DOLL", + 0xcc: "MYSTERIOUS_FOSSIL", + 0xcd: "ENERGY_RETRIEVAL", + 0xce: "SUPER_ENERGY_RETRIEVAL", + 0xcf: "ENERGY_SEARCH", + 0xd0: "ENERGY_REMOVAL", + 0xd1: "SUPER_ENERGY_REMOVAL", + 0xd2: "SWITCH", + 0xd3: "POKEMON_CENTER", + 0xd4: "POKE_BALL", + 0xd5: "SCOOP_UP", + 0xd6: "COMPUTER_SEARCH", + 0xd7: "POKEDEX", + 0xd8: "PLUSPOWER", + 0xd9: "DEFENDER", + 0xda: "ITEM_FINDER", + 0xdb: "GUST_OF_WIND", + 0xdc: "DEVOLUTION_SPRAY", + 0xdd: "POTION", + 0xde: "SUPER_POTION", + 0xdf: "FULL_HEAL", + 0xe0: "REVIVE", + 0xe1: "MAINTENANCE", + 0xe2: "POKEMON_FLUTE", + 0xe3: "GAMBLER", + 0xe4: "RECYCLE", + 0xff: "$ff", +} + +decks = { + 0x00: "SAMS_PRACTICE_DECK_ID", + 0x01: "PRACTICE_PLAYER_DECK_ID", + 0x02: "SAMS_NORMAL_DECK_ID", + 0x03: "CHARMANDER_AND_FRIENDS_DECK_ID", + 0x04: "CHARMANDER_EXTRA_DECK_ID", + 0x05: "SQUIRTLE_AND_FRIENDS_DECK_ID", + 0x06: "SQUIRTLE_EXTRA_DECK_ID", + 0x07: "BULBASAUR_AND_FRIENDS_DECK_ID", + 0x08: "BULBASAUR_EXTRA_DECK_ID", + 0x09: "LIGHTNING_AND_FIRE_DECK_ID", + 0x0a: "WATER_AND_FIGHTING_DECK_ID", + 0x0b: "GRASS_AND_PSYCHIC_DECK_ID", + 0x0c: "LEGENDARY_MOLTRES_DECK_ID", + 0x0d: "LEGENDARY_ZAPDOS_DECK_ID", + 0x0e: "LEGENDARY_ARTICUNO_DECK_ID", + 0x0f: "LEGENDARY_DRAGONITE_DECK_ID", + 0x10: "FIRST_STRIKE_DECK_ID", + 0x11: "ROCK_CRUSHER_DECK_ID", + 0x12: "GO_GO_RAIN_DANCE_DECK_ID", + 0x13: "ZAPPING_SELFDESTRUCT_DECK_ID", + 0x14: "FLOWER_POWER_DECK_ID", + 0x15: "STRANGE_PSYSHOCK_DECK_ID", + 0x16: "WONDERS_OF_SCIENCE_DECK_ID", + 0x17: "FIRE_CHARGE_DECK_ID", + 0x18: "IM_RONALD_DECK_ID", + 0x19: "POWERFUL_RONALD_DECK_ID", + 0x1a: "INVINCIBLE_RONALD_DECK_ID", + 0x1b: "LEGENDARY_RONALD_DECK_ID", + 0x1c: "MUSCLES_FOR_BRAINS_DECK_ID", + 0x1d: "HEATED_BATTLE_DECK_ID", + 0x1e: "LOVE_TO_BATTLE_DECK_ID", + 0x1f: "EXCAVATION_DECK_ID", + 0x20: "BLISTERING_POKEMON_DECK_ID", + 0x21: "HARD_POKEMON_DECK_ID", + 0x22: "WATERFRONT_POKEMON_DECK_ID", + 0x23: "LONELY_FRIENDS_DECK_ID", + 0x24: "SOUND_OF_THE_WAVES_DECK_ID", + 0x25: "PIKACHU_DECK_ID", + 0x26: "BOOM_BOOM_SELFDESTRUCT_DECK_ID", + 0x27: "POWER_GENERATOR_DECK_ID", + 0x28: "ETCETERA_DECK_ID", + 0x29: "FLOWER_GARDEN_DECK_ID", + 0x2a: "KALEIDOSCOPE_DECK_ID", + 0x2b: "GHOST_DECK_ID", + 0x2c: "NAP_TIME_DECK_ID", + 0x2d: "STRANGE_POWER_DECK_ID", + 0x2e: "FLYIN_POKEMON_DECK_ID", + 0x2f: "LOVELY_NIDORAN_DECK_ID", + 0x30: "POISON_DECK_ID", + 0x31: "ANGER_DECK_ID", + 0x32: "FLAMETHROWER_DECK_ID", + 0x33: "RESHUFFLE_DECK_ID", + 0x34: "IMAKUNI_DECK_ID", + 0xff: "$ff", +} + +directions = [ + "NORTH", + "EAST", + "SOUTH", + "WEST", +] + +events = [ + "EVENT_FLAG_00", + "EVENT_FLAG_01", + "EVENT_TEMP_TALKED_TO_IMAKUNI", + "EVENT_TEMP_BATTLED_IMAKUNI", + "EVENT_FLAG_04", + "EVENT_FLAG_05", + "EVENT_FLAG_06", + "EVENT_FLAG_07", + "EVENT_FLAG_08", + "EVENT_FLAG_09", + "EVENT_FLAG_0A", + "EVENT_BEAT_AMY", + "EVENT_FLAG_0C", + "EVENT_FLAG_0D", + "EVENT_FLAG_0E", + "EVENT_FLAG_0F", + "EVENT_FLAG_10", + "EVENT_FLAG_11", + "EVENT_FLAG_12", + "EVENT_IMAKUNI_STATE", + "EVENT_FLAG_14", + "EVENT_BEAT_SARA", + "EVENT_BEAT_AMANDA", + "EVENT_FLAG_17", + "EVENT_FLAG_18", + "EVENT_FLAG_19", + "EVENT_FLAG_1A", + "EVENT_FLAG_1B", + "EVENT_FLAG_1C", + "EVENT_FLAG_1D", + "EVENT_FLAG_1E", + "EVENT_FLAG_1F", + "EVENT_FLAG_20", + "EVENT_FLAG_21", + "EVENT_RECEIVED_LEGENDARY_CARD", + "EVENT_FLAG_23", + "EVENT_FLAG_24", + "EVENT_FLAG_25", + "EVENT_FLAG_26", + "EVENT_FLAG_27", + "EVENT_FLAG_28", + "EVENT_FLAG_29", + "EVENT_FLAG_2A", + "EVENT_FLAG_2B", + "EVENT_FLAG_2C", + "EVENT_FLAG_2D", + "EVENT_MEDAL_COUNT", + "EVENT_FLAG_2F", + "EVENT_FLAG_30", + "EVENT_FLAG_31", + "EVENT_FLAG_32", + "EVENT_JOSHUA_STATE", + "EVENT_IMAKUNI_ROOM", + "EVENT_FLAG_35", + "EVENT_IMAKUNI_WIN_COUNT", + "EVENT_FLAG_37", + "EVENT_FLAG_38", + "EVENT_FLAG_39", + "EVENT_FLAG_3A", + "EVENT_FLAG_3B", + "FLAG_BEAT_BRITTANY", + "EVENT_FLAG_3D", + "EVENT_FLAG_3E", + "EVENT_FLAG_3F", + "EVENT_FLAG_40", + "EVENT_FLAG_41", + "EVENT_FLAG_42", + "EVENT_FLAG_43", + "EVENT_FLAG_44", + "EVENT_FLAG_45", + "EVENT_FLAG_46", + "EVENT_FLAG_47", + "EVENT_FLAG_48", + "EVENT_FLAG_49", + "EVENT_FLAG_4A", + "EVENT_FLAG_4B", + "EVENT_FLAG_4C", + "EVENT_FLAG_4D", + "EVENT_FLAG_4E", + "EVENT_FLAG_4F", + "EVENT_FLAG_50", + "EVENT_FLAG_51", + "EVENT_FLAG_52", + "EVENT_FLAG_53", + "EVENT_FLAG_54", + "EVENT_FLAG_55", + "EVENT_FLAG_56", + "EVENT_FLAG_57", + "EVENT_FLAG_58", + "EVENT_FLAG_59", + "EVENT_FLAG_5A", + "EVENT_FLAG_5B", + "EVENT_FLAG_5C", + "EVENT_FLAG_5D", + "EVENT_FLAG_5E", + "EVENT_FLAG_5F", + "EVENT_FLAG_60", + "EVENT_FLAG_61", + "EVENT_FLAG_62", + "EVENT_FLAG_63", + "EVENT_FLAG_64", + "EVENT_FLAG_65", + "EVENT_FLAG_66", + "EVENT_FLAG_67", + "EVENT_FLAG_68", + "EVENT_FLAG_69", + "EVENT_FLAG_6A", + "EVENT_FLAG_6B", + "EVENT_FLAG_6C", + "EVENT_FLAG_6D", + "EVENT_FLAG_6E", + "EVENT_FLAG_6F", + "EVENT_FLAG_70", + "EVENT_FLAG_71", + "EVENT_FLAG_72", + "EVENT_FLAG_73", + "EVENT_FLAG_74", + "EVENT_FLAG_75", + "EVENT_FLAG_76", +] + +maps = [ + "OVERWORLD_MAP", + "MASON_LABORATORY", + "DECK_MACHINE_ROOM", + "ISHIHARAS_HOUSE", + "FIGHTING_CLUB_ENTRANCE", + "FIGHTING_CLUB_LOBBY", + "FIGHTING_CLUB", + "ROCK_CLUB_ENTRANCE", + "ROCK_CLUB_LOBBY", + "ROCK_CLUB", + "WATER_CLUB_ENTRANCE", + "WATER_CLUB_LOBBY", + "WATER_CLUB", + "LIGHTNING_CLUB_ENTRANCE", + "LIGHTNING_CLUB_LOBBY", + "LIGHTNING_CLUB", + "GRASS_CLUB_ENTRANCE", + "GRASS_CLUB_LOBBY", + "GRASS_CLUB", + "PSYCHIC_CLUB_ENTRANCE", + "PSYCHIC_CLUB_LOBBY", + "PSYCHIC_CLUB", + "SCIENCE_CLUB_ENTRANCE", + "SCIENCE_CLUB_LOBBY", + "SCIENCE_CLUB", + "FIRE_CLUB_ENTRANCE", + "FIRE_CLUB_LOBBY", + "FIRE_CLUB", + "CHALLENGE_HALL_ENTRANCE", + "CHALLENGE_HALL_LOBBY", + "CHALLENGE_HALL", + "POKEMON_DOME_ENTRANCE", + "POKEMON_DOME", + "HALL_OF_HONOR", +] + +npcs = [ + "", + "NPC_DRMASON", + "NPC_RONALD1", + "NPC_ISHIHARA", + "NPC_IMAKUNI", + "NPC_05", + "NPC_06", + "NPC_SAM", + "NPC_TECH1", + "NPC_TECH2", + "NPC_TECH3", + "NPC_TECH4", + "NPC_TECH5", + "NPC_TECH6", + "NPC_CLERK1", + "NPC_CLERK2", + "NPC_CLERK3", + "NPC_CLERK4", + "NPC_CLERK5", + "NPC_CLERK6", + "NPC_CLERK7", + "NPC_CLERK8", + "NPC_CLERK9", + "NPC_CHRIS", + "NPC_MICHAEL", + "NPC_JESSICA", + "NPC_MITCH", + "NPC_MATTHEW", + "NPC_RYAN", + "NPC_ANDREW", + "NPC_GENE", + "NPC_SARA", + "NPC_AMANDA", + "NPC_JOSHUA", + "NPC_AMY", + "NPC_JENNIFER", + "NPC_NICHOLAS", + "NPC_BRANDON", + "NPC_ISAAC", + "NPC_BRITTANY", + "NPC_KRISTIN", + "NPC_HEATHER", + "NPC_NIKKI", + "NPC_ROBERT", + "NPC_DANIEL", + "NPC_STEPHANIE", + "NPC_MURRAY1", + "NPC_JOSEPH", + "NPC_DAVID", + "NPC_ERIK", + "NPC_RICK", + "NPC_JOHN", + "NPC_ADAM", + "NPC_JONATHAN", + "NPC_KEN", + "NPC_COURTNEY", + "NPC_STEVE", + "NPC_JACK", + "NPC_ROD", + "NPC_CLERK10", + "NPC_GIFT_CENTER_CLERK", + "NPC_MAN1", + "NPC_WOMAN1", + "NPC_CHAP1", + "NPC_GAL1", + "NPC_LASS1", + "NPC_CHAP2", + "NPC_LASS2", + "NPC_PAPPY1", + "NPC_LAD1", + "NPC_LAD2", + "NPC_CHAP3", + "NPC_CLERK12", + "NPC_CLERK13", + "NPC_HOST", + "NPC_SPECS1", + "NPC_BUTCH", + "NPC_GRANNY1", + "NPC_LASS3", + "NPC_MAN2", + "NPC_PAPPY2", + "NPC_LASS4", + "NPC_HOOD1", + "NPC_GRANNY2", + "NPC_GAL2", + "NPC_LAD3", + "NPC_GAL3", + "NPC_CHAP4", + "NPC_MAN3", + "NPC_SPECS2", + "NPC_SPECS3", + "NPC_WOMAN2", + "NPC_MANIA", + "NPC_PAPPY3", + "NPC_GAL4", + "NPC_CHAMP", + "NPC_HOOD2", + "NPC_LASS5", + "NPC_CHAP5", + "NPC_AARON", + "NPC_GUIDE", + "NPC_TECH7", + "NPC_TECH8", + "NPC_TORCH", + "NPC_LEGENDARY_CARD_TOP_LEFT", + "NPC_LEGENDARY_CARD_TOP_RIGHT", + "NPC_LEGENDARY_CARD_LEFT_SPARK", + "NPC_LEGENDARY_CARD_BOTTOM_LEFT", + "NPC_LEGENDARY_CARD_BOTTOM_RIGHT", + "NPC_LEGENDARY_CARD_RIGHT_SPARK", + "NPC_6E", + "NPC_6F", + "NPC_MURRAY2", + "NPC_RONALD2", + "NPC_RONALD3", + "NPC_73", +] + +sfxs = [ + "SFX_STOP", + "SFX_01", + "SFX_02", + "SFX_03", + "SFX_04", + "SFX_05", + "SFX_06", + "SFX_07", + "SFX_08", + "SFX_09", + "SFX_0A", + "SFX_0B", + "SFX_0C", + "SFX_0D", + "SFX_0E", + "SFX_0F", + "SFX_10", + "SFX_11", + "SFX_12", + "SFX_13", + "SFX_14", + "SFX_15", + "SFX_16", + "SFX_17", + "SFX_18", + "SFX_19", + "SFX_1A", + "SFX_1B", + "SFX_1C", + "SFX_1D", + "SFX_1E", + "SFX_1F", + "SFX_20", + "SFX_21", + "SFX_22", + "SFX_23", + "SFX_24", + "SFX_25", + "SFX_26", + "SFX_27", + "SFX_28", + "SFX_29", + "SFX_2A", + "SFX_2B", + "SFX_2C", + "SFX_2D", + "SFX_2E", + "SFX_2F", + "SFX_30", + "SFX_31", + "SFX_32", + "SFX_33", + "SFX_34", + "SFX_35", + "SFX_36", + "SFX_37", + "SFX_38", + "SFX_39", + "SFX_3A", + "SFX_3B", + "SFX_3C", + "SFX_3D", + "SFX_3E", + "SFX_3F", + "SFX_40", + "SFX_41", + "SFX_42", + "SFX_43", + "SFX_44", + "SFX_45", + "SFX_46", + "SFX_47", + "SFX_48", + "SFX_49", + "SFX_4A", + "SFX_4B", + "SFX_4C", + "SFX_4D", + "SFX_4E", + "SFX_4F", + "SFX_50", + "SFX_51", + "SFX_52", + "SFX_53", + "SFX_54", + "SFX_55", + "SFX_56", + "SFX_57", + "SFX_58", + "SFX_59", + "SFX_5A", + "SFX_5B", + "SFX_5C", + "SFX_5D", + "SFX_5E", + "SFX_5F", +] + +songs = [ + "MUSIC_STOP", + "MUSIC_TITLESCREEN", + "MUSIC_DUEL_THEME_1", + "MUSIC_DUEL_THEME_2", + "MUSIC_DUEL_THEME_3", + "MUSIC_PAUSE_MENU", + "MUSIC_PC_MAIN_MENU", + "MUSIC_DECK_MACHINE", + "MUSIC_CARD_POP", + "MUSIC_OVERWORLD", + "MUSIC_POKEMON_DOME", + "MUSIC_CHALLENGE_HALL", + "MUSIC_CLUB_1", + "MUSIC_CLUB_2", + "MUSIC_CLUB_3", + "MUSIC_RONALD", + "MUSIC_IMAKUNI", + "MUSIC_HALL_OF_HONOR", + "MUSIC_CREDITS", + "MUSIC_UNUSED_13", + "MUSIC_UNUSED_14", + "MUSIC_MATCH_START_1", + "MUSIC_MATCH_START_2", + "MUSIC_MATCH_START_3", + "MUSIC_MATCH_VICTORY", + "MUSIC_MATCH_LOSS", + "MUSIC_MATCH_DRAW", + "MUSIC_UNUSED_1B", + "MUSIC_BOOSTER_PACK", + "MUSIC_MEDAL", + "MUSIC_UNUSED_1E", +] diff --git a/tools/script_extractor.py b/tools/script_extractor.py index 8869c66..ed8eaf9 100755 --- a/tools/script_extractor.py +++ b/tools/script_extractor.py @@ -86,9 +86,9 @@ def decodeLine(scriptList, game_data, loc, ignore_broken, locList): wordLoc = (game_data[loc] + (game_data[loc+1]<<8)) if wordLoc == 0000: if macroMode: - ret += "NO_JUMP, " + ret += "NULL, " else: - ret += "\tdw NO_JUMP\n" + ret += "\tdw NULL\n" else: if macroMode: ret += ".ows_" + format(wordLoc+0x8000,"04x") + ", " @@ -285,7 +285,7 @@ def createList(): # this is a func just so all this can go at the bottom ("Func_d3e0", "", DO_NOT_QUIT,""), ("Func_d3fe", "q", DO_NOT_QUIT,""), ("Func_d408", "b", DO_NOT_QUIT,""), - ("Func_d40f", "q", DO_NOT_QUIT,""), + ("ScriptCommand_PlaySong", "b", DO_NOT_QUIT,"play_song"), ("ScriptCommand_PlaySFX", "b", DO_NOT_QUIT,"play_sfx"), ("ScriptCommand_PauseSong", "", DO_NOT_QUIT,"pause_song"), ("ScriptCommand_ResumeSong", "", DO_NOT_QUIT,"resume_song"), diff --git a/tools/script_extractor2.py b/tools/script_extractor2.py new file mode 100755 index 0000000..0e835e4 --- /dev/null +++ b/tools/script_extractor2.py @@ -0,0 +1,393 @@ +#!/usr/bin/env python + +import argparse + +from constants import boosters +from constants import cards +from constants import decks +from constants import directions +from constants import events +from constants import maps +from constants import npcs +from constants import sfxs +from constants import songs + +args = None +rom = None + +# script command names and parameter lists +script_commands = { + 0xe7: { "name": "start_script", "params": [] }, + + 0x00: { "name": "end_script_loop", "params": [] }, + 0x01: { "name": "close_advanced_text_box", "params": [] }, + 0x02: { "name": "print_text_string", "params": [ "text" ] }, + 0x03: { "name": "Func_ccdc", "params": [ "text" ] }, # print text and ??? + 0x04: { "name": "ask_question_jump", "params": [ "text", "label" ] }, + 0x05: { "name": "start_battle", "params": [ "prizes", "deck", "song" ] }, + 0x06: { "name": "print_variable_text", "params": [ "text", "text" ] }, + 0x07: { "name": "Func_cda8", "params": [ "text", "text" ] }, # print variable text and ??? + 0x08: { "name": "print_text_quit_fully", "params": [ "text" ] }, + 0x09: { "name": "Func_cdcb", "params": [] }, + 0x0a: { "name": "move_active_npc_by_direction", "params": [ "movement_table" ] }, + 0x0b: { "name": "close_text_box", "params": [] }, + 0x0c: { "name": "give_booster_packs", "params": [ "booster", "booster", "booster" ] }, + 0x0d: { "name": "jump_if_card_owned", "params": [ "card", "label" ] }, + 0x0e: { "name": "jump_if_card_in_collection", "params": [ "card", "label" ] }, + 0x0f: { "name": "give_card", "params": [ "card" ] }, + 0x10: { "name": "take_card", "params": [ "card" ] }, + 0x11: { "name": "Func_cf53", "params": [ "label" ] }, # jump if any energy cards in collection + 0x12: { "name": "Func_cf7b", "params": [] }, # remove all energy cards from collection + 0x13: { "name": "jump_if_enough_cards_owned", "params": [ "word_decimal", "label" ] }, + 0x14: { "name": "fight_club_pupil_jump", "params": [ "label", "label", "label", "label", "label" ] }, + 0x15: { "name": "Func_cfc6", "params": [ "byte" ] }, + 0x16: { "name": "Func_cfd4", "params": [] }, + 0x17: { "name": "Func_d00b", "params": [] }, # get card name for EVENT_FLAG_2B + 0x18: { "name": "Func_d025", "params": [ "label" ] }, # jump if card in EVENT_FLAG_2B is in collection or decks + 0x19: { "name": "Func_d032", "params": [ "label" ] }, # jump if card in EVENT_FLAG_2B is in collection + 0x1a: { "name": "Func_d03f", "params": [] }, # remove card in EVENT_FLAG_2B from collection + 0x1b: { "name": "script_jump", "params": [ "label" ] }, + 0x1c: { "name": "try_give_medal_pc_packs", "params": [] }, + 0x1d: { "name": "set_player_direction", "params": [ "direction" ] }, + 0x1e: { "name": "move_player", "params": [ "direction", "byte_decimal" ] }, + 0x1f: { "name": "show_card_received_screen", "params": [ "card" ] }, + 0x20: { "name": "set_dialog_npc", "params": [ "npc" ] }, + 0x21: { "name": "set_next_npc_and_script", "params": [ "npc", "label" ] }, + 0x22: { "name": "Func_d095", "params": [ "byte", "byte", "byte" ] }, # LOADED_NPC_FIELD_05 and LOADED_NPC_FIELD_06 + 0x23: { "name": "Func_d0be", "params": [ "byte", "byte" ] }, # coords + 0x24: { "name": "do_frames", "params": [ "byte_decimal" ] }, + 0x25: { "name": "Func_d0d9", "params": [ "byte", "byte", "label" ] }, # coords, jump if npc coords match + 0x26: { "name": "jump_if_player_coords_match", "params": [ "byte_decimal", "byte_decimal", "label" ] }, + 0x27: { "name": "move_active_npc", "params": [ "movement" ] }, + 0x28: { "name": "give_one_of_each_trainer_booster", "params": [] }, + 0x29: { "name": "Func_d103", "params": [ "npc", "label" ] }, # jump if npc loaded + 0x2a: { "name": "Func_d125", "params": [ "event" ] }, # give medal + 0x2b: { "name": "Func_d135", "params": [ "byte" ] }, # load current map name into tx ram slot + 0x2c: { "name": "Func_d16b", "params": [ "byte" ] }, # load current npc name into tx ram slot + 0x2d: { "name": "Func_cd4f", "params": [ "prizes", "deck", "song" ] }, + 0x2e: { "name": "Func_cd94", "params": [ "text", "text", "text" ] }, + 0x2f: { "name": "move_wram_npc", "params": [ "movement" ] }, + 0x30: { "name": "Func_cdd8", "params": [] }, + 0x31: { "name": "Func_cdf5", "params": [ "byte", "byte" ] }, # coords + 0x32: { "name": "Func_d195", "params": [] }, # pick challenge hall opponent + 0x33: { "name": "Func_d1ad", "params": [] }, # open menu + 0x34: { "name": "Func_d1b3", "params": [] }, # pick trade card + 0x35: { "name": "quit_script_fully", "params": [] }, + 0x36: { "name": "Func_d244", "params": [ "byte" ] }, + 0x37: { "name": "choose_deck_to_duel_against_multichoice", "params": [] }, + 0x38: { "name": "open_deck_machine", "params": [ "byte" ] }, + 0x39: { "name": "choose_starter_deck_multichoice", "params": [] }, + 0x3a: { "name": "enter_map", "params": [ "byte", "map", "byte_decimal", "byte_decimal", "direction" ] }, + 0x3b: { "name": "move_arbitrary_npc", "params": [ "npc", "movement" ] }, + 0x3c: { "name": "Func_d209", "params": [] }, # pick legendary card + 0x3d: { "name": "Func_d38f", "params": [ "byte" ] }, + 0x3e: { "name": "Func_d396", "params": [ "byte" ] }, + 0x3f: { "name": "Func_cd76", "params": [] }, + 0x40: { "name": "Func_d39d", "params": [ "byte" ] }, + 0x41: { "name": "Func_d3b9", "params": [] }, + 0x42: { "name": "try_give_pc_pack", "params": [ "byte" ] }, + 0x43: { "name": "script_nop", "params": [] }, + 0x44: { "name": "Func_d3d4", "params": [] }, + 0x45: { "name": "Func_d3e0", "params": [] }, + 0x46: { "name": "Func_d3fe", "params": [ "song" ] }, + 0x47: { "name": "Func_d408", "params": [ "song" ] }, # set default song + 0x48: { "name": "play_song", "params": [ "song" ] }, + 0x49: { "name": "play_sfx", "params": [ "sfx" ] }, + 0x4a: { "name": "pause_song", "params": [] }, + 0x4b: { "name": "resume_song", "params": [] }, + 0x4c: { "name": "Func_d41d", "params": [] }, # play default song + 0x4d: { "name": "wait_for_song_to_finish", "params": [] }, + 0x4e: { "name": "Func_d435", "params": [ "byte" ] }, + 0x4f: { "name": "ask_question_jump_default_yes", "params": [ "text", "label" ] }, + 0x50: { "name": "show_sam_normal_multichoice", "params": [] }, + 0x51: { "name": "show_sam_tutorial_multichoice", "params": [] }, + 0x52: { "name": "Func_d43d", "params": [] }, + 0x53: { "name": "end_script_loop_2", "params": [] }, + 0x54: { "name": "end_script_loop_3", "params": [] }, + 0x55: { "name": "end_script_loop_4", "params": [] }, + 0x56: { "name": "end_script_loop_5", "params": [] }, + 0x57: { "name": "end_script_loop_6", "params": [] }, + 0x58: { "name": "script_set_flag_value", "params": [ "event", "byte" ] }, + 0x59: { "name": "jump_if_flag_zero_1", "params": [ "event", "label" ] }, + 0x5a: { "name": "jump_if_flag_nonzero_1", "params": [ "event", "label" ] }, + 0x5b: { "name": "jump_if_flag_equal", "params": [ "event", "byte", "label" ] }, + 0x5c: { "name": "jump_if_flag_not_equal", "params": [ "event", "byte", "label" ] }, + 0x5d: { "name": "jump_if_flag_not_less_than", "params": [ "event", "byte", "label" ] }, + 0x5e: { "name": "jump_if_flag_less_than", "params": [ "event", "byte", "label" ] }, + 0x5f: { "name": "max_out_flag_value", "params": [ "event" ] }, + 0x60: { "name": "zero_out_flag_value", "params": [ "event" ] }, + 0x61: { "name": "jump_if_flag_nonzero_2", "params": [ "event", "label"] }, + 0x62: { "name": "jump_if_flag_zero_2", "params": [ "event", "label" ] }, + 0x63: { "name": "increment_flag_value", "params": [ "event" ] }, + 0x64: { "name": "end_script_loop_7", "params": [] }, + 0x65: { "name": "end_script_loop_8", "params": [] }, + 0x66: { "name": "end_script_loop_9", "params": [] }, + 0x67: { "name": "end_script_loop_10", "params": [] }, +} + +quit_commands = [ + 0x00, + 0x08, + 0x1b, + 0x35, + 0x53, + 0x54, + 0x55, + 0x56, + 0x57, + 0x64, + 0x65, + 0x66, + 0x67, +] + +# length in bytes of each type of parameter +param_lengths = { + "byte": 1, + "byte_decimal": 1, + "booster": 1, + "card": 1, + "deck": 1, + "direction": 1, + "event": 1, + "map": 1, + "npc": 1, + "prizes": 1, + "sfx": 1, + "song": 1, + "word_decimal": 2, + "movement": 2, + "movement_table": 2, + "text": 2, + "label": 2, +} + +def get_bank(address): + return int(address / 0x4000) + +def get_relative_address(address): + if address < 0x4000: + return address + return (address % 0x4000) + 0x4000 + +# get absolute pointer stored at an address in the rom +# if bank is None, assumes the pointer refers to the same bank as the bank it is located in +def get_pointer(address, bank=None): + raw_pointer = rom[address + 1] * 0x100 + rom[address] + if raw_pointer < 0x4000: + bank = 0 + if bank is None: + bank = get_bank(address) + return (raw_pointer % 0x4000) + bank * 0x4000 + +def make_address_comment(address): + return " ; {:x} ({:x}:{:x})\n".format(address, get_bank(address), get_relative_address(address)) + +def make_blob(start, output, end=None): + return { "start": start, "output": output, "end": end if end else start } + +def dump_movement(address): + blobs = [] + blobs.append(make_blob(address, "NPCMovement_{:x}:".format(address) + make_address_comment(address))) + while 1: + movement = rom[address] + if movement == 0xff: + blobs.append(make_blob(address, "\tdb ${:02x}\n\n".format(movement), address + 1)) + break + if movement == 0xfe: + jump = rom[address + 1] + if jump > 127: + jump -= 256 + blobs.append(make_blob(address, "\tdb ${:02x}, {}\n\n".format(movement, jump), address + 2)) + break + blobs.append(make_blob(address, "\tdb {}".format(directions[movement & 0b01111111]) + (" | NO_MOVE\n" if movement & 0b10000000 else "\n"), address + 1)) + address += 1 + return blobs + +def dump_movement_table(address): + blobs = [] + blobs.append(make_blob(address, "NPCMovementTable_{:x}:".format(address) + make_address_comment(address))) + for i in range(4): + pointer = get_pointer(address) + blobs.append(make_blob(address, "\tdw NPCMovement_{:x}\n".format(pointer) + ("\n" if i == 3 else ""), address + 2)) + blobs += dump_movement(pointer) + address += 2 + return blobs + +# parse a script starting at the given address +# returns a list of all commands +def dump_script(start_address, address=None, visited=set()): + blobs = [] + branches = set() + if address is None: + blobs.append(make_blob(start_address, "Script_{:x}:".format(start_address) + make_address_comment(start_address))) + address = start_address + else: + blobs.append(make_blob(address, ".ows_{:x}\n".format(address))) + if address in visited: + return blobs + visited.add(address) + while 1: + command_address = address + command_id = rom[command_address] + command = script_commands[command_id] + address += 1 + macro_mode = not command["name"].startswith("Func_") + if macro_mode: + output = "\t{}".format(command["name"]) + else: + output = "\trun_command {}".format(command["name"]) + # print all params for current command + for i in range(len(command["params"])): + param = rom[address] + param_type = command["params"][i] + param_length = param_lengths[param_type] + if param_type == "byte": + if not macro_mode: + output += "\n\tdb" + output += " ${:02x}".format(param) + elif param_type == "byte_decimal": + if not macro_mode: + output += "\n\tdb" + output += " {}".format(param) + elif param_type == "booster": + if not macro_mode: + output += "\n\tdb" + output += " {}".format(boosters[param]) + elif param_type == "card": + if not macro_mode: + output += "\n\tdb" + output += " {}".format(cards[param]) + elif param_type == "deck": + if not macro_mode: + output += "\n\tdb" + output += " {}".format(decks[param]) + elif param_type == "direction": + if not macro_mode: + output += "\n\tdb" + output += " {}".format(directions[param]) + elif param_type == "event": + if not macro_mode: + output += "\n\tdb" + output += " {}".format(events[param]) + elif param_type == "map": + if not macro_mode: + output += "\n\tdb" + output += " {}".format(maps[param]) + elif param_type == "npc": + if not macro_mode: + output += "\n\tdb" + output += " {}".format(npcs[param]) + elif param_type == "prizes": + if not macro_mode: + output += "\n\tdb" + output += " PRIZES_{}".format(param) + elif param_type == "sfx": + if not macro_mode: + output += "\n\tdb" + output += " {}".format(sfxs[param]) + elif param_type == "song": + if not macro_mode: + output += "\n\tdb" + output += " {}".format(songs[param]) + elif param_type == "word_decimal": + if not macro_mode: + output += "\n\tdw" + output += " {}".format(param + rom[address + 1] * 0x100) + elif param_type == "movement": + param = get_pointer(address) + label = "NPCMovement_{:x}".format(param) + if not macro_mode: + output += "\n\tdw" + output += " {}".format(label) + blobs += dump_movement(param) + elif param_type == "movement_table": + param = get_pointer(address) + label = "NPCMovementTable_{:x}".format(param) + if not macro_mode: + output += "\n\tdw" + output += " {}".format(label) + blobs += dump_movement_table(param) + elif param_type == "text": + text_id = param + rom[address + 1] * 0x100 + if not macro_mode: + if text_id == 0x0000: + output += "\n\tdw" + else: + output += "\n\ttx" + if text_id == 0x0000: + output += " NULL" + else: + output += " Text{:04x}".format(text_id) + elif param_type == "label": + param = get_pointer(address) + if param == 0x0000: + label = "NULL" + elif param == start_address: + label = "Script_{:x}".format(param) + else: + label = ".ows_{:x}".format(param) + if param > start_address or args.allow_backward_jumps: + branches.add(param) + if not macro_mode: + output += "\n\tdw" + output += " {}".format(label) + address += param_length + if macro_mode and i < len(command["params"]) - 1: + output += "," + output += "\n" + blobs.append(make_blob(command_address, output, address)) + if command_id in quit_commands: + if rom[address] == 0xc9: + blobs.append(make_blob(address, "\tret\n", address + 1)) + address += 1 + blobs.append(make_blob(address, "; 0x{:x}\n\n".format(address))) + break + for branch in branches: + blobs += dump_script(start_address, branch, visited) + return blobs + +def fill_gap(start, end): + output = "" + for address in range(start, end): + output += "\tdb ${:x}\n".format(rom[address]) + output += "\n" + return output + +def sort_and_filter(blobs): + blobs.sort(key=lambda b: (b["start"], b["end"], not b["output"].startswith(";"))) + filtered = [] + for blob, next in zip(blobs, blobs[1:]+[None]): + if next and blob["start"] == next["start"] and blob["output"] == next["output"]: + continue + if next and blob["end"] < next["start"] and get_bank(blob["end"]) == get_bank(next["start"]): + if args.fill_gaps: + blob["output"] += fill_gap(blob["end"], next["start"]) + else: + blob["output"] += "; gap from 0x{:x} to 0x{:x}\n\n".format(blob["end"], next["start"]) + filtered.append(blob) + if len(filtered) > 0: + filtered[-1]["output"] = filtered[-1]["output"].rstrip("\n") + return filtered + +if __name__ == "__main__": + ap = argparse.ArgumentParser(description="Pokemon TCG Script Extractor") + ap.add_argument("-b", "--allow-backward-jumps", action="store_true", help="extract scripts that are found before the starting address") + ap.add_argument("-g", "--fill-gaps", action="store_true", help="use 'db's to fill the gaps between visited locations") + ap.add_argument("-i", "--ignore-errors", action="store_true", help="silently proceed to the next address if an error occurs") + ap.add_argument("-r", "--rom", default="baserom.gbc", help="rom file to extract script from") + ap.add_argument("addresses", nargs="+", help="addresses to extract from") + args = ap.parse_args() + rom = bytearray(open(args.rom, "rb").read()) + blobs = [] + for address in args.addresses: + try: + blobs += dump_script(int(address, 16)) + except: + if not args.ignore_errors: + raise + blobs = sort_and_filter(blobs) + output = "" + for blob in blobs: + output += blob["output"] + print(output) |