mirror of https://github.com/zeldaret/oot.git
				
				
				
			
		
			
				
	
	
		
			2264 lines
		
	
	
		
			84 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			2264 lines
		
	
	
		
			84 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
| #!/usr/bin/env python3
 | |
| #
 | |
| #   message_data_static disassembler/decompiler
 | |
| #
 | |
| 
 | |
| import argparse, re, struct
 | |
| from pathlib import Path
 | |
| from typing import Callable, Dict, List, Optional, Tuple, TypeVar
 | |
| 
 | |
| import version_config
 | |
| 
 | |
| T = TypeVar("T")
 | |
| 
 | |
| item_ids = {
 | |
|     0x00 : "ITEM_DEKU_STICK",
 | |
|     0x01 : "ITEM_DEKU_NUT",
 | |
|     0x02 : "ITEM_BOMB",
 | |
|     0x03 : "ITEM_BOW",
 | |
|     0x04 : "ITEM_ARROW_FIRE",
 | |
|     0x05 : "ITEM_DINS_FIRE",
 | |
|     0x06 : "ITEM_SLINGSHOT",
 | |
|     0x07 : "ITEM_OCARINA_FAIRY",
 | |
|     0x08 : "ITEM_OCARINA_OF_TIME",
 | |
|     0x09 : "ITEM_BOMBCHU",
 | |
|     0x0A : "ITEM_HOOKSHOT",
 | |
|     0x0B : "ITEM_LONGSHOT",
 | |
|     0x0C : "ITEM_ARROW_ICE",
 | |
|     0x0D : "ITEM_FARORES_WIND",
 | |
|     0x0E : "ITEM_BOOMERANG",
 | |
|     0x0F : "ITEM_LENS_OF_TRUTH",
 | |
|     0x10 : "ITEM_MAGIC_BEAN",
 | |
|     0x11 : "ITEM_HAMMER",
 | |
|     0x12 : "ITEM_ARROW_LIGHT",
 | |
|     0x13 : "ITEM_NAYRUS_LOVE",
 | |
|     0x14 : "ITEM_BOTTLE_EMPTY",
 | |
|     0x15 : "ITEM_BOTTLE_POTION_RED",
 | |
|     0x16 : "ITEM_BOTTLE_POTION_GREEN",
 | |
|     0x17 : "ITEM_BOTTLE_POTION_BLUE",
 | |
|     0x18 : "ITEM_BOTTLE_FAIRY",
 | |
|     0x19 : "ITEM_BOTTLE_FISH",
 | |
|     0x1A : "ITEM_BOTTLE_MILK_FULL",
 | |
|     0x1B : "ITEM_BOTTLE_RUTOS_LETTER",
 | |
|     0x1C : "ITEM_BOTTLE_BLUE_FIRE",
 | |
|     0x1D : "ITEM_BOTTLE_BUG",
 | |
|     0x1E : "ITEM_BOTTLE_BIG_POE",
 | |
|     0x1F : "ITEM_BOTTLE_MILK_HALF",
 | |
|     0x20 : "ITEM_BOTTLE_POE",
 | |
|     0x21 : "ITEM_WEIRD_EGG",
 | |
|     0x22 : "ITEM_CHICKEN",
 | |
|     0x23 : "ITEM_ZELDAS_LETTER",
 | |
|     0x24 : "ITEM_MASK_KEATON",
 | |
|     0x25 : "ITEM_MASK_SKULL",
 | |
|     0x26 : "ITEM_MASK_SPOOKY",
 | |
|     0x27 : "ITEM_MASK_BUNNY_HOOD",
 | |
|     0x28 : "ITEM_MASK_GORON",
 | |
|     0x29 : "ITEM_MASK_ZORA",
 | |
|     0x2A : "ITEM_MASK_GERUDO",
 | |
|     0x2B : "ITEM_MASK_TRUTH",
 | |
|     0x2C : "ITEM_SOLD_OUT",
 | |
|     0x2D : "ITEM_POCKET_EGG",
 | |
|     0x2E : "ITEM_POCKET_CUCCO",
 | |
|     0x2F : "ITEM_COJIRO",
 | |
|     0x30 : "ITEM_ODD_MUSHROOM",
 | |
|     0x31 : "ITEM_ODD_POTION",
 | |
|     0x32 : "ITEM_POACHERS_SAW",
 | |
|     0x33 : "ITEM_BROKEN_GORONS_SWORD",
 | |
|     0x34 : "ITEM_PRESCRIPTION",
 | |
|     0x35 : "ITEM_EYEBALL_FROG",
 | |
|     0x36 : "ITEM_EYE_DROPS",
 | |
|     0x37 : "ITEM_CLAIM_CHECK",
 | |
|     0x38 : "ITEM_BOW_FIRE",
 | |
|     0x39 : "ITEM_BOW_ICE",
 | |
|     0x3A : "ITEM_BOW_LIGHT",
 | |
|     0x3B : "ITEM_SWORD_KOKIRI",
 | |
|     0x3C : "ITEM_SWORD_MASTER",
 | |
|     0x3D : "ITEM_SWORD_BIGGORON",
 | |
|     0x3E : "ITEM_SHIELD_DEKU",
 | |
|     0x3F : "ITEM_SHIELD_HYLIAN",
 | |
|     0x40 : "ITEM_SHIELD_MIRROR",
 | |
|     0x41 : "ITEM_TUNIC_KOKIRI",
 | |
|     0x42 : "ITEM_TUNIC_GORON",
 | |
|     0x43 : "ITEM_TUNIC_ZORA",
 | |
|     0x44 : "ITEM_BOOTS_KOKIRI",
 | |
|     0x45 : "ITEM_BOOTS_IRON",
 | |
|     0x46 : "ITEM_BOOTS_HOVER",
 | |
|     0x47 : "ITEM_BULLET_BAG_30",
 | |
|     0x48 : "ITEM_BULLET_BAG_40",
 | |
|     0x49 : "ITEM_BULLET_BAG_50",
 | |
|     0x4A : "ITEM_QUIVER_30",
 | |
|     0x4B : "ITEM_QUIVER_40",
 | |
|     0x4C : "ITEM_QUIVER_50",
 | |
|     0x4D : "ITEM_BOMB_BAG_20",
 | |
|     0x4E : "ITEM_BOMB_BAG_30",
 | |
|     0x4F : "ITEM_BOMB_BAG_40",
 | |
|     0x50 : "ITEM_STRENGTH_GORONS_BRACELET",
 | |
|     0x51 : "ITEM_STRENGTH_SILVER_GAUNTLETS",
 | |
|     0x52 : "ITEM_STRENGTH_GOLD_GAUNTLETS",
 | |
|     0x53 : "ITEM_SCALE_SILVER",
 | |
|     0x54 : "ITEM_SCALE_GOLDEN",
 | |
|     0x55 : "ITEM_GIANTS_KNIFE",
 | |
|     0x56 : "ITEM_ADULTS_WALLET",
 | |
|     0x57 : "ITEM_GIANTS_WALLET",
 | |
|     0x58 : "ITEM_DEKU_SEEDS",
 | |
|     0x59 : "ITEM_FISHING_POLE",
 | |
|     0x5A : "ITEM_SONG_MINUET",
 | |
|     0x5B : "ITEM_SONG_BOLERO",
 | |
|     0x5C : "ITEM_SONG_SERENADE",
 | |
|     0x5D : "ITEM_SONG_REQUIEM",
 | |
|     0x5E : "ITEM_SONG_NOCTURNE",
 | |
|     0x5F : "ITEM_SONG_PRELUDE",
 | |
|     0x60 : "ITEM_SONG_LULLABY",
 | |
|     0x61 : "ITEM_SONG_EPONA",
 | |
|     0x62 : "ITEM_SONG_SARIA",
 | |
|     0x63 : "ITEM_SONG_SUN",
 | |
|     0x64 : "ITEM_SONG_TIME",
 | |
|     0x65 : "ITEM_SONG_STORMS",
 | |
|     0x66 : "ITEM_MEDALLION_FOREST",
 | |
|     0x67 : "ITEM_MEDALLION_FIRE",
 | |
|     0x68 : "ITEM_MEDALLION_WATER",
 | |
|     0x69 : "ITEM_MEDALLION_SPIRIT",
 | |
|     0x6A : "ITEM_MEDALLION_SHADOW",
 | |
|     0x6B : "ITEM_MEDALLION_LIGHT",
 | |
|     0x6C : "ITEM_KOKIRI_EMERALD",
 | |
|     0x6D : "ITEM_GORON_RUBY",
 | |
|     0x6E : "ITEM_ZORA_SAPPHIRE",
 | |
|     0x6F : "ITEM_STONE_OF_AGONY",
 | |
|     0x70 : "ITEM_GERUDOS_CARD",
 | |
|     0x71 : "ITEM_SKULL_TOKEN",
 | |
|     0x72 : "ITEM_HEART_CONTAINER",
 | |
|     0x73 : "ITEM_HEART_PIECE",
 | |
|     0x74 : "ITEM_DUNGEON_BOSS_KEY",
 | |
|     0x75 : "ITEM_DUNGEON_COMPASS",
 | |
|     0x76 : "ITEM_DUNGEON_MAP",
 | |
|     0x77 : "ITEM_SMALL_KEY",
 | |
|     0x78 : "ITEM_MAGIC_JAR_SMALL",
 | |
|     0x79 : "ITEM_MAGIC_JAR_BIG",
 | |
|     0x7A : "ITEM_HEART_PIECE_2",
 | |
|     0x7B : "ITEM_INVALID_1",
 | |
|     0x7C : "ITEM_INVALID_2",
 | |
|     0x7D : "ITEM_INVALID_3",
 | |
|     0x7E : "ITEM_INVALID_4",
 | |
|     0x7F : "ITEM_INVALID_5",
 | |
|     0x80 : "ITEM_INVALID_6",
 | |
|     0x81 : "ITEM_INVALID_7",
 | |
|     0x82 : "ITEM_MILK",
 | |
|     0x83 : "ITEM_RECOVERY_HEART",
 | |
|     0x84 : "ITEM_RUPEE_GREEN",
 | |
|     0x85 : "ITEM_RUPEE_BLUE",
 | |
|     0x86 : "ITEM_RUPEE_RED",
 | |
|     0x87 : "ITEM_RUPEE_PURPLE",
 | |
|     0x88 : "ITEM_RUPEE_GOLD",
 | |
|     0x89 : "ITEM_INVALID_8",
 | |
|     0x8A : "ITEM_DEKU_STICKS_5",
 | |
|     0x8B : "ITEM_DEKU_STICKS_10",
 | |
|     0x8C : "ITEM_DEKU_NUTS_5",
 | |
|     0x8D : "ITEM_DEKU_NUTS_10",
 | |
|     0x8E : "ITEM_BOMBS_5",
 | |
|     0x8F : "ITEM_BOMBS_10",
 | |
|     0x90 : "ITEM_BOMBS_20",
 | |
|     0x91 : "ITEM_BOMBS_30",
 | |
|     0x92 : "ITEM_ARROWS_5",
 | |
|     0x93 : "ITEM_ARROWS_10",
 | |
|     0x94 : "ITEM_ARROWS_30",
 | |
|     0x95 : "ITEM_DEKU_SEEDS_30",
 | |
|     0x96 : "ITEM_BOMBCHUS_5",
 | |
|     0x97 : "ITEM_BOMBCHUS_20",
 | |
|     0x98 : "ITEM_DEKU_STICK_UPGRADE_20",
 | |
|     0x99 : "ITEM_DEKU_STICK_UPGRADE_30",
 | |
|     0x9A : "ITEM_DEKU_NUT_UPGRADE_30",
 | |
|     0x9B : "ITEM_DEKU_NUT_UPGRADE_40",
 | |
|     0xFC : "ITEM_SWORD_CS",
 | |
|     0xFE : "ITEM_NONE_FE",
 | |
|     0xFF : "ITEM_NONE",
 | |
| }
 | |
| 
 | |
| sfx_ids = {
 | |
|     0x0000 : "NA_SE_PL_WALK_GROUND",
 | |
|     0x0001 : "NA_SE_PL_WALK_SAND",
 | |
|     0x0002 : "NA_SE_PL_WALK_CONCRETE",
 | |
|     0x0003 : "NA_SE_PL_WALK_DIRT",
 | |
|     0x0004 : "NA_SE_PL_WALK_WATER0",
 | |
|     0x0005 : "NA_SE_PL_WALK_WATER1",
 | |
|     0x0006 : "NA_SE_PL_WALK_WATER2",
 | |
|     0x0007 : "NA_SE_PL_WALK_MAGMA",
 | |
|     0x0008 : "NA_SE_PL_WALK_GRASS",
 | |
|     0x0009 : "NA_SE_PL_WALK_IRON",
 | |
|     0x000A : "NA_SE_PL_WALK_LADDER",
 | |
|     0x000B : "NA_SE_PL_WALK_GLASS",
 | |
|     0x000C : "NA_SE_PL_WALK_WALL",
 | |
|     0x000D : "NA_SE_PL_WALK_HEAVYBOOTS",
 | |
|     0x000E : "NA_SE_PL_DUMMY_14",
 | |
|     0x000F : "NA_SE_PL_WALK_ICE",
 | |
|     0x0010 : "NA_SE_PL_JUMP",
 | |
|     0x0011 : "NA_SE_PL_JUMP_SAND",
 | |
|     0x0012 : "NA_SE_PL_JUMP_CONCRETE",
 | |
|     0x0013 : "NA_SE_PL_JUMP_DIRT",
 | |
|     0x0014 : "NA_SE_PL_JUMP_WATER0",
 | |
|     0x0015 : "NA_SE_PL_JUMP_WATER1",
 | |
|     0x0016 : "NA_SE_PL_JUMP_WATER2",
 | |
|     0x0017 : "NA_SE_PL_JUMP_MAGMA",
 | |
|     0x0018 : "NA_SE_PL_JUMP_GRASS",
 | |
|     0x0019 : "NA_SE_PL_JUMP_IRON",
 | |
|     0x001A : "NA_SE_PL_JUMP_LADDER",
 | |
|     0x001B : "NA_SE_PL_JUMP_GLASS",
 | |
|     0x001C : "NA_SE_PL_DUMMY28",
 | |
|     0x001D : "NA_SE_PL_JUMP_HEAVYBOOTS",
 | |
|     0x001E : "NA_SE_PL_DUMMY30",
 | |
|     0x001F : "NA_SE_PL_JUMP_ICE",
 | |
|     0x0020 : "NA_SE_PL_LAND",
 | |
|     0x0021 : "NA_SE_PL_LAND_SAND",
 | |
|     0x0022 : "NA_SE_PL_LAND_CONCRETE",
 | |
|     0x0023 : "NA_SE_PL_LAND_DIRT",
 | |
|     0x0024 : "NA_SE_PL_LAND_WATER0",
 | |
|     0x0025 : "NA_SE_PL_LAND_WATER1",
 | |
|     0x0026 : "NA_SE_PL_LAND_WATER2",
 | |
|     0x0027 : "NA_SE_PL_LAND_MAGMA",
 | |
|     0x0028 : "NA_SE_PL_LAND_GRASS",
 | |
|     0x0029 : "NA_SE_PL_LAND_IRON",
 | |
|     0x002A : "NA_SE_PL_LAND_LADDER",
 | |
|     0x002B : "NA_SE_PL_LAND_GLASS",
 | |
|     0x002C : "NA_SE_PL_DUMMY_44",
 | |
|     0x002D : "NA_SE_PL_LAND_HEAVYBOOTS",
 | |
|     0x002E : "NA_SE_PL_DUMMY_46",
 | |
|     0x002F : "NA_SE_PL_LAND_ICE",
 | |
|     0x0030 : "NA_SE_PL_SLIPDOWN",
 | |
|     0x0031 : "NA_SE_PL_CLIMB_CLIFF",
 | |
|     0x0032 : "NA_SE_PL_SIT_ON_HORSE",
 | |
|     0x0033 : "NA_SE_PL_GET_OFF_HORSE",
 | |
|     0x0034 : "NA_SE_PL_TAKE_OUT_SHIELD",
 | |
|     0x0035 : "NA_SE_PL_CHANGE_ARMS",
 | |
|     0x0036 : "NA_SE_PL_CATCH_BOOMERANG",
 | |
|     0x0037 : "NA_SE_PL_DUMMY_55",
 | |
|     0x0038 : "NA_SE_PL_DUMMY_56",
 | |
|     0x0039 : "NA_SE_PL_SWIM",
 | |
|     0x003A : "NA_SE_PL_THROW",
 | |
|     0x003B : "NA_SE_PL_BODY_BOUND",
 | |
|     0x003C : "NA_SE_PL_ROLL",
 | |
|     0x003D : "NA_SE_PL_SKIP",
 | |
|     0x003E : "NA_SE_PL_BODY_HIT",
 | |
|     0x003F : "NA_SE_PL_DAMAGE",
 | |
|     0x0040 : "NA_SE_PL_SLIP",
 | |
|     0x0041 : "NA_SE_PL_SLIP_SAND",
 | |
|     0x0042 : "NA_SE_PL_SLIP_CONCRETE",
 | |
|     0x0043 : "NA_SE_PL_SLIP_DIRT",
 | |
|     0x0044 : "NA_SE_PL_SLIP_WATER0",
 | |
|     0x0045 : "NA_SE_PL_SLIP_WATER1",
 | |
|     0x0046 : "NA_SE_PL_SLIP_WATER2",
 | |
|     0x0047 : "NA_SE_PL_SLIP_MAGMA",
 | |
|     0x0048 : "NA_SE_PL_SLIP_GRASS",
 | |
|     0x0049 : "NA_SE_PL_SLIP_IRON",
 | |
|     0x004A : "NA_SE_PL_SLIP_LADDER",
 | |
|     0x004B : "NA_SE_PL_SLIP_GLASS",
 | |
|     0x004C : "NA_SE_PL_DUMMY76",
 | |
|     0x004D : "NA_SE_PL_SLIP_HEAVYBOOTS",
 | |
|     0x004E : "NA_SE_PL_DUMMY78",
 | |
|     0x004F : "NA_SE_PL_SLIP_ICE",
 | |
|     0x0050 : "NA_SE_PL_BOUND",
 | |
|     0x0051 : "NA_SE_PL_BOUND_SAND",
 | |
|     0x0052 : "NA_SE_PL_BOUND_CONCRETE",
 | |
|     0x0053 : "NA_SE_PL_BOUND_DIRT",
 | |
|     0x0054 : "NA_SE_PL_BOUND_WATER0",
 | |
|     0x0055 : "NA_SE_PL_BOUND_WATER1",
 | |
|     0x0056 : "NA_SE_PL_BOUND_WATER2",
 | |
|     0x0057 : "NA_SE_PL_BOUND_MAGMA",
 | |
|     0x0058 : "NA_SE_PL_BOUND_GRASS",
 | |
|     0x0059 : "NA_SE_PL_BOUND_IRON",
 | |
|     0x005A : "NA_SE_PL_BOUND_LADDER",
 | |
|     0x005B : "NA_SE_PL_BOUND_WOOD",
 | |
|     0x005C : "NA_SE_PL_DUMMY_92",
 | |
|     0x005D : "NA_SE_PL_BOUND_HEAVYBOOTS",
 | |
|     0x005E : "NA_SE_PL_DUMMY_94",
 | |
|     0x005F : "NA_SE_PL_BOUND_ICE",
 | |
|     0x0060 : "NA_SE_PL_DUMMY_96",
 | |
|     0x0061 : "NA_SE_PL_DUMMY_97",
 | |
|     0x0062 : "NA_SE_PL_DUMMY_98",
 | |
|     0x0063 : "NA_SE_PL_FACE_UP",
 | |
|     0x0064 : "NA_SE_PL_DIVE_BUBBLE",
 | |
|     0x0065 : "NA_SE_PL_MOVE_BUBBLE",
 | |
|     0x0066 : "NA_SE_PL_METALEFFECT_KID",
 | |
|     0x0067 : "NA_SE_PL_METALEFFECT_ADULT",
 | |
|     0x0068 : "NA_SE_PL_SPARK",
 | |
|     0x0069 : "NA_SE_PL_PULL_UP_PLANT",
 | |
|     0x006A : "NA_SE_PL_PULL_UP_ROCK",
 | |
|     0x006B : "NA_SE_PL_IN_BUBBLE",
 | |
|     0x006C : "NA_SE_PL_PULL_UP_BIGROCK",
 | |
|     0x006D : "NA_SE_PL_SWORD_CHARGE",
 | |
|     0x006E : "NA_SE_PL_FREEZE",
 | |
|     0x006F : "NA_SE_PL_PULL_UP_POT",
 | |
|     0x0070 : "NA_SE_PL_KNOCK",
 | |
|     0x0071 : "NA_SE_PL_CALM_HIT",
 | |
|     0x0072 : "NA_SE_PL_CALM_PAT",
 | |
|     0x0073 : "NA_SE_PL_SUBMERGE",
 | |
|     0x0074 : "NA_SE_PL_FREEZE_S",
 | |
|     0x0075 : "NA_SE_PL_ICE_BROKEN",
 | |
|     0x0076 : "NA_SE_PL_SLIP_ICE_LELEL",
 | |
|     0x0077 : "NA_SE_PL_PUT_OUT_ITEM",
 | |
|     0x0078 : "NA_SE_PL_PULL_UP_WOODBOX",
 | |
|     0x0079 : "NA_SE_PL_MAGIC_FIRE",
 | |
|     0x007A : "NA_SE_PL_MAGIC_WIND_NORMAL",
 | |
|     0x007B : "NA_SE_PL_MAGIC_WIND_WARP",
 | |
|     0x007C : "NA_SE_PL_MAGIC_SOUL_NORMAL",
 | |
|     0x007D : "NA_SE_PL_ARROW_CHARGE_FIRE",
 | |
|     0x007E : "NA_SE_PL_ARROW_CHARGE_ICE",
 | |
|     0x007F : "NA_SE_PL_ARROW_CHARGE_LIGHT",
 | |
|     0x0080 : "NA_SE_PL_DUMMY_128",
 | |
|     0x0081 : "NA_SE_PL_DUMMY_129",
 | |
|     0x0082 : "NA_SE_PL_DUMMY_130",
 | |
|     0x0083 : "NA_SE_PL_PULL_UP_RUTO",
 | |
|     0x0084 : "NA_SE_PL_DUMMY_132",
 | |
|     0x0085 : "NA_SE_PL_DUMMY_133",
 | |
|     0x0086 : "NA_SE_PL_DUMMY_134",
 | |
|     0x0087 : "NA_SE_PL_DUMMY_135",
 | |
|     0x0088 : "NA_SE_PL_DUMMY_136",
 | |
|     0x0089 : "NA_SE_PL_DUMMY_137",
 | |
|     0x008A : "NA_SE_PL_DUMMY_138",
 | |
|     0x008B : "NA_SE_PL_DUMMY_139",
 | |
|     0x008C : "NA_SE_PL_DUMMY_140",
 | |
|     0x008D : "NA_SE_PL_DUMMY_141",
 | |
|     0x008E : "NA_SE_PL_DUMMY_142",
 | |
|     0x008F : "NA_SE_PL_DUMMY_143",
 | |
|     0x0090 : "NA_SE_PL_DUMMY_144",
 | |
|     0x0091 : "NA_SE_PL_DUMMY_145",
 | |
|     0x0092 : "NA_SE_PL_DUMMY_146",
 | |
|     0x0093 : "NA_SE_PL_DUMMY_147",
 | |
|     0x0094 : "NA_SE_PL_DUMMY_148",
 | |
|     0x0095 : "NA_SE_PL_DUMMY_149",
 | |
|     0x0096 : "NA_SE_PL_DUMMY_150",
 | |
|     0x0097 : "NA_SE_PL_DUMMY_151",
 | |
|     0x0098 : "NA_SE_PL_DUMMY_152",
 | |
|     0x0099 : "NA_SE_PL_DUMMY_153",
 | |
|     0x009A : "NA_SE_PL_DUMMY_154",
 | |
|     0x009B : "NA_SE_PL_DUMMY_155",
 | |
|     0x009C : "NA_SE_PL_DUMMY_156",
 | |
|     0x009D : "NA_SE_PL_DUMMY_157",
 | |
|     0x009E : "NA_SE_PL_DUMMY_158",
 | |
|     0x009F : "NA_SE_PL_DUMMY_159",
 | |
|     0x00A0 : "NA_SE_PL_DUMMY_160",
 | |
|     0x00A1 : "NA_SE_PL_DUMMY_161",
 | |
|     0x00A2 : "NA_SE_PL_DUMMY_162",
 | |
|     0x00A3 : "NA_SE_PL_DUMMY_163",
 | |
|     0x00A4 : "NA_SE_PL_DUMMY_164",
 | |
|     0x00A5 : "NA_SE_PL_DUMMY_165",
 | |
|     0x00A6 : "NA_SE_PL_DUMMY_166",
 | |
|     0x00A7 : "NA_SE_PL_DUMMY_167",
 | |
|     0x00A8 : "NA_SE_PL_DUMMY_168",
 | |
|     0x00A9 : "NA_SE_PL_DUMMY_169",
 | |
|     0x00AA : "NA_SE_PL_DUMMY_170",
 | |
|     0x00AB : "NA_SE_PL_DUMMY_171",
 | |
|     0x00AC : "NA_SE_PL_DUMMY_172",
 | |
|     0x00AD : "NA_SE_PL_DUMMY_173",
 | |
|     0x00AE : "NA_SE_PL_DUMMY_174",
 | |
|     0x00AF : "NA_SE_PL_DUMMY_175",
 | |
|     0x00B0 : "NA_SE_PL_CRAWL",
 | |
|     0x00B1 : "NA_SE_PL_CRAWL_SAND",
 | |
|     0x00B2 : "NA_SE_PL_CRAWL_CONCRETE",
 | |
|     0x00B3 : "NA_SE_PL_CRAWL_DIRT",
 | |
|     0x00B4 : "NA_SE_PL_CRAWL_WATER0",
 | |
|     0x00B5 : "NA_SE_PL_DUMMY_181",
 | |
|     0x00B6 : "NA_SE_PL_DUMMY_182",
 | |
|     0x00B7 : "NA_SE_PL_DUMMY_183",
 | |
|     0x00B8 : "NA_SE_PL_DUMMY_184",
 | |
|     0x00B9 : "NA_SE_PL_DUMMY_185",
 | |
|     0x00BA : "NA_SE_PL_DUMMY_186",
 | |
|     0x00BB : "NA_SE_PL_CRAWL_WOOD",
 | |
|     0x00BC : "NA_SE_PL_CRAWL_ICE",
 | |
|     0x00BD : "NA_SE_PL_DUMMY_189",
 | |
|     0x00BE : "NA_SE_PL_DUMMY_190",
 | |
|     0x00BF : "NA_SE_PL_DUMMY_191",
 | |
|     0x00C0 : "NA_SE_PL_MAGIC_SOUL_FLASH",
 | |
|     0x00C1 : "NA_SE_PL_ROLL_DUST",
 | |
|     0x00C2 : "NA_SE_PL_DUMMY_192",
 | |
|     0x00C3 : "NA_SE_PL_MAGIC_SOUL_BALL",
 | |
|     0x00C4 : "NA_SE_PL_SPIRAL_HEAL_BEAM",
 | |
|     0x00C5 : "NA_SE_PL_BOUND_NOWEAPON",
 | |
|     0x00C6 : "NA_SE_PL_PLANT_GROW_UP",
 | |
|     0x00C7 : "NA_SE_PL_PLANT_TALLER",
 | |
|     0x00C8 : "NA_SE_PL_MAGIC_WIND_VANISH",
 | |
|     0x00C9 : "NA_SE_PL_HOBBERBOOTS_LV",
 | |
|     0x00CA : "NA_SE_PL_PLANT_MOVE",
 | |
|     0x00CB : "NA_SE_EV_WALL_MOVE_SP",
 | |
|     0x00CC : "NA_SE_PL_DUMMY_204",
 | |
|     0x00CD : "NA_SE_PL_DUMMY_205",
 | |
|     0x00CE : "NA_SE_PL_DUMMY_206",
 | |
|     0x00CF : "NA_SE_PL_DUMMY_207",
 | |
|     0x00D0 : "NA_SE_PL_SLIP_LEVEL",
 | |
|     0x00D1 : "NA_SE_PL_SLIP_SAND_LEVEL",
 | |
|     0x00D2 : "NA_SE_PL_SLIP_CONCRETE_LEVEL",
 | |
|     0x00D3 : "NA_SE_PL_SLIP_DIRT_LEVEL",
 | |
|     0x00D4 : "NA_SE_PL_SLIP_WATER0_LEVEL",
 | |
|     0x00D5 : "NA_SE_PL_SLIP_WATER1_LEVEL",
 | |
|     0x00D6 : "NA_SE_PL_SLIP_WATER2_LEVEL",
 | |
|     0x00D7 : "NA_SE_PL_SLIP_MAGMA_LEVEL",
 | |
|     0x00D8 : "NA_SE_PL_SLIP_GRASS_LEVEL",
 | |
|     0x00D9 : "NA_SE_PL_SLIP_IRON_LEVEL",
 | |
|     0x00DA : "NA_SE_PL_SLIP_GLASS_LEVEL",
 | |
|     0x00DB : "NA_SE_PL_SLIP_WOOD_LEVEL",
 | |
|     0x00DC : "NA_SE_PL_DUMMY_220",
 | |
|     0x00DD : "NA_SE_PL_DUMMY_221",
 | |
|     0x00DE : "NA_SE_PL_SLIP_HEAVYBOOTS_LEVEL",
 | |
|     0x00DF : "NA_SE_PL_SLIP_ICE_LEVEL",
 | |
|     0x1000 : "NA_SE_IT_SWORD_IMPACT",
 | |
|     0x1001 : "NA_SE_IT_SWORD_SWING",
 | |
|     0x1002 : "NA_SE_IT_SWORD_PUTAWAY",
 | |
|     0x1003 : "NA_SE_IT_SWORD_PICKOUT",
 | |
|     0x1004 : "NA_SE_IT_ARROW_SHOT",
 | |
|     0x1005 : "NA_SE_IT_BOOMERANG_THROW",
 | |
|     0x1006 : "NA_SE_IT_SHIELD_BOUND",
 | |
|     0x1007 : "NA_SE_IT_BOW_DRAW",
 | |
|     0x1008 : "NA_SE_IT_SHIELD_REFLECT_SW",
 | |
|     0x1009 : "NA_SE_IT_ARROW_STICK_HRAD",
 | |
|     0x100A : "NA_SE_IT_HAMMER_HIT",
 | |
|     0x100B : "NA_SE_IT_HOOKSHOT_CHAIN",
 | |
|     0x100C : "NA_SE_IT_SHIELD_REFLECT_MG",
 | |
|     0x100D : "NA_SE_IT_BOMB_IGNIT",
 | |
|     0x100E : "NA_SE_IT_BOMB_EXPLOSION",
 | |
|     0x100F : "NA_SE_IT_BOMB_UNEXPLOSION",
 | |
|     0x1010 : "NA_SE_IT_BOOMERANG_FLY",
 | |
|     0x1011 : "NA_SE_IT_SWORD_STRIKE",
 | |
|     0x1012 : "NA_SE_IT_HAMMER_SWING",
 | |
|     0x1013 : "NA_SE_IT_HOOKSHOT_REFLECT",
 | |
|     0x1014 : "NA_SE_IT_ARROW_STICK_CRE",
 | |
|     0x1015 : "NA_SE_IT_ARROW_STICK_OBJ",
 | |
|     0x1016 : "NA_SE_IT_DUMMY",
 | |
|     0x1017 : "NA_SE_IT_DUMMY2",
 | |
|     0x1018 : "NA_SE_IT_SWORD_SWING_HARD",
 | |
|     0x1019 : "NA_SE_IT_DUMMY3",
 | |
|     0x101A : "NA_SE_IT_WALL_HIT_HARD",
 | |
|     0x101B : "NA_SE_IT_WALL_HIT_SOFT",
 | |
|     0x101C : "NA_SE_IT_STONE_HIT",
 | |
|     0x101D : "NA_SE_IT_WOODSTICK_BROKEN",
 | |
|     0x101E : "NA_SE_IT_LASH",
 | |
|     0x101F : "NA_SE_IT_SHIELD_POSTURE",
 | |
|     0x1020 : "NA_SE_IT_SLING_SHOT",
 | |
|     0x1021 : "NA_SE_IT_SLING_DRAW",
 | |
|     0x1022 : "NA_SE_IT_SWORD_CHARGE",
 | |
|     0x1023 : "NA_SE_IT_ROLLING_CUT",
 | |
|     0x1024 : "NA_SE_IT_SWORD_STRIKE_HARD",
 | |
|     0x1025 : "NA_SE_IT_SLING_REFLECT",
 | |
|     0x1026 : "NA_SE_IT_SHIELD_REMOVE",
 | |
|     0x1027 : "NA_SE_IT_HOOKSHOT_READY",
 | |
|     0x1028 : "NA_SE_IT_HOOKSHOT_RECEIVE",
 | |
|     0x1029 : "NA_SE_IT_HOOKSHOT_STICK_OBJ",
 | |
|     0x102A : "NA_SE_IT_SWORD_REFLECT_MG",
 | |
|     0x102B : "NA_SE_IT_DEKU",
 | |
|     0x102C : "NA_SE_IT_WALL_HIT_BUYO",
 | |
|     0x102D : "NA_SE_IT_SWORD_PUTAWAY_STN",
 | |
|     0x102E : "NA_SE_IT_ROLLING_CUT_LV1",
 | |
|     0x102F : "NA_SE_IT_ROLLING_CUT_LV2",
 | |
|     0x1030 : "NA_SE_IT_BOW_FLICK",
 | |
|     0x1031 : "NA_SE_IT_BOMBCHU_MOVE",
 | |
|     0x1032 : "NA_SE_IT_SHIELD_CHARGE_LV1",
 | |
|     0x1033 : "NA_SE_IT_SHIELD_CHARGE_LV2",
 | |
|     0x1034 : "NA_SE_IT_SHIELD_CHARGE_LV3",
 | |
|     0x1035 : "NA_SE_IT_SLING_FLICK",
 | |
|     0x1036 : "NA_SE_IT_SWORD_STICK_STN",
 | |
|     0x1037 : "NA_SE_IT_REFLECTION_WOOD",
 | |
|     0x1038 : "NA_SE_IT_SHIELD_REFLECT_MG2",
 | |
|     0x1039 : "NA_SE_IT_MAGIC_ARROW_SHOT",
 | |
|     0x103A : "NA_SE_IT_EXPLOSION_FRAME",
 | |
|     0x103B : "NA_SE_IT_EXPLOSION_ICE",
 | |
|     0x103C : "NA_SE_IT_EXPLOSION_LIGHT",
 | |
|     0x103D : "NA_SE_IT_FISHING_REEL_SLOW",
 | |
|     0x103E : "NA_SE_IT_FISHING_REEL_HIGH",
 | |
|     0x103F : "NA_SE_IT_PULL_FISHING_ROD",
 | |
|     0x1040 : "NA_SE_IT_DM_FLYING_GOD_PASS",
 | |
|     0x1041 : "NA_SE_IT_DM_FLYING_GOD_DASH",
 | |
|     0x1042 : "NA_SE_IT_DM_RING_EXPLOSION",
 | |
|     0x1043 : "NA_SE_IT_DM_RING_GATHER",
 | |
|     0x1044 : "NA_SE_IT_INGO_HORSE_NEIGH",
 | |
|     0x1045 : "NA_SE_IT_EARTHQUAKE",
 | |
|     0x1046 : "NA_SE_IT_DUMMY4",
 | |
|     0x1047 : "NA_SE_IT_KAKASHI_JUMP",
 | |
|     0x1048 : "NA_SE_IT_FLAME",
 | |
|     0x1049 : "NA_SE_IT_SHIELD_BEAM",
 | |
|     0x104A : "NA_SE_IT_FISHING_HIT",
 | |
|     0x104B : "NA_SE_IT_GOODS_APPEAR",
 | |
|     0x104C : "NA_SE_IT_MAJIN_SWORD_BROKEN",
 | |
|     0x104D : "NA_SE_IT_HAND_CLAP",
 | |
|     0x104E : "NA_SE_IT_MASTER_SWORD_SWING",
 | |
|     0x104F : "NA_SE_IT_DUMMY5",
 | |
|     0x2000 : "NA_SE_EV_DOOR_OPEN",
 | |
|     0x2001 : "NA_SE_EV_DOOR_CLOSE",
 | |
|     0x2002 : "NA_SE_EV_EXPLOSION",
 | |
|     0x2003 : "NA_SE_EV_HORSE_WALK",
 | |
|     0x2004 : "NA_SE_EV_HORSE_RUN",
 | |
|     0x2005 : "NA_SE_EV_HORSE_NEIGH",
 | |
|     0x2006 : "NA_SE_EV_RIVER_STREAM",
 | |
|     0x2007 : "NA_SE_EV_WATER_WALL_BIG",
 | |
|     0x2008 : "NA_SE_EV_OUT_OF_WATER",
 | |
|     0x2009 : "NA_SE_EV_DIVE_WATER",
 | |
|     0x200A : "NA_SE_EV_ROCK_SLIDE",
 | |
|     0x200B : "NA_SE_EV_MAGMA_LEVEL",
 | |
|     0x200C : "NA_SE_EV_BRIDGE_OPEN",
 | |
|     0x200D : "NA_SE_EV_BRIDGE_CLOSE",
 | |
|     0x200E : "NA_SE_EV_BRIDGE_OPEN_STOP",
 | |
|     0x200F : "NA_SE_EV_BRIDGE_CLOSE_STOP",
 | |
|     0x2010 : "NA_SE_EV_WALL_BROKEN",
 | |
|     0x2011 : "NA_SE_EV_CHICKEN_CRY_N",
 | |
|     0x2012 : "NA_SE_EV_CHICKEN_CRY_A",
 | |
|     0x2013 : "NA_SE_EV_CHICKEN_CRY_M",
 | |
|     0x2014 : "NA_SE_EV_SLIDE_DOOR_OPEN",
 | |
|     0x2015 : "NA_SE_EV_FOOT_SWITCH",
 | |
|     0x2016 : "NA_SE_EV_HORSE_GROAN",
 | |
|     0x2017 : "NA_SE_EV_BOMB_DROP_WATER",
 | |
|     0x2018 : "NA_SE_EV_HORSE_JUMP",
 | |
|     0x2019 : "NA_SE_EV_HORSE_LAND",
 | |
|     0x201A : "NA_SE_EV_HORSE_SLIP",
 | |
|     0x201B : "NA_SE_EV_FAIRY_DASH",
 | |
|     0x201C : "NA_SE_EV_SLIDE_DOOR_CLOSE",
 | |
|     0x201D : "NA_SE_EV_STONE_BOUND",
 | |
|     0x201E : "NA_SE_EV_STONE_STATUE_OPEN",
 | |
|     0x201F : "NA_SE_EV_TBOX_UNLOCK",
 | |
|     0x2020 : "NA_SE_EV_TBOX_OPEN",
 | |
|     0x2021 : "NA_SE_SY_TIMER",
 | |
|     0x2022 : "NA_SE_EV_FLAME_IGNITION",
 | |
|     0x2023 : "NA_SE_EV_SPEAR_HIT",
 | |
|     0x2024 : "NA_SE_EV_ELEVATOR_MOVE",
 | |
|     0x2025 : "NA_SE_EV_WARP_HOLE",
 | |
|     0x2026 : "NA_SE_EV_LINK_WARP",
 | |
|     0x2027 : "NA_SE_EV_PILLAR_SINK",
 | |
|     0x2028 : "NA_SE_EV_WATER_WALL",
 | |
|     0x2029 : "NA_SE_EV_RIVER_STREAM_S",
 | |
|     0x202A : "NA_SE_EV_RIVER_STREAM_F",
 | |
|     0x202B : "NA_SE_EV_HORSE_LAND2",
 | |
|     0x202C : "NA_SE_EV_HORSE_SANDDUST",
 | |
|     0x202D : "NA_SE_EV_DUMMY45",
 | |
|     0x202E : "NA_SE_EV_LIGHTNING",
 | |
|     0x202F : "NA_SE_EV_BOMB_BOUND",
 | |
|     0x2030 : "NA_SE_EV_WATERDROP",
 | |
|     0x2031 : "NA_SE_EV_TORCH",
 | |
|     0x2032 : "NA_SE_EV_MAGMA_LEVEL_M",
 | |
|     0x2033 : "NA_SE_EV_FIRE_PILLAR",
 | |
|     0x2034 : "NA_SE_EV_FIRE_PLATE",
 | |
|     0x2035 : "NA_SE_EV_BLOCK_BOUND",
 | |
|     0x2036 : "NA_SE_EV_METALDOOR_SLIDE",
 | |
|     0x2037 : "NA_SE_EV_METALDOOR_STOP",
 | |
|     0x2038 : "NA_SE_EV_BLOCK_SHAKE",
 | |
|     0x2039 : "NA_SE_EV_BOX_BREAK",
 | |
|     0x203A : "NA_SE_EV_HAMMER_SWITCH",
 | |
|     0x203B : "NA_SE_EV_MAGMA_LEVEL_L",
 | |
|     0x203C : "NA_SE_EV_SPEAR_FENCE",
 | |
|     0x203D : "NA_SE_EV_GANON_HORSE_NEIGH",
 | |
|     0x203E : "NA_SE_EV_GANON_HORSE_GROAN",
 | |
|     0x203F : "NA_SE_EV_FANTOM_WARP_S",
 | |
|     0x2040 : "NA_SE_EV_FANTOM_WARP_L",
 | |
|     0x2041 : "NA_SE_EV_FOUNTAIN",
 | |
|     0x2042 : "NA_SE_EV_KID_HORSE_WALK",
 | |
|     0x2043 : "NA_SE_EV_KID_HORSE_RUN",
 | |
|     0x2044 : "NA_SE_EV_KID_HORSE_NEIGH",
 | |
|     0x2045 : "NA_SE_EV_KID_HORSE_GROAN",
 | |
|     0x2046 : "NA_SE_EV_WHITE_OUT",
 | |
|     0x2047 : "NA_SE_EV_LIGHT_GATHER",
 | |
|     0x2048 : "NA_SE_EV_TREE_CUT",
 | |
|     0x2049 : "NA_SE_EV_VOLCANO",
 | |
|     0x204A : "NA_SE_EV_GUILLOTINE_UP",
 | |
|     0x204B : "NA_SE_EV_GUILLOTINE_BOUND",
 | |
|     0x204C : "NA_SE_EV_ROLLCUTTER_MOTOR",
 | |
|     0x204D : "NA_SE_EV_CHINETRAP_DOWN",
 | |
|     0x204E : "NA_SE_EV_PLANT_BROKEN",
 | |
|     0x204F : "NA_SE_EV_SHIP_BELL",
 | |
|     0x2050 : "NA_SE_EV_FLUTTER_FLAG",
 | |
|     0x2051 : "NA_SE_EV_TRAP_BOUND",
 | |
|     0x2052 : "NA_SE_EV_ROCK_BROKEN",
 | |
|     0x2053 : "NA_SE_EV_FANTOM_WARP_S2",
 | |
|     0x2054 : "NA_SE_EV_FANTOM_WARP_L2",
 | |
|     0x2055 : "NA_SE_EV_COFFIN_CAP_OPEN",
 | |
|     0x2056 : "NA_SE_EV_COFFIN_CAP_BOUND",
 | |
|     0x2057 : "NA_SE_EV_WIND_TRAP",
 | |
|     0x2058 : "NA_SE_EV_TRAP_OBJ_SLIDE",
 | |
|     0x2059 : "NA_SE_EV_METALDOOR_OPEN",
 | |
|     0x205A : "NA_SE_EV_METALDOOR_CLOSE",
 | |
|     0x205B : "NA_SE_EV_BURN_OUT",
 | |
|     0x205C : "NA_SE_EV_BLOCKSINK",
 | |
|     0x205D : "NA_SE_EV_CROWD",
 | |
|     0x205E : "NA_SE_EV_WATER_LEVEL_DOWN",
 | |
|     0x205F : "NA_SE_EV_NAVY_VANISH",
 | |
|     0x2060 : "NA_SE_EV_LADDER_DOUND",
 | |
|     0x2061 : "NA_SE_EV_WEB_VIBRATION",
 | |
|     0x2062 : "NA_SE_EV_WEB_BROKEN",
 | |
|     0x2063 : "NA_SE_EV_ROLL_STAND",
 | |
|     0x2064 : "NA_SE_EV_BUYODOOR_OPEN",
 | |
|     0x2065 : "NA_SE_EV_BUYODOOR_CLOSE",
 | |
|     0x2066 : "NA_SE_EV_WOODDOOR_OPEN",
 | |
|     0x2067 : "NA_SE_EV_METALGATE_OPEN",
 | |
|     0x2068 : "NA_SE_IT_SCOOP_UP_WATER",
 | |
|     0x2069 : "NA_SE_EV_FISH_LEAP",
 | |
|     0x206A : "NA_SE_EV_KAKASHI_SWING",
 | |
|     0x206B : "NA_SE_EV_KAKASHI_ROLL",
 | |
|     0x206C : "NA_SE_EV_BOTTLE_CAP_OPEN",
 | |
|     0x206D : "NA_SE_EV_JABJAB_BREATHE",
 | |
|     0x206E : "NA_SE_EV_SPIRIT_STONE",
 | |
|     0x206F : "NA_SE_EV_TRIFORCE_FLASH",
 | |
|     0x2070 : "NA_SE_EV_FALL_DOWN_DIRT",
 | |
|     0x2071 : "NA_SE_EV_NAVY_FLY",
 | |
|     0x2072 : "NA_SE_EV_NAVY_CRASH",
 | |
|     0x2073 : "NA_SE_EV_WOOD_HIT",
 | |
|     0x2074 : "NA_SE_EV_SCOOPUP_WATER",
 | |
|     0x2075 : "NA_SE_EV_DROP_FALL",
 | |
|     0x2076 : "NA_SE_EV_WOOD_GEAR",
 | |
|     0x2077 : "NA_SE_EV_TREE_SWING",
 | |
|     0x2078 : "NA_SE_EV_HORSE_RUN_LEVEL",
 | |
|     0x2079 : "NA_SE_EV_ELEVATOR_MOVE2",
 | |
|     0x207A : "NA_SE_EV_ELEVATOR_STOP",
 | |
|     0x207B : "NA_SE_EV_TRE_BOX_APPEAR",
 | |
|     0x207C : "NA_SE_EV_CHAIN_KEY_UNLOCK",
 | |
|     0x207D : "NA_SE_EV_SPINE_TRAP_MOVE",
 | |
|     0x207E : "NA_SE_EV_HEALING",
 | |
|     0x207F : "NA_SE_EV_GREAT_FAIRY_APPEAR",
 | |
|     0x2080 : "NA_SE_EV_GREAT_FAIRY_VANISH",
 | |
|     0x2081 : "NA_SE_EV_RED_EYE",
 | |
|     0x2082 : "NA_SE_EV_ROLL_STAND_2",
 | |
|     0x2083 : "NA_SE_EV_WALL_SLIDE",
 | |
|     0x2084 : "NA_SE_EV_TRE_BOX_FLASH",
 | |
|     0x2085 : "NA_SE_EV_WINDMILL_LEVEL",
 | |
|     0x2086 : "NA_SE_EV_GOTO_HEAVEN",
 | |
|     0x2087 : "NA_SE_EV_POT_BROKEN",
 | |
|     0x2088 : "NA_SE_PL_PUT_DOWN_POT",
 | |
|     0x2089 : "NA_SE_EV_DIVE_INTO_WATER",
 | |
|     0x208A : "NA_SE_EV_JUMP_OUT_WATER",
 | |
|     0x208B : "NA_SE_EV_GOD_FLYING",
 | |
|     0x208C : "NA_SE_EV_TRIFORCE",
 | |
|     0x208D : "NA_SE_EV_AURORA",
 | |
|     0x208E : "NA_SE_EV_DEKU_DEATH",
 | |
|     0x208F : "NA_SE_EV_BUYOSTAND_RISING",
 | |
|     0x2090 : "NA_SE_EV_BUYOSTAND_FALL",
 | |
|     0x2091 : "NA_SE_EV_BUYOSHUTTER_OPEN",
 | |
|     0x2092 : "NA_SE_EV_BUYOSHUTTER_CLOSE",
 | |
|     0x2093 : "NA_SE_EV_STONEDOOR_STOP",
 | |
|     0x2094 : "NA_SE_EV_S_STONE_REVIVAL",
 | |
|     0x2095 : "NA_SE_EV_MEDAL_APPEAR_S",
 | |
|     0x2096 : "NA_SE_EV_HUMAN_BOUND",
 | |
|     0x2097 : "NA_SE_EV_MEDAL_APPEAR_L",
 | |
|     0x2098 : "NA_SE_EV_EARTHQUAKE",
 | |
|     0x2099 : "NA_SE_EV_SHUT_BY_CRYSTAL",
 | |
|     0x209A : "NA_SE_EV_GOD_LIGHTBALL_2",
 | |
|     0x209B : "NA_SE_EV_RUN_AROUND",
 | |
|     0x209C : "NA_SE_EV_CONSENTRATION",
 | |
|     0x209D : "NA_SE_EV_TIMETRIP_LIGHT",
 | |
|     0x209E : "NA_SE_EV_BUYOSTAND_STOP_A",
 | |
|     0x209F : "NA_SE_EV_BUYOSTAND_STOP_U",
 | |
|     0x20A0 : "NA_SE_EV_OBJECT_FALL",
 | |
|     0x20A1 : "NA_SE_EV_JUMP_CONC",
 | |
|     0x20A2 : "NA_SE_EV_ICE_MELT",
 | |
|     0x20A3 : "NA_SE_EV_FIRE_PILLAR_S",
 | |
|     0x20A4 : "NA_SE_EV_BLOCK_RISING",
 | |
|     0x20A5 : "NA_SE_EV_NABALL_VANISH",
 | |
|     0x20A6 : "NA_SE_EV_SARIA_MELODY",
 | |
|     0x20A7 : "NA_SE_EV_LINK_WARP_OUT",
 | |
|     0x20A8 : "NA_SE_EV_FIATY_HEAL",
 | |
|     0x20A9 : "NA_SE_EV_CHAIN_KEY_UNLOCK_B",
 | |
|     0x20AA : "NA_SE_EV_WOODBOX_BREAK",
 | |
|     0x20AB : "NA_SE_EV_PUT_DOWN_WOODBOX",
 | |
|     0x20AC : "NA_SE_EV_LAND_DIRT",
 | |
|     0x20AD : "NA_SE_EV_FLOOR_ROLLING",
 | |
|     0x20AE : "NA_SE_EV_DOG_CRY_EVENING",
 | |
|     0x20AF : "NA_SE_EV_JABJAB_HICCUP",
 | |
|     0x20B0 : "NA_SE_EV_NALE_MAGIC",
 | |
|     0x20B1 : "NA_SE_EV_FROG_JUMP",
 | |
|     0x20B2 : "NA_SE_EV_ICE_FREEZE",
 | |
|     0x20B3 : "NA_SE_EV_BURNING",
 | |
|     0x20B4 : "NA_SE_EV_WOODPLATE_BOUND",
 | |
|     0x20B5 : "NA_SE_EV_GORON_WATER_DROP",
 | |
|     0x20B6 : "NA_SE_EV_JABJAB_GROAN",
 | |
|     0x20B7 : "NA_SE_EV_DARUMA_VANISH",
 | |
|     0x20B8 : "NA_SE_EV_BIGBALL_ROLL",
 | |
|     0x20B9 : "NA_SE_EV_ELEVATOR_MOVE3",
 | |
|     0x20BA : "NA_SE_EV_DIAMOND_SWITCH",
 | |
|     0x20BB : "NA_SE_EV_FLAME_OF_FIRE",
 | |
|     0x20BC : "NA_SE_EV_RAINBOW_SHOWER",
 | |
|     0x20BD : "NA_SE_EV_FLYING_AIR",
 | |
|     0x20BE : "NA_SE_EV_PASS_AIR",
 | |
|     0x20BF : "NA_SE_EV_COME_UP_DEKU_JR",
 | |
|     0x20C0 : "NA_SE_EV_SAND_STORM",
 | |
|     0x20C1 : "NA_SE_EV_TRIFORCE_MARK",
 | |
|     0x20C2 : "NA_SE_EV_GRAVE_EXPLOSION",
 | |
|     0x20C3 : "NA_SE_EV_LURE_MOVE_W",
 | |
|     0x20C4 : "NA_SE_EV_POT_MOVE_START",
 | |
|     0x20C5 : "NA_SE_EV_DIVE_INTO_WATER_L",
 | |
|     0x20C6 : "NA_SE_EV_OUT_OF_WATER_L",
 | |
|     0x20C7 : "NA_SE_EV_GANON_MANTLE",
 | |
|     0x20C8 : "NA_SE_EV_DIG_UP",
 | |
|     0x20C9 : "NA_SE_EV_WOOD_BOUND",
 | |
|     0x20CA : "NA_SE_EV_WATER_BUBBLE",
 | |
|     0x20CB : "NA_SE_EV_ICE_BROKEN",
 | |
|     0x20CC : "NA_SE_EV_FROG_GROW_UP",
 | |
|     0x20CD : "NA_SE_EV_WATER_CONVECTION",
 | |
|     0x20CE : "NA_SE_EV_GROUND_GATE_OPEN",
 | |
|     0x20CF : "NA_SE_EV_FACE_BREAKDOWN",
 | |
|     0x20D0 : "NA_SE_EV_FACE_EXPLOSION",
 | |
|     0x20D1 : "NA_SE_EV_FACE_CRUMBLE_SLOW",
 | |
|     0x20D2 : "NA_SE_EV_ROUND_TRAP_MOVE",
 | |
|     0x20D3 : "NA_SE_EV_HIT_SOUND",
 | |
|     0x20D4 : "NA_SE_EV_ICE_SWING",
 | |
|     0x20D5 : "NA_SE_EV_DOWN_TO_GROUND",
 | |
|     0x20D6 : "NA_SE_EV_KENJA_ENVIROMENT_0",
 | |
|     0x20D7 : "NA_SE_EV_KENJA_ENVIROMENT_1",
 | |
|     0x20D8 : "NA_SE_EV_SMALL_DOG_BARK",
 | |
|     0x20D9 : "NA_SE_EV_ZELDA_POWER",
 | |
|     0x20DA : "NA_SE_EV_RAIN",
 | |
|     0x20DB : "NA_SE_EV_IRON_DOOR_OPEN",
 | |
|     0x20DC : "NA_SE_EV_IRON_DOOR_CLOSE",
 | |
|     0x20DD : "NA_SE_EV_WHIRLPOOL",
 | |
|     0x20DE : "NA_SE_EV_TOWER_PARTS_BROKEN",
 | |
|     0x20DF : "NA_SE_EV_COW_CRY",
 | |
|     0x20E0 : "NA_SE_EV_METAL_BOX_BOUND",
 | |
|     0x20E1 : "NA_SE_EV_ELECTRIC_EXPLOSION",
 | |
|     0x20E2 : "NA_SE_EV_HEAVY_THROW",
 | |
|     0x20E3 : "NA_SE_EV_FROG_CRY_0",
 | |
|     0x20E4 : "NA_SE_EV_FROG_CRY_1",
 | |
|     0x20E5 : "NA_SE_EV_COW_CRY_LV",
 | |
|     0x20E6 : "NA_SE_EV_RONRON_DOOR_CLOSE",
 | |
|     0x20E7 : "NA_SE_EV_BUTTERFRY_TO_FAIRY",
 | |
|     0x20E8 : "NA_SE_EV_FIVE_COUNT_LUPY",
 | |
|     0x20E9 : "NA_SE_EV_STONE_GROW_UP",
 | |
|     0x20EA : "NA_SE_EV_STONE_LAUNCH",
 | |
|     0x20EB : "NA_SE_EV_STONE_ROLLING",
 | |
|     0x20EC : "NA_SE_EV_TOGE_STICK_ROLLING",
 | |
|     0x20ED : "NA_SE_EV_TOWER_ENERGY",
 | |
|     0x20EE : "NA_SE_EV_TOWER_BARRIER",
 | |
|     0x20EF : "NA_SE_EV_CHIBI_WALK",
 | |
|     0x20F0 : "NA_SE_EV_KNIGHT_WALK",
 | |
|     0x20F1 : "NA_SE_EV_PILLAR_MOVE_STOP",
 | |
|     0x20F2 : "NA_SE_EV_ERUPTION_CLOUD",
 | |
|     0x20F3 : "NA_SE_EV_LINK_WARP_OUT_LV",
 | |
|     0x20F4 : "NA_SE_EV_LINK_WARP_IN",
 | |
|     0x20F5 : "NA_SE_EV_OCARINA_BMELO_0",
 | |
|     0x20F6 : "NA_SE_EV_OCARINA_BMELO_1",
 | |
|     0x20F7 : "NA_SE_EV_EXPLOSION_FOR_RENZOKU",
 | |
|     0x3000 : "NA_SE_EN_DODO_J_WALK",
 | |
|     0x3001 : "NA_SE_EN_DODO_J_CRY",
 | |
|     0x3002 : "NA_SE_EN_DODO_J_FIRE",
 | |
|     0x3003 : "NA_SE_EN_DODO_J_DAMAGE",
 | |
|     0x3004 : "NA_SE_EN_DODO_J_DEAD",
 | |
|     0x3005 : "NA_SE_EN_DODO_K_CRY",
 | |
|     0x3006 : "NA_SE_EN_DODO_K_DAMAGE",
 | |
|     0x3007 : "NA_SE_EN_DODO_K_DEAD",
 | |
|     0x3008 : "NA_SE_EN_DODO_K_WALK",
 | |
|     0x3009 : "NA_SE_EN_DODO_K_FIRE",
 | |
|     0x300A : "NA_SE_EN_GOMA_WALK",
 | |
|     0x300B : "NA_SE_EN_GOMA_HIGH",
 | |
|     0x300C : "NA_SE_EN_GOMA_CLIM",
 | |
|     0x300D : "NA_SE_EN_GOMA_DOWN",
 | |
|     0x300E : "NA_SE_EN_GOMA_CRY1",
 | |
|     0x300F : "NA_SE_EN_GOMA_CRY2",
 | |
|     0x3010 : "NA_SE_EN_GOMA_DAM1",
 | |
|     0x3011 : "NA_SE_EN_GOMA_DAM2",
 | |
|     0x3012 : "NA_SE_EN_GOMA_DEAD",
 | |
|     0x3013 : "NA_SE_EN_GOMA_UNARI",
 | |
|     0x3014 : "NA_SE_EN_GOMA_BJR_EGG1",
 | |
|     0x3015 : "NA_SE_EN_GOMA_BJR_EGG2",
 | |
|     0x3016 : "NA_SE_EN_GOMA_BJR_WALK",
 | |
|     0x3017 : "NA_SE_EN_GOMA_BJR_CRY",
 | |
|     0x3018 : "NA_SE_EN_GOMA_BJR_DAM1",
 | |
|     0x3019 : "NA_SE_EN_GOMA_BJR_DAM2",
 | |
|     0x301A : "NA_SE_EN_GOMA_BJR_DEAD",
 | |
|     0x301B : "NA_SE_EN_GOMA_DEMO_EYE",
 | |
|     0x301C : "NA_SE_EN_GOMA_LAST",
 | |
|     0x301D : "NA_SE_EN_GOMA_UNARI2",
 | |
|     0x301E : "NA_SE_EN_GOMA_FAINT",
 | |
|     0x301F : "NA_SE_EN_GOMA_BJR_FREEZE",
 | |
|     0x3020 : "NA_SE_EN_DODO_M_CRY",
 | |
|     0x3021 : "NA_SE_EN_DODO_M_DEAD",
 | |
|     0x3022 : "NA_SE_EN_DODO_M_MOVE",
 | |
|     0x3023 : "NA_SE_EN_DODO_M_DOWN",
 | |
|     0x3024 : "NA_SE_EN_DODO_M_UP",
 | |
|     0x3025 : "NA_SE_EN_GANON_THROW_MASIC",
 | |
|     0x3026 : "NA_SE_EN_DODO_M_EAT",
 | |
|     0x3027 : "NA_SE_EN_GANON_DD_THUNDER",
 | |
|     0x3028 : "NA_SE_EN_RIZA_ONGND",
 | |
|     0x3029 : "NA_SE_EN_RIZA_CRY",
 | |
|     0x302A : "NA_SE_EN_RIZA_ATTACK",
 | |
|     0x302B : "NA_SE_EN_RIZA_DAMAGE",
 | |
|     0x302C : "NA_SE_EN_RIZA_WARAU",
 | |
|     0x302D : "NA_SE_EN_RIZA_DEAD",
 | |
|     0x302E : "NA_SE_EN_RIZA_WALK",
 | |
|     0x302F : "NA_SE_EN_RIZA_JUMP",
 | |
|     0x3030 : "NA_SE_EN_STALKID_WALK",
 | |
|     0x3031 : "NA_SE_EN_STALKID_ATTACK",
 | |
|     0x3032 : "NA_SE_EN_STALKID_DAMAGE",
 | |
|     0x3033 : "NA_SE_EN_STALKID_DEAD",
 | |
|     0x3034 : "NA_SE_EN_FLOORMASTER_SLIDING",
 | |
|     0x3035 : "NA_SE_EN_TEKU_WALK_WATER",
 | |
|     0x3036 : "NA_SE_EN_LIGHT_ARROW_HIT",
 | |
|     0x3037 : "NA_SE_EN_TUBOOCK_FLY",
 | |
|     0x3038 : "NA_SE_EN_STAL_WARAU",
 | |
|     0x3039 : "NA_SE_EN_STAL_SAKEBI",
 | |
|     0x303A : "NA_SE_EN_STAL_DAMAGE",
 | |
|     0x303B : "NA_SE_EN_STAL_DEAD",
 | |
|     0x303C : "NA_SE_EN_WOLFOS_APPEAR",
 | |
|     0x303D : "NA_SE_EN_STAL_WALK",
 | |
|     0x303E : "NA_SE_EN_WOLFOS_CRY",
 | |
|     0x303F : "NA_SE_EN_WOLFOS_ATTACK",
 | |
|     0x3040 : "NA_SE_EN_FFLY_ATTACK",
 | |
|     0x3041 : "NA_SE_EN_FFLY_FLY",
 | |
|     0x3042 : "NA_SE_EN_FFLY_DEAD",
 | |
|     0x3043 : "NA_SE_EN_WOLFOS_DAMAGE",
 | |
|     0x3044 : "NA_SE_EN_AMOS_WALK",
 | |
|     0x3045 : "NA_SE_EN_AMOS_WAVE",
 | |
|     0x3046 : "NA_SE_EN_AMOS_DEAD",
 | |
|     0x3047 : "NA_SE_EN_AMOS_DAMAGE",
 | |
|     0x3048 : "NA_SE_EN_AMOS_VOICE",
 | |
|     0x3049 : "NA_SE_EN_SHELL_MOUTH",
 | |
|     0x304A : "NA_SE_EN_SHELL_DEAD",
 | |
|     0x304B : "NA_SE_EN_WOLFOS_DEAD",
 | |
|     0x304C : "NA_SE_EN_DODO_K_COLI",
 | |
|     0x304D : "NA_SE_EN_DODO_K_COLI2",
 | |
|     0x304E : "NA_SE_EN_DODO_K_ROLL",
 | |
|     0x304F : "NA_SE_EN_DODO_K_BREATH",
 | |
|     0x3050 : "NA_SE_EN_DODO_K_DRINK",
 | |
|     0x3051 : "NA_SE_EN_DODO_K_DOWN",
 | |
|     0x3052 : "NA_SE_EN_DODO_K_OTAKEBI",
 | |
|     0x3053 : "NA_SE_EN_DODO_K_END",
 | |
|     0x3054 : "NA_SE_EN_DODO_K_LAST",
 | |
|     0x3055 : "NA_SE_EN_DODO_K_LAVA",
 | |
|     0x3056 : "NA_SE_EN_GANON_FLOAT",
 | |
|     0x3057 : "NA_SE_EN_GANON_DARKWAVE_M",
 | |
|     0x3058 : "NA_SE_EN_DODO_J_BREATH",
 | |
|     0x3059 : "NA_SE_EN_DODO_J_TAIL",
 | |
|     0x305A : "NA_SE_EN_WOLFOS_WALK",
 | |
|     0x305B : "NA_SE_EN_DODO_J_EAT",
 | |
|     0x305C : "NA_SE_EN_DEKU_MOUTH",
 | |
|     0x305D : "NA_SE_EN_DEKU_ATTACK",
 | |
|     0x305E : "NA_SE_EN_DEKU_DAMAGE",
 | |
|     0x305F : "NA_SE_EN_DEKU_DEAD",
 | |
|     0x3060 : "NA_SE_EN_DEKU_JR_MOUTH",
 | |
|     0x3061 : "NA_SE_EN_DEKU_JR_ATTACK",
 | |
|     0x3062 : "NA_SE_EN_DEKU_JR_DEAD",
 | |
|     0x3063 : "NA_SE_EN_DEKU_SCRAPE",
 | |
|     0x3064 : "NA_SE_EN_TAIL_FLY",
 | |
|     0x3065 : "NA_SE_EN_TAIL_CRY",
 | |
|     0x3066 : "NA_SE_EN_TAIL_DEAD",
 | |
|     0x3067 : "NA_SE_EN_GANON_SPARK",
 | |
|     0x3068 : "NA_SE_EN_STALTU_DOWN",
 | |
|     0x3069 : "NA_SE_EN_STALTU_UP",
 | |
|     0x306A : "NA_SE_EN_STALTU_LAUGH",
 | |
|     0x306B : "NA_SE_EN_STALTU_DAMAGE",
 | |
|     0x306C : "NA_SE_EN_STAL_JUMP",
 | |
|     0x306D : "NA_SE_EN_TEKU_DAMAGE",
 | |
|     0x306E : "NA_SE_EN_TEKU_DEAD",
 | |
|     0x306F : "NA_SE_EN_TEKU_WALK",
 | |
|     0x3070 : "NA_SE_EN_PO_KANTERA",
 | |
|     0x3071 : "NA_SE_EN_PO_FLY",
 | |
|     0x3072 : "NA_SE_EN_PO_AWAY",
 | |
|     0x3073 : "NA_SE_EN_PO_APPEAR",
 | |
|     0x3074 : "NA_SE_EN_PO_DISAPPEAR",
 | |
|     0x3075 : "NA_SE_EN_PO_DAMAGE",
 | |
|     0x3076 : "NA_SE_EN_PO_DEAD",
 | |
|     0x3077 : "NA_SE_EN_PO_DEAD2",
 | |
|     0x3078 : "NA_SE_EN_EXTINCT",
 | |
|     0x3079 : "NA_SE_EN_GOLON_LAND_BIG",
 | |
|     0x307A : "NA_SE_EN_RIZA_DOWN",
 | |
|     0x307B : "NA_SE_EN_DODO_M_GND",
 | |
|     0x307C : "NA_SE_EN_NUTS_UP",
 | |
|     0x307D : "NA_SE_EN_NUTS_DOWN",
 | |
|     0x307E : "NA_SE_EN_NUTS_THROW",
 | |
|     0x307F : "NA_SE_EN_NUTS_WALK",
 | |
|     0x3080 : "NA_SE_EN_NUTS_DAMAGE",
 | |
|     0x3081 : "NA_SE_EN_NUTS_DEAD",
 | |
|     0x3082 : "NA_SE_EN_NUTS_FAINT",
 | |
|     0x3083 : "NA_SE_EN_PO_BIG_GET",
 | |
|     0x3084 : "NA_SE_EN_STALTU_ROLL",
 | |
|     0x3085 : "NA_SE_EN_STALWALL_DEAD",
 | |
|     0x3086 : "NA_SE_EN_PO_SISTER_DEAD",
 | |
|     0x3087 : "NA_SE_EN_BARI_SPLIT",
 | |
|     0x3088 : "NA_SE_EN_TEKU_REVERSE",
 | |
|     0x3089 : "NA_SE_EN_VALVAISA_LAND2",
 | |
|     0x308A : "NA_SE_EN_TEKU_LAND_WATER",
 | |
|     0x308B : "NA_SE_EN_LAST_DAMAGE",
 | |
|     0x308C : "NA_SE_EN_STALWALL_ROLL",
 | |
|     0x308D : "NA_SE_EN_STALWALL_DASH",
 | |
|     0x308E : "NA_SE_EN_TEKU_JUMP_WATER",
 | |
|     0x308F : "NA_SE_EN_TEKU_LAND_WATER2",
 | |
|     0x3090 : "NA_SE_EN_FALL_AIM",
 | |
|     0x3091 : "NA_SE_EN_FALL_UP",
 | |
|     0x3092 : "NA_SE_EN_FALL_CATCH",
 | |
|     0x3093 : "NA_SE_EN_FALL_LAND",
 | |
|     0x3094 : "NA_SE_EN_FALL_WALK",
 | |
|     0x3095 : "NA_SE_EN_FALL_DAMAGE",
 | |
|     0x3096 : "NA_SE_EN_FALL_DEAD",
 | |
|     0x3097 : "NA_SE_EN_KAICHO_FLUTTER",
 | |
|     0x3098 : "NA_SE_EN_BIRI_FLY",
 | |
|     0x3099 : "NA_SE_EN_BIRI_JUMP",
 | |
|     0x309A : "NA_SE_EN_BIRI_SPARK",
 | |
|     0x309B : "NA_SE_EN_BIRI_DEAD",
 | |
|     0x309C : "NA_SE_EN_BIRI_BUBLE",
 | |
|     0x309D : "NA_SE_EN_BARI_ROLL",
 | |
|     0x309E : "NA_SE_EN_GOMA_JR_FREEZE",
 | |
|     0x309F : "NA_SE_EN_BARI_DEAD",
 | |
|     0x30A0 : "NA_SE_EN_GANON_FIRE",
 | |
|     0x30A1 : "NA_SE_EN_FANTOM_TRANSFORM",
 | |
|     0x30A2 : "NA_SE_EN_FANTOM_THUNDER",
 | |
|     0x30A3 : "NA_SE_EN_FANTOM_SPARK",
 | |
|     0x30A4 : "NA_SE_EN_FANTOM_FLOAT",
 | |
|     0x30A5 : "NA_SE_EN_FANTOM_MASIC1",
 | |
|     0x30A6 : "NA_SE_EN_FANTOM_MASIC2",
 | |
|     0x30A7 : "NA_SE_EN_FANTOM_FIRE",
 | |
|     0x30A8 : "NA_SE_EN_FANTOM_HIT_THUNDER",
 | |
|     0x30A9 : "NA_SE_EN_FANTOM_ATTACK",
 | |
|     0x30AA : "NA_SE_EN_FANTOM_STICK",
 | |
|     0x30AB : "NA_SE_EN_FANTOM_EYE",
 | |
|     0x30AC : "NA_SE_EN_FANTOM_LAST",
 | |
|     0x30AD : "NA_SE_EN_FANTOM_THUNDER_GND",
 | |
|     0x30AE : "NA_SE_EN_FANTOM_DAMAGE",
 | |
|     0x30AF : "NA_SE_EN_FANTOM_DEAD",
 | |
|     0x30B0 : "NA_SE_EN_FANTOM_LAUGH",
 | |
|     0x30B1 : "NA_SE_EN_FANTOM_DAMAGE2",
 | |
|     0x30B2 : "NA_SE_EN_FANTOM_VOICE",
 | |
|     0x30B3 : "NA_SE_EN_KAICHO_DAMAGE",
 | |
|     0x30B4 : "NA_SE_EN_GANON_ATTACK_DEMO",
 | |
|     0x30B5 : "NA_SE_EN_GANON_FIRE_DEMO",
 | |
|     0x30B6 : "NA_SE_EN_KAICHO_CRY",
 | |
|     0x30B7 : "NA_SE_EN_KAICHO_ATTACK",
 | |
|     0x30B8 : "NA_SE_EN_MORIBLIN_WALK",
 | |
|     0x30B9 : "NA_SE_EN_MORIBLIN_SLIDE",
 | |
|     0x30BA : "NA_SE_EN_MORIBLIN_ATTACK",
 | |
|     0x30BB : "NA_SE_EN_MORIBLIN_VOICE",
 | |
|     0x30BC : "NA_SE_EN_MORIBLIN_SPEAR_AT",
 | |
|     0x30BD : "NA_SE_EN_MORIBLIN_SPEAR_NORM",
 | |
|     0x30BE : "NA_SE_EN_MORIBLIN_DEAD",
 | |
|     0x30BF : "NA_SE_EN_MORIBLIN_DASH",
 | |
|     0x30C0 : "NA_SE_EN_OCTAROCK_ROCK",
 | |
|     0x30C1 : "NA_SE_EN_OCTAROCK_FLOAT",
 | |
|     0x30C2 : "NA_SE_EN_OCTAROCK_JUMP",
 | |
|     0x30C3 : "NA_SE_EN_OCTAROCK_LAND",
 | |
|     0x30C4 : "NA_SE_EN_OCTAROCK_SINK",
 | |
|     0x30C5 : "NA_SE_EN_OCTAROCK_BUBLE",
 | |
|     0x30C6 : "NA_SE_EN_OCTAROCK_DEAD1",
 | |
|     0x30C7 : "NA_SE_EN_OCTAROCK_DEAD2",
 | |
|     0x30C8 : "NA_SE_EN_BUBLE_WING",
 | |
|     0x30C9 : "NA_SE_EN_BUBLE_MOUTH",
 | |
|     0x30CA : "NA_SE_EN_BUBLE_LAUGH",
 | |
|     0x30CB : "NA_SE_EN_BUBLE_BITE",
 | |
|     0x30CC : "NA_SE_EN_BUBLE_UP",
 | |
|     0x30CD : "NA_SE_EN_BUBLE_DOWN",
 | |
|     0x30CE : "NA_SE_EN_BUBLE_DEAD",
 | |
|     0x30CF : "NA_SE_EN_BUBLEFALL_FIRE",
 | |
|     0x30D0 : "NA_SE_EN_VALVAISA_APPEAR",
 | |
|     0x30D1 : "NA_SE_EN_VALVAISA_ROAR",
 | |
|     0x30D2 : "NA_SE_EN_VALVAISA_MAHI1",
 | |
|     0x30D3 : "NA_SE_EN_VALVAISA_MAHI2",
 | |
|     0x30D4 : "NA_SE_EN_VALVAISA_KNOCKOUT",
 | |
|     0x30D5 : "NA_SE_EN_VALVAISA_DAMAGE1",
 | |
|     0x30D6 : "NA_SE_EN_VALVAISA_DAMAGE2",
 | |
|     0x30D7 : "NA_SE_EN_VALVAISA_ROCK",
 | |
|     0x30D8 : "NA_SE_EN_VALVAISA_SW_NAIL",
 | |
|     0x30D9 : "NA_SE_EN_VALVAISA_DEAD",
 | |
|     0x30DA : "NA_SE_EN_VALVAISA_BURN",
 | |
|     0x30DB : "NA_SE_EN_VALVAISA_FIRE",
 | |
|     0x30DC : "NA_SE_EN_BARI_DAMAGE",
 | |
|     0x30DD : "NA_SE_EN_MOFER_CORE_LAND",
 | |
|     0x30DE : "NA_SE_EN_MOFER_CORE_MOVE_WT",
 | |
|     0x30DF : "NA_SE_EN_MOFER_CORE_SMJUMP",
 | |
|     0x30E0 : "NA_SE_EN_MONBLIN_GNDWAVE",
 | |
|     0x30E1 : "NA_SE_EN_MONBLIN_HAM_DOWN",
 | |
|     0x30E2 : "NA_SE_EN_MONBLIN_HAM_UP",
 | |
|     0x30E3 : "NA_SE_EN_BUBLE_DAMAGE",
 | |
|     0x30E4 : "NA_SE_EN_REDEAD_CRY",
 | |
|     0x30E5 : "NA_SE_EN_REDEAD_AIM",
 | |
|     0x30E6 : "NA_SE_EN_REDEAD_DAMAGE",
 | |
|     0x30E7 : "NA_SE_EN_REDEAD_DEAD",
 | |
|     0x30E8 : "NA_SE_EN_REDEAD_ATTACK",
 | |
|     0x30E9 : "NA_SE_EN_NYU_MOVE",
 | |
|     0x30EA : "NA_SE_EN_NYU_HIT_STOP",
 | |
|     0x30EB : "NA_SE_EN_KAICHO_DEAD",
 | |
|     0x30EC : "NA_SE_EN_PO_LAUGH",
 | |
|     0x30ED : "NA_SE_EN_PO_CRY",
 | |
|     0x30EE : "NA_SE_EN_PO_ROLL",
 | |
|     0x30EF : "NA_SE_EN_PO_LAUGH2",
 | |
|     0x30F0 : "NA_SE_EN_MOFER_APPEAR",
 | |
|     0x30F1 : "NA_SE_EN_MOFER_ATTACK",
 | |
|     0x30F2 : "NA_SE_EN_MOFER_WAVE",
 | |
|     0x30F3 : "NA_SE_EN_MOFER_CATCH",
 | |
|     0x30F4 : "NA_SE_EN_MOFER_CUT",
 | |
|     0x30F5 : "NA_SE_EN_MOFER_MOVE_DEMO",
 | |
|     0x30F6 : "NA_SE_EN_MOFER_BUBLE_DEMO",
 | |
|     0x30F7 : "NA_SE_EN_MOFER_CORE_JUMP",
 | |
|     0x30F8 : "NA_SE_EN_MOFER_DEAD",
 | |
|     0x30F9 : "NA_SE_EN_MOFER_LASTVOICE",
 | |
|     0x30FA : "NA_SE_EN_MOFER_CORE_ROLL",
 | |
|     0x30FB : "NA_SE_EN_MOFER_CORE_FLY",
 | |
|     0x30FC : "NA_SE_EN_GOLON_WAKE_UP",
 | |
|     0x30FD : "NA_SE_EN_GOLON_SIT_DOWN",
 | |
|     0x30FE : "NA_SE_EN_CHICKEN_FLUTTER",
 | |
|     0x30FF : "NA_SE_EN_DEKU_WAKEUP",
 | |
|     0x3100 : "NA_SE_EN_DEADHAND_BITE",
 | |
|     0x3101 : "NA_SE_EN_DEADHAND_WALK",
 | |
|     0x3102 : "NA_SE_EN_DEADHAND_GRIP",
 | |
|     0x3103 : "NA_SE_EN_DEADHAND_HAND_AT",
 | |
|     0x3104 : "NA_SE_EN_DAIOCTA_MAHI",
 | |
|     0x3105 : "NA_SE_EN_DAIOCTA_SPLASH",
 | |
|     0x3106 : "NA_SE_EN_DAIOCTA_VOICE",
 | |
|     0x3107 : "NA_SE_EN_DAIOCTA_DAMAGE",
 | |
|     0x3108 : "NA_SE_EN_DAIOCTA_SINK",
 | |
|     0x3109 : "NA_SE_EN_DAIOCTA_DEAD",
 | |
|     0x310A : "NA_SE_EN_DAIOCTA_DEAD2",
 | |
|     0x310B : "NA_SE_EN_GANON_HIT_THUNDER",
 | |
|     0x310C : "NA_SE_EN_TWINROBA_APPEAR_MS",
 | |
|     0x310D : "NA_SE_EN_TWINROBA_TRANSFORM",
 | |
|     0x310E : "NA_SE_EN_TWINROBA_MS_FIRE",
 | |
|     0x310F : "NA_SE_EN_TWINROBA_FIRE_EXP",
 | |
|     0x3110 : "NA_SE_EN_TWINROBA_POWERUP",
 | |
|     0x3111 : "NA_SE_EN_TWINROBA_SHOOT_FREEZE",
 | |
|     0x3112 : "NA_SE_EN_TWINROBA_MS_FREEZE",
 | |
|     0x3113 : "NA_SE_EN_TWINROBA_MASIC_SET",
 | |
|     0x3114 : "NA_SE_EN_TWINROBA_CUTBODY",
 | |
|     0x3115 : "NA_SE_EN_GANON_HIT_GND_IMP",
 | |
|     0x3116 : "NA_SE_EN_TWINROBA_DAMAGE_VOICE",
 | |
|     0x3117 : "NA_SE_EN_TWINROBA_REFL_FIRE",
 | |
|     0x3118 : "NA_SE_EN_TWINROBA_REFL_FREEZE",
 | |
|     0x3119 : "NA_SE_EN_GANON_CUTBODY",
 | |
|     0x311A : "NA_SE_EN_TWINROBA_YOUNG_DAMAGE",
 | |
|     0x311B : "NA_SE_EN_TWINROBA_YOUNG_DEAD",
 | |
|     0x311C : "NA_SE_EN_GOLON_EYE_BIG",
 | |
|     0x311D : "NA_SE_EN_GOLON_GOOD_BIG",
 | |
|     0x311E : "NA_SE_EN_TWINROBA_FB_FLY",
 | |
|     0x311F : "NA_SE_EN_TWINROBA_FLY",
 | |
|     0x3120 : "NA_SE_EN_TWINROBA_UNARI",
 | |
|     0x3121 : "NA_SE_EN_TWINROBA_ROLL",
 | |
|     0x3122 : "NA_SE_EN_TWINROBA_SHOOT_FIRE",
 | |
|     0x3123 : "NA_SE_EN_TWINROBA_THROW_MASIC",
 | |
|     0x3124 : "NA_SE_EN_DARUNIA_HIT_BREAST",
 | |
|     0x3125 : "NA_SE_EN_DARUNIA_HIT_LINK",
 | |
|     0x3126 : "NA_SE_EN_OWL_FLUTTER",
 | |
|     0x3127 : "NA_SE_EN_VALVAISA_LAND",
 | |
|     0x3128 : "NA_SE_EN_IRONNACK_WALK",
 | |
|     0x3129 : "NA_SE_EN_IRONNACK_SWING_AXE",
 | |
|     0x312A : "NA_SE_EN_IRONNACK_ARMOR_DEMO",
 | |
|     0x312B : "NA_SE_EN_IRONNACK_STAGGER_DEMO",
 | |
|     0x312C : "NA_SE_EN_IRONNACK_ARMOR_OFF_DEMO",
 | |
|     0x312D : "NA_SE_EN_IRONNACK_ARMOR_LAND1_DEMO",
 | |
|     0x312E : "NA_SE_EN_IRONNACK_ARMOR_LAND2_DEMO",
 | |
|     0x312F : "NA_SE_EN_IRONNACK_ARMOR_LAND3_DEMO",
 | |
|     0x3130 : "NA_SE_EN_FLOORMASTER_ATTACK",
 | |
|     0x3131 : "NA_SE_EN_FLOORMASTER_SM_WALK",
 | |
|     0x3132 : "NA_SE_EN_FLOORMASTER_SM_DEAD",
 | |
|     0x3133 : "NA_SE_EN_FLOORMASTER_RESTORE",
 | |
|     0x3134 : "NA_SE_EN_FLOORMASTER_EXPAND",
 | |
|     0x3135 : "NA_SE_EN_FLOORMASTER_SPLIT",
 | |
|     0x3136 : "NA_SE_EN_FLOORMASTER_SM_STICK",
 | |
|     0x3137 : "NA_SE_EN_FLOORMASTER_SM_LAND",
 | |
|     0x3138 : "NA_SE_EN_IRONNACK_WAVE_DEMO",
 | |
|     0x3139 : "NA_SE_EN_IRONNACK_FINGER_DEMO",
 | |
|     0x313A : "NA_SE_EN_IRONNACK_ARMOR_HIT",
 | |
|     0x313B : "NA_SE_EN_NUTS_CUTBODY",
 | |
|     0x313C : "NA_SE_EN_BALINADE_LEVEL",
 | |
|     0x313D : "NA_SE_EN_BALINADE_DAMAGE",
 | |
|     0x313E : "NA_SE_EN_BALINADE_FAINT",
 | |
|     0x313F : "NA_SE_EN_BALINADE_BREAK",
 | |
|     0x3140 : "NA_SE_EN_BALINADE_DEAD",
 | |
|     0x3141 : "NA_SE_EN_BALINADE_STICK",
 | |
|     0x3142 : "NA_SE_EN_BALINADE_THUNDER",
 | |
|     0x3143 : "NA_SE_EN_BALINADE_BL_SPARK",
 | |
|     0x3144 : "NA_SE_EN_BALINADE_BL_DEAD",
 | |
|     0x3145 : "NA_SE_EN_BALINADE_BREAK2",
 | |
|     0x3146 : "NA_SE_EN_BALINADE_HIT_RINK",
 | |
|     0x3147 : "NA_SE_EN_GANON_WAVE_GND",
 | |
|     0x3148 : "NA_SE_EN_AWA_BOUND",
 | |
|     0x3149 : "NA_SE_EN_AWA_BREAK",
 | |
|     0x314A : "NA_SE_EN_BROB_WAVE",
 | |
|     0x314B : "NA_SE_EN_NYU_DEAD",
 | |
|     0x314C : "NA_SE_EN_EIER_DAMAGE",
 | |
|     0x314D : "NA_SE_EN_EIER_DEAD",
 | |
|     0x314E : "NA_SE_EN_EIER_FLUTTER",
 | |
|     0x314F : "NA_SE_EN_EIER_FLY",
 | |
|     0x3150 : "NA_SE_EN_SHADEST_TAIKO_LOW",
 | |
|     0x3151 : "NA_SE_EN_SHADEST_TAIKO_HIGH",
 | |
|     0x3152 : "NA_SE_EN_SHADEST_CLAP",
 | |
|     0x3153 : "NA_SE_EN_SHADEST_FLY_ATTACK",
 | |
|     0x3154 : "NA_SE_EN_PIHAT_UP",
 | |
|     0x3155 : "NA_SE_EN_PIHAT_FLY",
 | |
|     0x3156 : "NA_SE_EN_PIHAT_DAMAGE",
 | |
|     0x3157 : "NA_SE_EN_PIHAT_LAND",
 | |
|     0x3158 : "NA_SE_EN_BALINADE_HAND_DOWN",
 | |
|     0x3159 : "NA_SE_EN_BALINADE_HAND_UP",
 | |
|     0x315A : "NA_SE_EN_BALINADE_HAND_DAMAGE",
 | |
|     0x315B : "NA_SE_EN_BALINADE_HAND_DEAD",
 | |
|     0x315C : "NA_SE_EN_GOMA_JR_WALK",
 | |
|     0x315D : "NA_SE_EN_GOMA_JR_CRY",
 | |
|     0x315E : "NA_SE_EN_GOMA_JR_DAM1",
 | |
|     0x315F : "NA_SE_EN_GOMA_JR_DAM2",
 | |
|     0x3160 : "NA_SE_EN_GOMA_JR_DEAD",
 | |
|     0x3161 : "NA_SE_EN_GOMA_EGG1",
 | |
|     0x3162 : "NA_SE_EN_GOMA_EGG2",
 | |
|     0x3163 : "NA_SE_EN_GANON_BODY_SPARK",
 | |
|     0x3164 : "NA_SE_EN_SHADEST_HAND_WAVE",
 | |
|     0x3165 : "NA_SE_EN_SHADEST_CATCH",
 | |
|     0x3166 : "NA_SE_EN_SHADEST_LAND",
 | |
|     0x3167 : "NA_SE_EN_SHADEST_HAND_FLY",
 | |
|     0x3168 : "NA_SE_EN_SHADEST_SHAKEHAND",
 | |
|     0x3169 : "NA_SE_EN_SHADEST_DAMAGE",
 | |
|     0x316A : "NA_SE_EN_SHADEST_DAMAGE_HAND",
 | |
|     0x316B : "NA_SE_EN_SHADEST_DISAPPEAR",
 | |
|     0x316C : "NA_SE_EN_GANON_CHARGE_MASIC",
 | |
|     0x316D : "NA_SE_EN_GANON_THROW_BIG",
 | |
|     0x316E : "NA_SE_EN_SHADEST_FREEZE",
 | |
|     0x316F : "NA_SE_EN_SHADEST_DEAD",
 | |
|     0x3170 : "NA_SE_EN_BIMOS_ROLL_HEAD",
 | |
|     0x3171 : "NA_SE_EN_BIMOS_LAZER",
 | |
|     0x3172 : "NA_SE_EN_BIMOS_LAZER_GND",
 | |
|     0x3173 : "NA_SE_EN_BIMOS_AIM",
 | |
|     0x3174 : "NA_SE_EN_BUBLEWALK_WALK",
 | |
|     0x3175 : "NA_SE_EN_BUBLEWALK_AIM",
 | |
|     0x3176 : "NA_SE_EN_BUBLEWALK_REVERSE",
 | |
|     0x3177 : "NA_SE_EN_BUBLEWALK_DAMAGE",
 | |
|     0x3178 : "NA_SE_EN_BUBLEWALK_DEAD",
 | |
|     0x3179 : "NA_SE_EN_YUKABYUN_FLY",
 | |
|     0x317A : "NA_SE_EN_FLAME_DAMAGE",
 | |
|     0x317B : "NA_SE_EN_TWINROBA_FLY_DEMO",
 | |
|     0x317C : "NA_SE_EN_FLAME_KICK",
 | |
|     0x317D : "NA_SE_EN_FLAME_RUN",
 | |
|     0x317E : "NA_SE_EN_FLAME_ROLL",
 | |
|     0x317F : "NA_SE_EN_FLAME_MAN_RUN",
 | |
|     0x3180 : "NA_SE_EN_FLAME_MAN_DAMAGE",
 | |
|     0x3181 : "NA_SE_EN_FLAME_LAUGH",
 | |
|     0x3182 : "NA_SE_EN_FLAME_MAN_SLIDE",
 | |
|     0x3183 : "NA_SE_EN_FLAME_FIRE_ATTACK",
 | |
|     0x3184 : "NA_SE_EN_PIHAT_SM_FLY",
 | |
|     0x3185 : "NA_SE_EN_PIHAT_SM_DEAD",
 | |
|     0x3186 : "NA_SE_EN_RIVA_APPEAR",
 | |
|     0x3187 : "NA_SE_EN_AKINDONUTS_HIDE",
 | |
|     0x3188 : "NA_SE_EN_RIVA_DAMAGE",
 | |
|     0x3189 : "NA_SE_EN_RIVA_DEAD",
 | |
|     0x318A : "NA_SE_EN_RIVA_MOVE",
 | |
|     0x318B : "NA_SE_EN_FLAME_MAN_SURP",
 | |
|     0x318C : "NA_SE_EN_SHADEST_LAST",
 | |
|     0x318D : "NA_SE_EN_SHADEST_MOVE",
 | |
|     0x318E : "NA_SE_EN_SHADEST_PRAY",
 | |
|     0x318F : "NA_SE_EN_MGANON_ROAR",
 | |
|     0x3190 : "NA_SE_EN_LIKE_WALK",
 | |
|     0x3191 : "NA_SE_EN_LIKE_UNARI",
 | |
|     0x3192 : "NA_SE_EN_LIKE_DRINK",
 | |
|     0x3193 : "NA_SE_EN_LIKE_EAT",
 | |
|     0x3194 : "NA_SE_EN_LIKE_THROW",
 | |
|     0x3195 : "NA_SE_EN_LIKE_DAMAGE",
 | |
|     0x3196 : "NA_SE_EN_LIKE_DEAD",
 | |
|     0x3197 : "NA_SE_EN_MGANON_SWORD",
 | |
|     0x3198 : "NA_SE_EN_GERUDOFT_ATTACK",
 | |
|     0x3199 : "NA_SE_EN_GERUDOFT_DAMAGE",
 | |
|     0x319A : "NA_SE_EN_GERUDOFT_DEAD",
 | |
|     0x319B : "NA_SE_EN_MGANON_DAMAGE",
 | |
|     0x319C : "NA_SE_EN_ANUBIS_FIRE",
 | |
|     0x319D : "NA_SE_EN_ANUBIS_FIREBOMB",
 | |
|     0x319E : "NA_SE_EN_MGANON_DEAD1",
 | |
|     0x319F : "NA_SE_EN_ANUBIS_DEAD",
 | |
|     0x31A0 : "NA_SE_EN_MUSI_LAND",
 | |
|     0x31A1 : "NA_SE_EN_MGANON_DEAD2",
 | |
|     0x31A2 : "NA_SE_EN_EIER_ATTACK",
 | |
|     0x31A3 : "NA_SE_EN_EIER_CRY",
 | |
|     0x31A4 : "NA_SE_EN_FREEZAD_BREATH",
 | |
|     0x31A5 : "NA_SE_EN_FREEZAD_DAMAGE",
 | |
|     0x31A6 : "NA_SE_EN_FREEZAD_DEAD",
 | |
|     0x31A7 : "NA_SE_EN_DEADHAND_LAUGH",
 | |
|     0x31A8 : "NA_SE_EN_DEADHAND_HIDE",
 | |
|     0x31A9 : "NA_SE_EN_DEADHAND_DAMAGE",
 | |
|     0x31AA : "NA_SE_EN_DEADHAND_HAND_DEAD",
 | |
|     0x31AB : "NA_SE_EN_DEADHAND_DEAD",
 | |
|     0x31AC : "NA_SE_EN_IRONNACK_BREAK_PILLAR2",
 | |
|     0x31AD : "NA_SE_EN_IRONNACK_BREAK_PILLAR",
 | |
|     0x31AE : "NA_SE_EN_IRONNACK_HIT_GND",
 | |
|     0x31AF : "NA_SE_EN_MGANON_BREATH",
 | |
|     0x31B0 : "NA_SE_EN_TWINROBA_LAUGH",
 | |
|     0x31B1 : "NA_SE_EN_TWINROBA_LAUGH2",
 | |
|     0x31B2 : "NA_SE_EN_DUMMY434",
 | |
|     0x31B3 : "NA_SE_EN_TWINROBA_SHOOT_VOICE",
 | |
|     0x31B4 : "NA_SE_EN_TWINROBA_SENSE",
 | |
|     0x31B5 : "NA_SE_EN_TWINROBA_DIE",
 | |
|     0x31B6 : "NA_SE_EN_DUMMY438",
 | |
|     0x31B7 : "NA_SE_EN_TWINROBA_YOUNG_DAMAGE2",
 | |
|     0x31B8 : "NA_SE_EN_TWINROBA_YOUNG_SHOOTVC",
 | |
|     0x31B9 : "NA_SE_EN_TWINROBA_YOUNG_LAUGH",
 | |
|     0x31BA : "NA_SE_EN_DUMMY442",
 | |
|     0x31BB : "NA_SE_EN_TWINROBA_YOUNG_WINK",
 | |
|     0x31BC : "NA_SE_EN_DUMMY444",
 | |
|     0x31BD : "NA_SE_EN_DUMMY445",
 | |
|     0x31BE : "NA_SE_EN_IRONNACK_DAMAGE",
 | |
|     0x31BF : "NA_SE_EN_IRONNACK_DASH",
 | |
|     0x31C0 : "NA_SE_EN_IRONNACK_DEAD",
 | |
|     0x31C1 : "NA_SE_EN_IRONNACK_PULLOUT",
 | |
|     0x31C2 : "NA_SE_EN_IRONNACK_WAKEUP",
 | |
|     0x31C3 : "NA_SE_EN_DUMMY451",
 | |
|     0x31C4 : "NA_SE_EN_DUMMY452",
 | |
|     0x31C5 : "NA_SE_EN_DUMMY453",
 | |
|     0x31C6 : "NA_SE_EN_GERUDOFT_BREATH",
 | |
|     0x31C7 : "NA_SE_EN_GANON_LAUGH",
 | |
|     0x31C8 : "NA_SE_EN_GANON_VOICE_DEMO",
 | |
|     0x31C9 : "NA_SE_EN_GANON_THROW",
 | |
|     0x31CA : "NA_SE_EN_GANON_AT_RETURN",
 | |
|     0x31CB : "NA_SE_EN_GANON_HIT_GND",
 | |
|     0x31CC : "NA_SE_EN_GANON_DAMAGE1",
 | |
|     0x31CD : "NA_SE_EN_GANON_DAMAGE2",
 | |
|     0x31CE : "NA_SE_EN_GANON_DOWN",
 | |
|     0x31CF : "NA_SE_EN_GANON_RESTORE",
 | |
|     0x31D0 : "NA_SE_EN_GANON_DEAD",
 | |
|     0x31D1 : "NA_SE_EN_GANON_BREATH",
 | |
|     0x31D2 : "NA_SE_EN_GANON_TOKETU",
 | |
|     0x31D3 : "NA_SE_EN_GANON_CASBREAK",
 | |
|     0x31D4 : "NA_SE_EN_GANON_BIGMASIC",
 | |
|     0x31D5 : "NA_SE_EN_GANON_DARKWAVE",
 | |
|     0x31D6 : "NA_SE_EN_FANTOM_ST_LAUGH",
 | |
|     0x31D7 : "NA_SE_EN_MGANON_WALK",
 | |
|     0x31D8 : "NA_SE_EN_MGANON_STAND",
 | |
|     0x31D9 : "NA_SE_EN_MGANON_UNARI",
 | |
|     0x31DA : "NA_SE_EN_STALGOLD_ROLL",
 | |
|     0x31DB : "NA_SE_EN_KDOOR_WAVE",
 | |
|     0x31DC : "NA_SE_EN_KDOOR_HIT",
 | |
|     0x31DD : "NA_SE_EN_KDOOR_BREAK",
 | |
|     0x31DE : "NA_SE_EN_KDOOR_HIT_GND",
 | |
|     0x31DF : "NA_SE_EN_MGANON_SWDIMP",
 | |
|     0x31E0 : "NA_SE_EN_STALTU_WAVE",
 | |
|     0x31E1 : "NA_SE_EN_STALTU_DOWN_SET",
 | |
|     0x31E2 : "NA_SE_EN_DUMMY482",
 | |
|     0x31E3 : "NA_SE_EN_GOMA_BJR_LAND",
 | |
|     0x31E4 : "NA_SE_EN_GOMA_BJR_LAND2",
 | |
|     0x31E5 : "NA_SE_EN_GOMA_JR_LAND",
 | |
|     0x31E6 : "NA_SE_EN_GOMA_JR_LAND2",
 | |
|     0x31E7 : "NA_SE_EN_TWINROBA_FIGHT",
 | |
|     0x31E8 : "NA_SE_EN_PO_BIG_CRY",
 | |
|     0x31E9 : "NA_SE_EN_MUSI_SINK",
 | |
|     0x31EA : "NA_SE_EN_STALGOLD_UP_CRY",
 | |
|     0x31EB : "NA_SE_EN_GOLON_CRY",
 | |
|     0x31EC : "NA_SE_EN_MOFER_CORE_DAMAGE",
 | |
|     0x31ED : "NA_SE_EN_DAIOCTA_LAND_WATER",
 | |
|     0x31EE : "NA_SE_EN_RIVA_BIG_APPEAR",
 | |
|     0x31EF : "NA_SE_EN_MONBLIN_HAM_LAND",
 | |
|     0x31F0 : "NA_SE_EN_MUSI_WALK",
 | |
|     0x31F1 : "NA_SE_EN_MIMICK_BREATH",
 | |
|     0x31F2 : "NA_SE_EN_STALWALL_LAUGH",
 | |
|     0x4000 : "NA_SE_SY_WIN_OPEN",
 | |
|     0x4001 : "NA_SE_SY_WIN_CLOSE",
 | |
|     0x4002 : "NA_SE_SY_CORRECT_CHIME",
 | |
|     0x4003 : "NA_SE_SY_GET_RUPY",
 | |
|     0x4004 : "NA_SE_SY_MESSAGE_WOMAN",
 | |
|     0x4005 : "NA_SE_SY_MESSAGE_MAN",
 | |
|     0x4006 : "NA_SE_SY_ERROR",
 | |
|     0x4007 : "NA_SE_SY_TRE_BOX_APPEAR",
 | |
|     0x4008 : "NA_SE_SY_DECIDE",
 | |
|     0x4009 : "NA_SE_SY_CURSOR",
 | |
|     0x400A : "NA_SE_SY_CANCEL",
 | |
|     0x400B : "NA_SE_SY_HP_RECOVER",
 | |
|     0x400C : "NA_SE_SY_ATTENTION_ON",
 | |
|     0x400D : "NA_SE_SY_DUMMY_13",
 | |
|     0x400E : "NA_SE_SY_DUMMY_14",
 | |
|     0x400F : "NA_SE_SY_LOCK_OFF",
 | |
|     0x4010 : "NA_SE_SY_LOCK_ON_HUMAN",
 | |
|     0x4011 : "NA_SE_SY_DUMMY_17",
 | |
|     0x4012 : "NA_SE_SY_DUMMY_18",
 | |
|     0x4013 : "NA_SE_SY_CAMERA_ZOOM_UP",
 | |
|     0x4014 : "NA_SE_SY_CAMERA_ZOOM_DOWN",
 | |
|     0x4015 : "NA_SE_SY_DUMMY_21",
 | |
|     0x4016 : "NA_SE_SY_DUMMY_22",
 | |
|     0x4017 : "NA_SE_SY_ATTENTION_ON_OLD",
 | |
|     0x4018 : "NA_SE_SY_MESSAGE_PASS",
 | |
|     0x4019 : "NA_SE_SY_WARNING_COUNT_N",
 | |
|     0x401A : "NA_SE_SY_WARNING_COUNT_E",
 | |
|     0x401B : "NA_SE_SY_HITPOINT_ALARM",
 | |
|     0x401C : "NA_SE_SY_DUMMY_28",
 | |
|     0x401D : "NA_SE_SY_DEMO_CUT",
 | |
|     0x401E : "NA_SE_SY_NAVY_CALL",
 | |
|     0x401F : "NA_SE_SY_GAUGE_UP",
 | |
|     0x4020 : "NA_SE_SY_DUMMY_32",
 | |
|     0x4021 : "NA_SE_SY_DUMMY_33",
 | |
|     0x4022 : "NA_SE_SY_DUMMY_34",
 | |
|     0x4023 : "NA_SE_SY_PIECE_OF_HEART",
 | |
|     0x4024 : "NA_SE_SY_GET_ITEM",
 | |
|     0x4025 : "NA_SE_SY_WIN_SCROLL_LEFT",
 | |
|     0x4026 : "NA_SE_SY_WIN_SCROLL_RIGHT",
 | |
|     0x4027 : "NA_SE_SY_OCARINA_ERROR",
 | |
|     0x4028 : "NA_SE_SY_CAMERA_ZOOM_UP_2",
 | |
|     0x4029 : "NA_SE_SY_CAMERA_ZOOM_DOWN_2",
 | |
|     0x402A : "NA_SE_SY_GLASSMODE_ON",
 | |
|     0x402B : "NA_SE_SY_GLASSMODE_OFF",
 | |
|     0x402C : "NA_SE_SY_FOUND",
 | |
|     0x402D : "NA_SE_SY_HIT_SOUND",
 | |
|     0x402E : "NA_SE_SY_MESSAGE_END",
 | |
|     0x402F : "NA_SE_SY_RUPY_COUNT",
 | |
|     0x4030 : "NA_SE_SY_LOCK_ON",
 | |
|     0x4031 : "NA_SE_SY_GET_BOXITEM",
 | |
|     0x4032 : "NA_SE_SY_WHITE_OUT_L",
 | |
|     0x4033 : "NA_SE_SY_WHITE_OUT_S",
 | |
|     0x4034 : "NA_SE_SY_WHITE_OUT_T",
 | |
|     0x4035 : "NA_SE_SY_START_SHOT",
 | |
|     0x4036 : "NA_SE_SY_METRONOME",
 | |
|     0x4037 : "NA_SE_SY_ATTENTION_URGENCY",
 | |
|     0x4038 : "NA_SE_SY_METRONOME_LV",
 | |
|     0x4039 : "NA_SE_SY_FSEL_CURSOR",
 | |
|     0x403A : "NA_SE_SY_FSEL_DECIDE_S",
 | |
|     0x403B : "NA_SE_SY_FSEL_DECIDE_L",
 | |
|     0x403C : "NA_SE_SY_FSEL_CLOSE",
 | |
|     0x403D : "NA_SE_SY_FSEL_ERROR",
 | |
|     0x403E : "NA_SE_SY_SET_FIRE_ARROW",
 | |
|     0x403F : "NA_SE_SY_SET_ICE_ARROW",
 | |
|     0x4040 : "NA_SE_SY_SET_LIGHT_ARROW",
 | |
|     0x4041 : "NA_SE_SY_SYNTH_MAGIC_ARROW",
 | |
|     0x4042 : "NA_SE_SY_METRONOME_2",
 | |
|     0x4043 : "NA_SE_SY_KINSTA_MARK_APPEAR",
 | |
|     0x4044 : "NA_SE_SY_FIVE_COUNT_LUPY",
 | |
|     0x4045 : "NA_SE_SY_CARROT_RECOVER",
 | |
|     0x4046 : "NA_SE_EV_FAIVE_LUPY_COUNT",
 | |
|     0x4047 : "NA_SE_SY_DUMMY_71",
 | |
|     0x5000 : "NA_SE_OC_OCARINA",
 | |
|     0x5001 : "NA_SE_OC_ABYSS",
 | |
|     0x5002 : "NA_SE_OC_DOOR_OPEN",
 | |
|     0x5003 : "NA_SE_OC_SECRET_WARP_IN",
 | |
|     0x5004 : "NA_SE_OC_SECRET_WARP_OUT",
 | |
|     0x5005 : "NA_SE_OC_SECRET_HOLE_OUT",
 | |
|     0x5006 : "NA_SE_OC_REVENGE",
 | |
|     0x5007 : "NA_SE_OC_HINT_MOVIE",
 | |
|     0x6000 : "NA_SE_VO_LI_SWORD_N",
 | |
|     0x6001 : "NA_SE_VO_LI_SWORD_L",
 | |
|     0x6002 : "NA_SE_VO_LI_LASH",
 | |
|     0x6003 : "NA_SE_VO_LI_HANG",
 | |
|     0x6004 : "NA_SE_VO_LI_CLIMB_END",
 | |
|     0x6005 : "NA_SE_VO_LI_DAMAGE_S",
 | |
|     0x6006 : "NA_SE_VO_LI_FREEZE",
 | |
|     0x6007 : "NA_SE_VO_LI_FALL_S",
 | |
|     0x6008 : "NA_SE_VO_LI_FALL_L",
 | |
|     0x6009 : "NA_SE_VO_LI_BREATH_REST",
 | |
|     0x600A : "NA_SE_VO_LI_BREATH_DRINK",
 | |
|     0x600B : "NA_SE_VO_LI_DOWN",
 | |
|     0x600C : "NA_SE_VO_LI_TAKEN_AWAY",
 | |
|     0x600D : "NA_SE_VO_LI_HELD",
 | |
|     0x600E : "NA_SE_VO_LI_SNEEZE",
 | |
|     0x600F : "NA_SE_VO_LI_SWEAT",
 | |
|     0x6010 : "NA_SE_VO_LI_DRINK",
 | |
|     0x6011 : "NA_SE_VO_LI_RELAX",
 | |
|     0x6012 : "NA_SE_VO_LI_SWORD_PUTAWAY",
 | |
|     0x6013 : "NA_SE_VO_LI_GROAN",
 | |
|     0x6014 : "NA_SE_VO_LI_AUTO_JUMP",
 | |
|     0x6015 : "NA_SE_VO_LI_MAGIC_NALE",
 | |
|     0x6016 : "NA_SE_VO_LI_SURPRISE",
 | |
|     0x6017 : "NA_SE_VO_LI_MAGIC_FROL",
 | |
|     0x6018 : "NA_SE_VO_LI_PUSH",
 | |
|     0x6019 : "NA_SE_VO_LI_HOOKSHOT_HANG",
 | |
|     0x601A : "NA_SE_VO_LI_LAND_DAMAGE_S",
 | |
|     0x601B : "NA_SE_VO_LI_NULL_0x1b",
 | |
|     0x601C : "NA_SE_VO_LI_MAGIC_ATTACK",
 | |
|     0x601D : "NA_SE_VO_BL_DOWN",
 | |
|     0x601E : "NA_SE_VO_LI_DEMO_DAMAGE",
 | |
|     0x601F : "NA_SE_VO_LI_ELECTRIC_SHOCK_LV",
 | |
|     0x6020 : "NA_SE_VO_LI_SWORD_N_KID",
 | |
|     0x6021 : "NA_SE_VO_LI_ROLLING_CUT_KID",
 | |
|     0x6022 : "NA_SE_VO_LI_LASH_KID",
 | |
|     0x6023 : "NA_SE_VO_LI_HANG_KID",
 | |
|     0x6024 : "NA_SE_VO_LI_CLIMB_END_KID",
 | |
|     0x6025 : "NA_SE_VO_LI_DAMAGE_S_KID",
 | |
|     0x6026 : "NA_SE_VO_LI_FREEZE_KID",
 | |
|     0x6027 : "NA_SE_VO_LI_FALL_S_KID",
 | |
|     0x6028 : "NA_SE_VO_LI_FALL_L_KID",
 | |
|     0x6029 : "NA_SE_VO_LI_BREATH_REST_KID",
 | |
|     0x602A : "NA_SE_VO_LI_BREATH_DRINK_KID",
 | |
|     0x602B : "NA_SE_VO_LI_DOWN_KID",
 | |
|     0x602C : "NA_SE_VO_LI_TAKEN_AWAY_KID",
 | |
|     0x602D : "NA_SE_VO_LI_HELD_KID",
 | |
|     0x602E : "NA_SE_VO_LI_SNEEZE_KID",
 | |
|     0x602F : "NA_SE_VO_LI_SWEAT_KID",
 | |
|     0x6030 : "NA_SE_VO_LI_DRINK_KID",
 | |
|     0x6031 : "NA_SE_VO_LI_RELAX_KID",
 | |
|     0x6032 : "NA_SE_VO_LI_SWORD_PUTAWAY_KID",
 | |
|     0x6033 : "NA_SE_VO_LI_GROAN_KID",
 | |
|     0x6034 : "NA_SE_VO_LI_AUTO_JUMP_KID",
 | |
|     0x6035 : "NA_SE_VO_LI_MAGIC_NALE_KID",
 | |
|     0x6036 : "NA_SE_VO_LI_SURPRISE_KID",
 | |
|     0x6037 : "NA_SE_VO_LI_MAGIC_FROL_KID",
 | |
|     0x6038 : "NA_SE_VO_LI_PUSH_KID",
 | |
|     0x6039 : "NA_SE_VO_LI_HOOKSHOT_HANG_KID",
 | |
|     0x603A : "NA_SE_VO_LI_LAND_DAMAGE_S_KID",
 | |
|     0x603B : "NA_SE_VO_LI_NULL_0x1b_KID",
 | |
|     0x603C : "NA_SE_VO_LI_MAGIC_ATTACK_KID",
 | |
|     0x603D : "NA_SE_VO_BL_DOWN_KID",
 | |
|     0x603E : "NA_SE_VO_LI_DEMO_DAMAGE_KID",
 | |
|     0x603F : "NA_SE_VO_LI_ELECTRIC_SHOCK_LV_KID",
 | |
|     0x6040 : "NA_SE_VO_NAVY_ENEMY",
 | |
|     0x6041 : "NA_SE_VO_NAVY_HELLO",
 | |
|     0x6042 : "NA_SE_VO_NAVY_HEAR",
 | |
|     0x6043 : "NA_SE_VO_NAVY_CALL",
 | |
|     0x6044 : "NA_SE_VO_NA_HELLO_3",
 | |
|     0x6045 : "NA_SE_VO_DUMMY_0x45",
 | |
|     0x6046 : "NA_SE_VO_DUMMY_0x46",
 | |
|     0x6047 : "NA_SE_VO_DUMMY_0x47",
 | |
|     0x6048 : "NA_SE_VO_DUMMY_0x48",
 | |
|     0x6049 : "NA_SE_VO_DUMMY_0x49",
 | |
|     0x604A : "NA_SE_VO_DUMMY_0x4a",
 | |
|     0x604B : "NA_SE_VO_DUMMY_0x4b",
 | |
|     0x604C : "NA_SE_VO_DUMMY_0x4c",
 | |
|     0x604D : "NA_SE_VO_DUMMY_0x4d",
 | |
|     0x604E : "NA_SE_VO_DUMMY_0x4e",
 | |
|     0x604F : "NA_SE_VO_DUMMY_0x4f",
 | |
|     0x6050 : "NA_SE_VO_TA_SLEEP",
 | |
|     0x6051 : "NA_SE_VO_TA_SURPRISE",
 | |
|     0x6052 : "NA_SE_VO_TA_CRY_0",
 | |
|     0x6053 : "NA_SE_VO_TA_CRY_1",
 | |
|     0x6054 : "NA_SE_VO_IN_CRY_0",
 | |
|     0x6055 : "NA_SE_VO_IN_LOST",
 | |
|     0x6056 : "NA_SE_VO_IN_LASH_0",
 | |
|     0x6057 : "NA_SE_VO_IN_LASH_1",
 | |
|     0x6058 : "NA_SE_VO_FR_LAUGH_0",
 | |
|     0x6059 : "NA_SE_VO_FR_SMILE_0",
 | |
|     0x605A : "NA_SE_VO_NB_AGONY",
 | |
|     0x605B : "NA_SE_VO_NB_CRY_0",
 | |
|     0x605C : "NA_SE_VO_NB_NOTICE",
 | |
|     0x605D : "NA_SE_VO_NA_HELLO_0",
 | |
|     0x605E : "NA_SE_VO_NA_HELLO_1",
 | |
|     0x605F : "NA_SE_VO_NA_HELLO_2",
 | |
|     0x6060 : "NA_SE_VO_RT_CRASH",
 | |
|     0x6061 : "NA_SE_VO_RT_DISCOVER",
 | |
|     0x6062 : "NA_SE_VO_RT_FALL",
 | |
|     0x6063 : "NA_SE_VO_RT_LAUGH_0",
 | |
|     0x6064 : "NA_SE_VO_RT_LIFT",
 | |
|     0x6065 : "NA_SE_VO_RT_THROW",
 | |
|     0x6066 : "NA_SE_VO_RT_UNBALLANCE",
 | |
|     0x6067 : "NA_SE_VO_ST_DAMAGE",
 | |
|     0x6068 : "NA_SE_VO_ST_ATTACK",
 | |
|     0x6069 : "NA_SE_VO_Z0_HURRY",
 | |
|     0x606A : "NA_SE_VO_Z0_MEET",
 | |
|     0x606B : "NA_SE_VO_Z0_QUESTION",
 | |
|     0x606C : "NA_SE_VO_Z0_SIGH_0",
 | |
|     0x606D : "NA_SE_VO_Z0_SMILE_0",
 | |
|     0x606E : "NA_SE_VO_Z0_SURPRISE",
 | |
|     0x606F : "NA_SE_VO_Z0_THROW",
 | |
|     0x6070 : "NA_SE_VO_SK_CRY_0",
 | |
|     0x6071 : "NA_SE_VO_SK_CRY_1",
 | |
|     0x6072 : "NA_SE_VO_SK_CRASH",
 | |
|     0x6073 : "NA_SE_VO_SK_LAUGH",
 | |
|     0x6074 : "NA_SE_VO_SK_SHOUT",
 | |
|     0x6075 : "NA_SE_VO_Z1_CRY_0",
 | |
|     0x6076 : "NA_SE_VO_Z1_CRY_1",
 | |
|     0x6077 : "NA_SE_VO_Z1_OPENDOOR",
 | |
|     0x6078 : "NA_SE_VO_Z1_SURPRISE",
 | |
|     0x6079 : "NA_SE_VO_Z1_PAIN",
 | |
|     0x607A : "NA_SE_VO_KZ_MOVE",
 | |
|     0x607B : "NA_SE_VO_NB_LAUGH",
 | |
|     0x607C : "NA_SE_VO_IN_LAUGH",
 | |
|     0x607D : "NA_SE_VO_DUMMY_0x7d",
 | |
|     0x607E : "NA_SE_VO_DUMMY_0x7e",
 | |
|     0x607F : "NA_SE_VO_DUMMY_0x7f",
 | |
| }
 | |
| 
 | |
| def read4(data : bytes, p : int) -> int:
 | |
|     return struct.unpack(">I", data[p:p+4])[0]
 | |
| 
 | |
| def unique_or_none(lst : List[T]) -> Optional[T]:
 | |
|     if not lst:
 | |
|         return None
 | |
|     elem = lst[0]
 | |
|     for e in lst[1:]:
 | |
|         if e != elem:
 | |
|             return None
 | |
|     return elem
 | |
| 
 | |
| class MessageDecoder:
 | |
|     def __init__(self, control_end : int, control_codes : Dict[int, Tuple[str, str, Optional[Tuple[Callable[[int], str]]]]], extraction_charmap : Dict[int, str]) -> None:
 | |
|         self.control_end : int = control_end
 | |
|         self.control_codes : Dict[int, Tuple[str, str, Optional[Tuple[Callable[[int], str]]]]] = control_codes
 | |
|         self.extraction_charmap : Dict[int, str] = extraction_charmap
 | |
|         self.msg : Optional[bytes] = None
 | |
| 
 | |
|     def pop_char(self) -> int:
 | |
|         # Implement in subclass
 | |
|         raise NotImplementedError()
 | |
| 
 | |
|     def pop_char_end(self) -> int:
 | |
|         # Implement in subclass
 | |
|         raise NotImplementedError()
 | |
| 
 | |
|     def decode_char(self, c : int) -> str:
 | |
|         # Implement in subclass
 | |
|         raise NotImplementedError()
 | |
| 
 | |
|     def pop_byte(self) -> int:
 | |
|         c, self.msg = self.msg[0], self.msg[1:]
 | |
|         return c
 | |
| 
 | |
|     def pop_byte_end(self) -> int:
 | |
|         c, self.msg = self.msg[-1], self.msg[:-1]
 | |
|         return c
 | |
| 
 | |
|     def pop_2byte(self) -> int:
 | |
|         u = self.pop_byte()
 | |
|         l = self.pop_byte()
 | |
|         return (u << 8) | l
 | |
| 
 | |
|     def pop_2byte_end(self) -> int:
 | |
|         l = self.pop_byte_end()
 | |
|         u = self.pop_byte_end()
 | |
|         return (u << 8) | l
 | |
| 
 | |
|     def format_sfx_id(self, c : int) -> str:
 | |
|         if c & 0x800:
 | |
|             return sfx_ids[c & ~0x800]
 | |
|         else:
 | |
|             return f"{sfx_ids[c]} - SFX_FLAG"
 | |
| 
 | |
|     def format_item_id(self, c : int) -> str:
 | |
|         return item_ids[c]
 | |
| 
 | |
|     def format_decimal(self, c : int) -> str:
 | |
|         return str(c)
 | |
| 
 | |
|     def format_text_id(self, c : int) -> str:
 | |
|         return f"0x{c:04X}"
 | |
| 
 | |
|     def format_bg_arg(self, c : int) -> str:
 | |
|         return {
 | |
|             0 : "X_LEFT",
 | |
|             1 : "X_RIGHT",
 | |
|         }[c]
 | |
| 
 | |
|     def format_bg_bits1(self, c : int) -> str:
 | |
|         c1 = (c >> 4) & 0xF
 | |
|         c2 = (c >> 0) & 0xF
 | |
| 
 | |
|         fgcol = {
 | |
|             0 : "WHITE",
 | |
|             1 : "DARK_RED",
 | |
|             2 : "ORANGE",
 | |
|             3 : "WHITE_3",
 | |
|             4 : "WHITE_4",
 | |
|             5 : "WHITE_5",
 | |
|             6 : "WHITE_6",
 | |
|             7 : "WHITE_7",
 | |
|         }[c1]
 | |
|         bgcol = {
 | |
|             0 : "BLACK",
 | |
|             1 : "GOLD",
 | |
|             2 : "BLACK_2",
 | |
|             3 : "BLACK_3",
 | |
|         }[c2]
 | |
| 
 | |
|         return f"{fgcol}, {bgcol}"
 | |
| 
 | |
|     def format_bg_bits2(self, c : int) -> str:
 | |
|         c1 = (c >> 4) & 0xF
 | |
|         c2 = (c >> 0) & 0xF
 | |
| 
 | |
|         y_offset = {
 | |
|             0 : "1",
 | |
|             1 : "2",
 | |
|         }[c1]
 | |
| 
 | |
|         return f"{y_offset}, {c2}"
 | |
| 
 | |
|     def emit_tokens(self, tokens : List[Tuple[str, str]]) -> str:
 | |
|         if len(tokens) == 0:
 | |
|             return "\"\""
 | |
| 
 | |
|         out = ""
 | |
| 
 | |
|         q_state = False
 | |
|         s_state = False
 | |
|         nindentlines = 0
 | |
| 
 | |
|         def maybe_enter_q():
 | |
|             nonlocal out, q_state
 | |
|             if not q_state:
 | |
|                 # If we're not in quotes, open quotes
 | |
|                 out += "\""
 | |
|                 q_state = True
 | |
| 
 | |
|         def maybe_exit_q(space=False):
 | |
|             nonlocal out, q_state
 | |
|             if q_state:
 | |
|                 # If we're in quotes, close quotes
 | |
|                 out += "\""
 | |
|                 if space:
 | |
|                     # If the caller asked for a trailing space following closing quotes, also add it
 | |
|                     out += " "
 | |
|                 q_state = False
 | |
| 
 | |
|         for tok_type,tok_dat in tokens:
 | |
|             if tok_type in ("BOX_BREAK", "BOX_BREAK_DELAYED"):
 | |
|                 # Box break has special handling since it is preceded by a newline and followed by two newlines
 | |
| 
 | |
|                 # Close quotes since we're about to newline
 | |
|                 maybe_exit_q()
 | |
|                 nindentlines = 0
 | |
|                 s_state = False
 | |
| 
 | |
|                 # Emit box break control character surrounded by real newlines
 | |
|                 out += "\n" + tok_dat + "\n\n"
 | |
|                 continue
 | |
| 
 | |
|             if s_state:
 | |
|                 # Add a leading space before this token
 | |
|                 out += " "
 | |
|                 s_state = False
 | |
| 
 | |
|             if tok_type == "NEWLINE":
 | |
|                 # Coming up on a newline
 | |
|                 maybe_enter_q()
 | |
|                 # Add the escaped newline character and a real newline
 | |
|                 out += "\\n\"\n"
 | |
|                 # Always closes quotes since we're at EOL
 | |
|                 q_state = False
 | |
|                 # Indent the line if requested
 | |
|                 if nindentlines != 0:
 | |
|                     out += "    "
 | |
|                     nindentlines -= 1
 | |
|             elif tok_type == "TEXT":
 | |
|                 # Coming up on text
 | |
|                 maybe_enter_q()
 | |
|                 # Emit text
 | |
|                 out += tok_dat
 | |
|             else:
 | |
|                 # Control characters
 | |
|                 maybe_exit_q(space=True)
 | |
| 
 | |
|                 # Emit the control character
 | |
|                 out += tok_dat
 | |
| 
 | |
|                 if tok_type == "TWO_CHOICE":
 | |
|                     # Start a new line and indent next two lines
 | |
|                     nindentlines = 2-1
 | |
|                     out += "\n    "
 | |
|                 elif tok_type == "THREE_CHOICE":
 | |
|                     # Start a new line and indent next three lines
 | |
|                     nindentlines = 3-1
 | |
|                     out += "\n    "
 | |
|                 else:
 | |
|                     # No particular special handling
 | |
|                     # Signal to next token to add a trailing space
 | |
|                     s_state = True
 | |
| 
 | |
|         # If the message ended with quotes open, close them
 | |
|         maybe_exit_q()
 | |
| 
 | |
|         if out[-1] == "\n":
 | |
|             out = out[:-1]
 | |
| 
 | |
|         return out
 | |
| 
 | |
|     def decode_ctrl(self, name : str, argfmt : str, formatters : Tuple[Callable[[int], str]]) -> str:
 | |
|         if argfmt == "":
 | |
|             # No args to handle, just return the control char name
 | |
|             return name
 | |
| 
 | |
|         # Read and format args
 | |
|         args : List[int] = []
 | |
|         for a in argfmt:
 | |
|             if a == "x":
 | |
|                 assert self.pop_byte() == 0
 | |
|             else:
 | |
|                 args.append({
 | |
|                     "b" : self.pop_byte,
 | |
|                     "h" : self.pop_2byte,
 | |
|                 }[a]())
 | |
|         return f"{name}({', '.join(formatters[i](a) for i,a in enumerate(args))})"
 | |
| 
 | |
|     def decode(self, msg : bytes) -> str:
 | |
|         if len(msg) == 0:
 | |
|             # Empty message without even an END?
 | |
|             return "None"
 | |
| 
 | |
|         # Strip trailing 0 bytes (assumed padding)
 | |
|         while msg[-1] == 0:
 | |
|             msg = msg[:-1]
 | |
| 
 | |
|         self.msg = msg
 | |
| 
 | |
|         # Must end in an END control code
 | |
|         assert self.pop_char_end() == self.control_end, msg
 | |
| 
 | |
|         tokens : List[Tuple[str, str]] = []
 | |
|         token_run = ""
 | |
|         def flush_text():
 | |
|             nonlocal tokens, token_run
 | |
|             if token_run != "":
 | |
|                 tokens.append(("TEXT", token_run))
 | |
|                 token_run = ""
 | |
| 
 | |
|         # Consume the message, transforming it into tokens
 | |
|         while len(self.msg) != 0:
 | |
|             c = self.pop_char()
 | |
|             # print(f"{c:02X}", self.control_codes.get(c,None))
 | |
| 
 | |
|             if c in self.control_codes:
 | |
|                 # Hit a control character, flush current run of text
 | |
|                 flush_text()
 | |
|                 # Add a token for the control character
 | |
|                 tokens.append((self.control_codes[c][0], self.decode_ctrl(*self.control_codes[c])))
 | |
|             else:
 | |
|                 # Not a control character, accumulate a run of text
 | |
|                 if c in self.extraction_charmap:
 | |
|                     token_run += self.extraction_charmap[c]
 | |
|                 else:
 | |
|                     token_run += self.decode_char(c)
 | |
| 
 | |
|         # Flush any remaining text
 | |
|         flush_text()
 | |
| 
 | |
|         self.msg = None
 | |
| 
 | |
|         # Convert tokens to final decoded text
 | |
|         return self.emit_tokens(tokens)
 | |
| 
 | |
|     def format_highscore(self, c : int) -> str:
 | |
|         return {
 | |
|             0 : "HS_HBA",
 | |
|             1 : "HS_POE_POINTS",
 | |
|             2 : "HS_FISHING",
 | |
|             3 : "HS_HORSE_RACE",
 | |
|             4 : "HS_MARATHON",
 | |
|             5 : "HS_UNK_05",
 | |
|             6 : "HS_DAMPE_RACE",
 | |
|         }[c]
 | |
| 
 | |
| class MessageDecoderJPN(MessageDecoder):
 | |
|     def __init__(self) -> None:
 | |
|         control_end = 0x8170
 | |
|         control_codes = {
 | |
|             0x000A : ("NEWLINE",            "",     None),
 | |
|             0x8170 : ("END",                "",     None),
 | |
|             0x81A5 : ("BOX_BREAK",          "",     None),
 | |
|             0x000B : ("COLOR",              "h",    (self.format_color,)),
 | |
|             0x86C7 : ("SHIFT",              "xb",   (self.format_decimal,)),
 | |
|             0x81CB : ("TEXTID",             "h",    (self.format_text_id,)),
 | |
|             0x8189 : ("QUICKTEXT_ENABLE",   "",     None),
 | |
|             0x818A : ("QUICKTEXT_DISABLE",  "",     None),
 | |
|             0x86C8 : ("PERSISTENT",         "",     None),
 | |
|             0x819F : ("EVENT",              "",     None),
 | |
|             0x81A3 : ("BOX_BREAK_DELAYED",  "xb",   (self.format_decimal,)),
 | |
|             0x81A4 : ("AWAIT_BUTTON_PRESS", "",     None),
 | |
|             0x819E : ("FADE",               "xb",   (self.format_decimal,)),
 | |
|             0x874F : ("NAME",               "",     None),
 | |
|             0x81F0 : ("OCARINA",            "",     None),
 | |
|             0x81F4 : ("FADE2",              "h",    (self.format_decimal,)),
 | |
|             0x81F3 : ("SFX",                "h",    (self.format_sfx_id,)),
 | |
|             0x819A : ("ITEM_ICON",          "xb",   (self.format_item_id,)),
 | |
|             0x86C9 : ("TEXT_SPEED",         "xb",   (self.format_decimal,)),
 | |
|             0x86B3 : ("BACKGROUND",         "xbbb", (self.format_bg_arg, self.format_bg_bits1, self.format_bg_bits2)),
 | |
|             0x8791 : ("MARATHON_TIME",      "",     None),
 | |
|             0x8792 : ("RACE_TIME",          "",     None),
 | |
|             0x879B : ("POINTS",             "",     None),
 | |
|             0x86A3 : ("TOKENS",             "",     None),
 | |
|             0x8199 : ("UNSKIPPABLE",        "",     None),
 | |
|             0x81BC : ("TWO_CHOICE",         "",     None),
 | |
|             0x81B8 : ("THREE_CHOICE",       "",     None),
 | |
|             0x86A4 : ("FISH_INFO",          "",     None),
 | |
|             0x869F : ("HIGHSCORE",          "xb",   (self.format_highscore,)),
 | |
|             0x81A1 : ("TIME",               "",     None),
 | |
|         }
 | |
|         extraction_charmap = {
 | |
|             0x839F : "[A]",
 | |
|             0x83A0 : "[B]",
 | |
|             0x83A1 : "[C]",
 | |
|             0x83A2 : "[L]",
 | |
|             0x83A3 : "[R]",
 | |
|             0x83A4 : "[Z]",
 | |
|             0x83A5 : "[C-Up]",
 | |
|             0x83A6 : "[C-Down]",
 | |
|             0x83A7 : "[C-Left]",
 | |
|             0x83A8 : "[C-Right]",
 | |
|             0x83A9 : "▼",
 | |
|             0x83AA : "[Control-Pad]",
 | |
| 
 | |
|             # Possibly from a SHIFT-JIS extension, python doesn't have builtin support
 | |
|             0x86D3 : "┯",
 | |
|         }
 | |
|         super().__init__(control_end, control_codes, extraction_charmap)
 | |
|         self.pop_char = self.pop_2byte
 | |
|         self.pop_char_end = self.pop_2byte_end
 | |
| 
 | |
|     def decode_char(self, c):
 | |
|         assert c not in range(0x8440, 0x847F), "Hylian codepage unimplemented"
 | |
|         return bytes([c>>8, c &0xFF]).decode("SHIFT-JIS")
 | |
| 
 | |
|     def format_color(self, c):
 | |
|         c1 = c & 0xF
 | |
|         c2 = c & ~0xF
 | |
|         assert c2 == 0x0C00
 | |
|         return {
 | |
|             0 : "DEFAULT",
 | |
|             1 : "RED",
 | |
|             2 : "ADJUSTABLE",
 | |
|             3 : "BLUE",
 | |
|             4 : "LIGHTBLUE",
 | |
|             5 : "PURPLE",
 | |
|             6 : "YELLOW",
 | |
|             7 : "BLACK",
 | |
|         }[c1]
 | |
| 
 | |
| class MessageDecoderNES(MessageDecoder):
 | |
|     def __init__(self) -> None:
 | |
|         control_end = 0x02
 | |
|         control_codes = {
 | |
|             0x01 : ("NEWLINE",            "",    None),
 | |
|             0x02 : ("END",                "",    None),
 | |
|             0x04 : ("BOX_BREAK",          "",    None),
 | |
|             0x05 : ("COLOR",              "b",   (self.format_color,)),
 | |
|             0x06 : ("SHIFT",              "b",   (self.format_decimal,)),
 | |
|             0x07 : ("TEXTID",             "h",   (self.format_text_id,)),
 | |
|             0x08 : ("QUICKTEXT_ENABLE",   "",    None),
 | |
|             0x09 : ("QUICKTEXT_DISABLE",  "",    None),
 | |
|             0x0A : ("PERSISTENT",         "",    None),
 | |
|             0x0B : ("EVENT",              "",    None),
 | |
|             0x0C : ("BOX_BREAK_DELAYED",  "b",   (self.format_decimal,)),
 | |
|             0x0D : ("AWAIT_BUTTON_PRESS", "",    None),
 | |
|             0x0E : ("FADE",               "b",   (self.format_decimal,)),
 | |
|             0x0F : ("NAME",               "",    None),
 | |
|             0x10 : ("OCARINA",            "",    None),
 | |
|             0x11 : ("FADE2",              "h",   (self.format_decimal,)),
 | |
|             0x12 : ("SFX",                "h",   (self.format_sfx_id,)),
 | |
|             0x13 : ("ITEM_ICON",          "b",   (self.format_item_id,)),
 | |
|             0x14 : ("TEXT_SPEED",         "b",   (self.format_decimal,)),
 | |
|             0x15 : ("BACKGROUND",         "bbb", (self.format_bg_arg, self.format_bg_bits1, self.format_bg_bits2)),
 | |
|             0x16 : ("MARATHON_TIME",      "",    None),
 | |
|             0x17 : ("RACE_TIME",          "",    None),
 | |
|             0x18 : ("POINTS",             "",    None),
 | |
|             0x19 : ("TOKENS",             "",    None),
 | |
|             0x1A : ("UNSKIPPABLE",        "",    None),
 | |
|             0x1B : ("TWO_CHOICE",         "",    None),
 | |
|             0x1C : ("THREE_CHOICE",       "",    None),
 | |
|             0x1D : ("FISH_INFO",          "",    None),
 | |
|             0x1E : ("HIGHSCORE",          "b",   (self.format_highscore,)),
 | |
|             0x1F : ("TIME",               "",    None),
 | |
|         }
 | |
|         extraction_charmap = {
 | |
|             0x80 : 'À',
 | |
|             0x81 : 'î',
 | |
|             0x82 : 'Â',
 | |
|             0x83 : 'Ä',
 | |
|             0x84 : 'Ç',
 | |
|             0x85 : 'È',
 | |
|             0x86 : 'É',
 | |
|             0x87 : 'Ê',
 | |
|             0x88 : 'Ë',
 | |
|             0x89 : 'Ï',
 | |
|             0x8A : 'Ô',
 | |
|             0x8B : 'Ö',
 | |
|             0x8C : 'Ù',
 | |
|             0x8D : 'Û',
 | |
|             0x8E : 'Ü',
 | |
|             0x8F : 'ß',
 | |
|             0x90 : 'à',
 | |
|             0x91 : 'á',
 | |
|             0x92 : 'â',
 | |
|             0x93 : 'ä',
 | |
|             0x94 : 'ç',
 | |
|             0x95 : 'è',
 | |
|             0x96 : 'é',
 | |
|             0x97 : 'ê',
 | |
|             0x98 : 'ë',
 | |
|             0x99 : 'ï',
 | |
|             0x9A : 'ô',
 | |
|             0x9B : 'ö',
 | |
|             0x9C : 'ù',
 | |
|             0x9D : 'û',
 | |
|             0x9E : 'ü',
 | |
|             0x9F : '[A]',
 | |
|             0xA0 : '[B]',
 | |
|             0xA1 : '[C]',
 | |
|             0xA2 : '[L]',
 | |
|             0xA3 : '[R]',
 | |
|             0xA4 : '[Z]',
 | |
|             0xA5 : '[C-Up]',
 | |
|             0xA6 : '[C-Down]',
 | |
|             0xA7 : '[C-Left]',
 | |
|             0xA8 : '[C-Right]',
 | |
|             0xA9 : '▼',
 | |
|             0xAA : '[Control-Pad]',
 | |
|             0xAB : '[D-Pad]',
 | |
|         }
 | |
|         super().__init__(control_end, control_codes, extraction_charmap)
 | |
|         self.pop_char = self.pop_byte
 | |
|         self.pop_char_end = self.pop_byte_end
 | |
| 
 | |
|     def decode_char(self, c : int) -> str:
 | |
|         decoded = bytes([c]).decode("ASCII")
 | |
|         # Escape quotes within the text itself
 | |
|         if decoded == "\"":
 | |
|             decoded = "\\\""
 | |
|         return decoded
 | |
| 
 | |
|     def format_color(self, c : int) -> str:
 | |
|         return {
 | |
|             0x40 : "DEFAULT",
 | |
|             0x41 : "RED",
 | |
|             0x42 : "ADJUSTABLE",
 | |
|             0x43 : "BLUE",
 | |
|             0x44 : "LIGHTBLUE",
 | |
|             0x45 : "PURPLE",
 | |
|             0x46 : "YELLOW",
 | |
|             0x47 : "BLACK",
 | |
|         }[c]
 | |
| 
 | |
| # Chinese Characters ordered according to their appearance in nes_font_static.
 | |
| # This unfortunately does not appear to match any standard encoding.
 | |
| CHN_CHARS =      """你借到了一\
 | |
| 颗口袋鸡蛋过夜后就会孵出只,用完\
 | |
| 别忘记把它还回去。归得克洛!与不\
 | |
| 同很少啼叫个奇异蘑菇新鲜的都容易\
 | |
| 变质快拿卡利科药店吧之知道这两人\
 | |
| 间发生什么事但带迷失森林物原主偷\
 | |
| 猎者锯定是那年轻留下炸弹枚卢比买\
 | |
| 德库子可以装弓换破损格雷剑大城修\
 | |
| 好交处方见卓拉王⋯兑券急切地希望\
 | |
| 点铸卖掉巨刀铁匠师所造坚摧卷眼青\
 | |
| 蛙趁凉海鲁湖世上最水在前送蠃啦骷\
 | |
| 髅面具按戴试看着真像怪恐怖吓基顿\
 | |
| 受欢迎哦兔兜帽长耳朵太爱让头起来\
 | |
| 有女孩?理更多我们娱乐中心:保龄\
 | |
| 球场想奖品吗秘密付钱才告诉玩次要\
 | |
| 瞄准洞放鼠十机预备开始再差()捡\
 | |
| 扔没能恢复正常请救其他兄弟给励诅\
 | |
| 咒解除谢报呀啊被小消灭蜘蛛已经减\
 | |
| 弱富办法越些验帮助寻找首先晚行动\
 | |
| 第二住喜松柔土壤仔细观察周围全靠\
 | |
| 成样因为种界每现徽章收集作战绩证\
 | |
| 明征途状态窗此图标旁边数字显示目\
 | |
| 量如果区名说里家族身感止错担需箭\
 | |
| 关系强迫游戏著射击从台够五支武器\
 | |
| 争取祝运堆软泥精灵选择或键并立即\
 | |
| 时举置跑投掷疑型甚至飞檐走壁闪光\
 | |
| 使敌眩晕旋镖攻远短钩条力链勾体获\
 | |
| 自己根木棒挥舞站携浪费锤砸碎废沉\
 | |
| 双手镜神井外也耗魔停笛塞尔达宝散\
 | |
| 芒施展花风返避退火勋圣尼亚觉醒将\
 | |
| 赐予茹特她萨莉娅魂纳波若暗英帕空\
 | |
| 瓶红色命份绿蓝和抓伙伴活随呼唤鱼\
 | |
| 非美豆园合适趣对纪念演奏各律重握\
 | |
| 盾蹲防御移表滑反升级延伸距离倍套\
 | |
| 件隔热穿潜服淹死坛充满靴浮悬缺摩\
 | |
| 擦段勇敢相信超东哥猛龙胃做幸银臂\
 | |
| 答应遵守诺言金焰入冷艳包钥匙打锁\
 | |
| 门限于宫内老却驱喝进然域烁当位拨\
 | |
| 查某层罗盘隐藏振石继续努哇公签临\
 | |
| 西便箱意惊话左右赌徒值威增冰结授\
 | |
| 艰苦训练该拥而荣义邪恶学步曲烈安\
 | |
| 影梦幻镯拔虫员张据翡翠伟树托代传\
 | |
| 碧商讲妖婆堡男情隆牛奶营养排销售\
 | |
| 榜朋友搬日客碰烧毁折断斗习骑士又\
 | |
| 承制尺码护炙侵害底溺掌丁妮席性危\
 | |
| 往创建娜产罩刚清舒爽般暂脱参加嗯\
 | |
| 顾片四整三房干稍候赛鳞跳深歌伊阳\
 | |
| 摇篮雪壮管术接智慧气疲惫治疗伤且\
 | |
| 硬技斩积蓄直释转效谈听束刻注嗨皇\
 | |
| 探儿附近半思仅燃紫价高百索何输虽\
 | |
| 惜幽妙愿勉网墙布藤蔓平爬屏幕顶端\
 | |
| 挂旧梯嘿饰熄久通狭路慢躲调视角弯\
 | |
| 旦侧落块推向兴引爆呢山坑楼绝总巧\
 | |
| 脸私语足导写险雕流粘浑电尾巴几瞧\
 | |
| 旗哪召跟拜访牧爸拯窟卜肚白马丢河\
 | |
| 殿村云吹寒庄谁教沙漠盖侬夫等介联\
 | |
| 声嘻曾领统疆怕鸟黑睛暴雨息初六聚\
 | |
| 封印七认识必须未梭另渡船乘艘咯扇\
 | |
| 许鬼板画廊扭天味冻音座锈漩涡吞嘛\
 | |
| 牢固殊静墓培睡掘阅读式租货款仍;\
 | |
| 载贪婪仇恨血腥历史诡计谜题亡闭今\
 | |
| 业早招聘兼职杂指启遗极亮照闯穴伏\
 | |
| 阻拦朝囚室贝泊泉黎童纯洁翻嘴陷野\
 | |
| 研究考坏竟坐玛录钓磅分纹誓忠哈眠\
 | |
| 瀑国务盯毯踩资瞎难倒阱塘屈镇径窄\
 | |
| 慌允禁激颁喷扰砍持草泰沿实峡谷册\
 | |
| 追赶市蜃崖灼宣疯狂滚伞脚共部免规\
 | |
| 递登补肉歉刺杀节横纵礼貌米无孪姐\
 | |
| 妹改池胆跃任句线范逃期待丽问闲泳\
 | |
| 连北棵锐虑挤障碍盔甲假设温际顽皮\
 | |
| 姆违盗贼蝴蝶崇象猫鹰凯普・博古化\
 | |
| 笨朗匹雄赚寄卵幼突袭腹绦食笔竖枯\
 | |
| 矮丛吃震撼吸败蜥蜴蝙蝠否则阿莫斯\
 | |
| 母绕触傻遭汀幅敬诱泡挡沃衣炬黏背\
 | |
| 抵权核挑壳肌缩邦苏透僵尸麻痹咬吉\
 | |
| 乃穷尽裂拢娃傀儡亲巫低骨斧漏莱彼\
 | |
| 塔扫描烟蛇弗扎挺八爪迪困陆嗜仙狼\
 | |
| 懈贩麦判乔绽速嗄羞永稻终薇呵父程\
 | |
| 工存氛笼令敏项欧谅众悍怎亏掏毕缓\
 | |
| 冲酷俯瞰哼蚀功糟呸黄类篇论控括冒\
 | |
| 度检单懂屋户致腾模嗒咔咋萎紧决呆\
 | |
| 闷畏骗苗茁算猜残妇婴蔽唯响抚吵境\
 | |
| 隙逝忆喂辈肩洋溢确迹凝髓混沌降健\
 | |
| 耕耘星倾沛础堂万宗源本替缝惩罚遇\
 | |
| 懒惰衷势维秩序抗衡旅顺叛愤辽阔茂\
 | |
| 称讨厌靶饲求材耶谊噓遍谱议吼薄饶\
 | |
| 稽齐懦抱千辛漂环配帝焦乎欠驯圈局\
 | |
| 咩既劳祭伪弃耐岗唔佳搭档负责攀绍\
 | |
| 忙提缠唉亳毛笑欣赏怜瓜奔啧踢志宜\
 | |
| 仿楚挖由捕播谣勤陌杰骏鞭抽享栏逛\
 | |
| 汊烦匆妈唱墟粗虐乡彻咕哝简优惠民\
 | |
| 灰聪南澈卫熟悉故乌兆企抢夺拼粉番\
 | |
| 群秒料肯赋婚诚邀斜诞及盛典拍轰植\
 | |
| 矿采阴罕昏压悦饿忍咳弄舔醉怀尊严\
 | |
| 滋农饥沮丧奋省撑脑灯隧派狗呜咣警\
 | |
| 挪窜峙含痛夸艺撒谎昨炎痒泪稳况磨\
 | |
| 休柱敲油菜盟骄傲献噢窒医甜鰓恼耽\
 | |
| 搁孤丈订戒贵财惹腐剂融厚映妻狠泄\
 | |
| 咿瞒咽恭涨嘎悔犹豫呃糕埃荡漾饵晃\
 | |
| 约专剔窍.乱甩鳅剧竿杆符呱团饱犯\
 | |
| 肃啵吟月诗碑奥扬舍副袖夏赖仆摆雇\
 | |
| 疙瘩居簧车剩玻璃赔欺育珍床蛮啄、\
 | |
| 稀栋柜鼻厉乏饭胡叮咚兵勃苛薪痴挣\
 | |
| 馊扑良竭慷慨欲愚蠢嘉监狱喔港逆误\
 | |
| 独划措颜奴罢洗俊罪偿牺牲劲岁恩账\
 | |
| 珂艾组织伯社架桥碟卑鄙臭占讶兽刷\
 | |
| 竞帐篷迟繁倦罐牌晨景田孔钻浓盒溜\
 | |
| 街概盹敞扉文撞姑娘糊涂依辐微汇缚\
 | |
| 宰摸侍垒扮惕估执悲拖累弥渴班搞谛\
 | |
| 哀圆鸣俩善塌埋孙凶聊寃怨购涌劈狐\
 | |
| 狸票闻哟唬摘愉呦棺溶褐肤颤逗娶逼\
 | |
| 悠蒙漆彩丰"""
 | |
| # Ensure the contents of the above is unique
 | |
| assert len(set(CHN_CHARS)) == len(CHN_CHARS), (len(set(CHN_CHARS)), len(CHN_CHARS))
 | |
| 
 | |
| class MessageDecoderCHN(MessageDecoderNES):
 | |
|     def __init__(self) -> None:
 | |
|         # The CHN text encoding is mostly the same as the NES encoding, except it lacks
 | |
|         # the D-Pad Icon and has multi-byte sequences for Chinese characters.
 | |
|         super().__init__()
 | |
|         # Remove D-Pad Icon
 | |
|         self.extraction_charmap.pop(0xAB)
 | |
|         # Add Chinese Characters
 | |
|         for i,c in enumerate(CHN_CHARS):
 | |
|             self.extraction_charmap[0xA08C + i] = c
 | |
|         self.pop_char = self.pop_char_chn
 | |
| 
 | |
|     def pop_char_chn(self) -> int:
 | |
|         c = self.pop_byte()
 | |
|         # AA acts like a sort of escape sequence for single-byte
 | |
|         # chars that are >= 0xA0 that should not be interpreted
 | |
|         # as a multi-byte sequence
 | |
|         if c == 0xAA:
 | |
|             return self.pop_byte()
 | |
|         # For other chars >= 0xA0, it indicates a multi-byte sequence
 | |
|         if c >= 0xA0:
 | |
|             return (c << 8) | self.pop_byte()
 | |
|         # If neither of the above, treat as a single byte char
 | |
|         return c
 | |
| 
 | |
| class MessageTableDesc:
 | |
|     def __init__(self, table_name : str, seg_name : str, decoder : MessageDecoder, parent : Optional[int]) -> None:
 | |
|         self.table_name : str = table_name
 | |
|         self.seg_name : str = seg_name
 | |
|         self.decoder : MessageDecoder = decoder
 | |
|         self.parent : Optional[int] = parent
 | |
| 
 | |
| class MessageTableEntry:
 | |
|     SIZE = 8
 | |
| 
 | |
|     def __init__(self, text_id : int, box_type : int, box_pos : int, addr : int) -> None:
 | |
|         self.text_id, self.box_type, self.box_pos, self.addr = text_id, box_type, box_pos, addr
 | |
| 
 | |
|     def __str__(self) -> str:
 | |
|         return f"MessageTableEntry(0x{self.text_id:04X}, {self.box_type}, {self.box_pos}, 0x{self.addr:08X})"
 | |
| 
 | |
|     @staticmethod
 | |
|     def from_bin(data : bytes) -> "MessageTableEntry":
 | |
|         text_id,info,addr = struct.unpack(">HBxI", data)
 | |
|         box_type = (info >> 4) & 0xF
 | |
|         box_pos  = (info >> 0) & 0xF
 | |
|         return MessageTableEntry(text_id, box_type, box_pos, addr)
 | |
| 
 | |
| class MessageData:
 | |
|     def __init__(self, box_type : int, box_pos : int, decoded_text : str):
 | |
|         self.box_type : int = box_type
 | |
|         self.box_pos : int = box_pos
 | |
|         self.decoded_text : str = decoded_text
 | |
| 
 | |
| class MessageEntry:
 | |
|     def __init__(self, message_tables : List[Optional[MessageTableDesc]], text_id : int) -> None:
 | |
|         self.text_id : int = text_id
 | |
|         self.data : List[Optional[MessageData]] = [None for _ in message_tables]
 | |
|         self.select = tuple(tbl is not None for tbl in message_tables)
 | |
| 
 | |
|     def define_message(self, defn : str, box_type : int, box_pos : int, data : List[Optional[MessageData]]) -> str:
 | |
|         box_type_str = {
 | |
|             0: "TEXTBOX_TYPE_BLACK",
 | |
|             1: "TEXTBOX_TYPE_WOODEN",
 | |
|             2: "TEXTBOX_TYPE_BLUE",
 | |
|             3: "TEXTBOX_TYPE_OCARINA",
 | |
|             4: "TEXTBOX_TYPE_NONE_BOTTOM",
 | |
|             5: "TEXTBOX_TYPE_NONE_NO_SHADOW",
 | |
|             0xB: "TEXTBOX_TYPE_CREDITS",
 | |
|         }[box_type]
 | |
|         box_pos_str = {
 | |
|             0: "TEXTBOX_POS_VARIABLE",
 | |
|             1: "TEXTBOX_POS_TOP",
 | |
|             2: "TEXTBOX_POS_MIDDLE",
 | |
|             3: "TEXTBOX_POS_BOTTOM",
 | |
|         }[box_pos]
 | |
|         out = f"{defn}(0x{self.text_id:04X}, {box_type_str}, {box_pos_str},\n"
 | |
|         out += "\n,\n".join(f"MSG(\n{d.decoded_text}\n)" if d is not None else "MSG(/* MISSING */)" for d in data)
 | |
|         out += "\n)\n"
 | |
|         return out
 | |
| 
 | |
|     def decode(self) -> str:
 | |
|         selection = tuple(not (select and data is None) for select,data in zip(self.select,self.data))
 | |
|         assert any(selection)
 | |
| 
 | |
|         out = ""
 | |
|         if all(selection):
 | |
|             shared_box_type = unique_or_none([data.box_type for data in self.data if data is not None])
 | |
|             shared_box_pos = unique_or_none([data.box_pos for data in self.data if data is not None])
 | |
|             if shared_box_type is not None and shared_box_pos is not None:
 | |
|                 # Valid for all languages
 | |
|                 out += self.define_message("DEFINE_MESSAGE", shared_box_type, shared_box_pos, self.data)
 | |
|             else:
 | |
|                 # Some NTSC/iQue messages have different box types/positions between JPN and NES/CHN,
 | |
|                 # so emit both DEFINE_MESSAGE_JPN and DEFINE_MESSAGE_NES
 | |
|                 assert len(self.data) == 4
 | |
|                 assert self.data[0] is not None
 | |
|                 assert self.data[1] is not None
 | |
|                 assert self.data[2] is None
 | |
|                 assert self.data[3] is None
 | |
|                 out += self.define_message("DEFINE_MESSAGE_JPN", self.data[0].box_type, self.data[0].box_pos, [self.data[0], None, None, None])
 | |
|                 out += self.define_message("DEFINE_MESSAGE_NES", self.data[1].box_type, self.data[1].box_pos, [None, self.data[1], None, None])
 | |
|         elif selection == (True,False,True,True):
 | |
|             # JPN only
 | |
|             out += self.define_message("DEFINE_MESSAGE_JPN", self.data[0].box_type, self.data[0].box_pos, self.data)
 | |
|         elif selection == (False,True,True,True):
 | |
|             # NES/CHN only
 | |
|             out += self.define_message("DEFINE_MESSAGE_NES", self.data[1].box_type, self.data[1].box_pos, self.data)
 | |
|         else:
 | |
|             # Other unimplemented cases
 | |
|             assert False
 | |
| 
 | |
|         return out
 | |
| 
 | |
| def collect_messages(message_tables : List[Optional[MessageTableDesc]], baserom_segments_dir : Path,
 | |
|                      config : version_config.VersionConfig, code_vram : int, code_bin : bytes):
 | |
| 
 | |
|     messages : Dict[int,MessageEntry] = {}
 | |
| 
 | |
|     all_text_ids : List[Optional[List[int]]] = [None for _ in range(len(message_tables))]
 | |
| 
 | |
|     for lang_num,desc in enumerate(message_tables):
 | |
|         if desc is None:
 | |
|             continue
 | |
| 
 | |
|         baserom_seg = (baserom_segments_dir / desc.seg_name).read_bytes()
 | |
|         code_offset = config.variables[desc.table_name] - code_vram
 | |
| 
 | |
|         if desc.parent is None:
 | |
|             # Complete table
 | |
| 
 | |
|             table_entries : List[MessageTableEntry] = []
 | |
|             text_ids : List[int] = []
 | |
| 
 | |
|             while True:
 | |
|                 end = code_offset + MessageTableEntry.SIZE
 | |
|                 entry = MessageTableEntry.from_bin(code_bin[code_offset:end])
 | |
|                 code_offset = end
 | |
| 
 | |
|                 table_entries.append(entry)
 | |
|                 text_ids.append(entry.text_id)
 | |
| 
 | |
|                 if entry.text_id == 0xFFFF:
 | |
|                     break
 | |
| 
 | |
|             all_text_ids[lang_num] = text_ids
 | |
| 
 | |
|             for i in range(len(table_entries) - 1):
 | |
|                 curr = table_entries[i + 0]
 | |
|                 next = table_entries[i + 1]
 | |
| 
 | |
|                 curr_offset = curr.addr & ~0x0F000000
 | |
|                 next_offset = (next.addr & ~0x0F000000) if next.text_id != 0xFFFF else len(baserom_seg)
 | |
|                 size = next_offset - curr_offset
 | |
| 
 | |
|                 if curr.text_id not in messages:
 | |
|                     messages[curr.text_id] = MessageEntry(message_tables, curr.text_id)
 | |
|                 messages[curr.text_id].data[lang_num] = MessageData(
 | |
|                     curr.box_type, curr.box_pos, desc.decoder.decode(baserom_seg[curr_offset : curr_offset+size]))
 | |
|         else:
 | |
|             # Addresses only
 | |
| 
 | |
|             for text_id in all_text_ids[desc.parent][:-1]: # Exclude text id 0xFFFF
 | |
|                 if text_id in (0xFFFC,):
 | |
|                     continue
 | |
| 
 | |
|                 curr = read4(code_bin, code_offset + 0)
 | |
|                 next = read4(code_bin, code_offset + 4)
 | |
|                 code_offset += 4
 | |
| 
 | |
|                 curr_offset = curr & ~0x0F000000
 | |
|                 next_offset = next & ~0x0F000000 if text_id != 0xFFFD else len(baserom_seg)
 | |
|                 size = next_offset - curr_offset
 | |
| 
 | |
|                 # The text id is guaranteed to already exist
 | |
|                 parent_data = messages[text_id].data[desc.parent]
 | |
|                 messages[text_id].data[lang_num] = MessageData(
 | |
|                     parent_data.box_type, parent_data.box_pos, desc.decoder.decode(baserom_seg[curr_offset:curr_offset+size]))
 | |
| 
 | |
|     return messages
 | |
| 
 | |
| def main():
 | |
|     parser = argparse.ArgumentParser(description="Extract text from the baserom into .h files")
 | |
|     parser.add_argument(
 | |
|         "baserom_segments_dir",
 | |
|         type=Path,
 | |
|         help="Directory of uncompressed ROM segments",
 | |
|     )
 | |
|     parser.add_argument(
 | |
|         "output_dir",
 | |
|         type=Path,
 | |
|         help="Output directory to place files in",
 | |
|     )
 | |
|     parser.add_argument(
 | |
|         "-v",
 | |
|         "--version",
 | |
|         dest="oot_version",
 | |
|         required=True,
 | |
|         help="OOT version",
 | |
|     )
 | |
|     args = parser.parse_args()
 | |
| 
 | |
|     baserom_segments_dir : Path = args.baserom_segments_dir
 | |
|     version : str = args.oot_version
 | |
|     output_dir : Path = args.output_dir
 | |
| 
 | |
|     args.output_dir.mkdir(parents=True, exist_ok=True)
 | |
| 
 | |
|     config = version_config.load_version_config(version)
 | |
|     code_vram = config.dmadata_segments["code"].vram
 | |
| 
 | |
|     # print(hex(code_vram))
 | |
| 
 | |
|     code_bin = (baserom_segments_dir / "code").read_bytes()
 | |
| 
 | |
|     jpn_decoder = MessageDecoderJPN()
 | |
|     nes_decoder = MessageDecoderNES()
 | |
|     chn_decoder = MessageDecoderCHN()
 | |
| 
 | |
|     message_tables : List[Optional[MessageTableDesc]] = [None for _ in range(4)] # JP, EN/CN, FR, DE
 | |
|     message_table_staff : MessageTableDesc = None
 | |
| 
 | |
|     if config.text_lang == "NTSC":
 | |
|         message_tables[0]   = MessageTableDesc("sJpnMessageEntryTable",   "jpn_message_data_static",   jpn_decoder, None)
 | |
|         message_tables[1]   = MessageTableDesc("sNesMessageEntryTable",   "nes_message_data_static",   nes_decoder, None)
 | |
|         message_tables[2]   = None
 | |
|         message_tables[3]   = None
 | |
|         message_table_staff = MessageTableDesc("sStaffMessageEntryTable", "staff_message_data_static", nes_decoder, None)
 | |
|     elif config.text_lang == "PAL":
 | |
|         message_tables[0]   = None
 | |
|         message_tables[1]   = MessageTableDesc("sNesMessageEntryTable",   "nes_message_data_static",   nes_decoder, None)
 | |
|         message_tables[2]   = MessageTableDesc("sGerMessageEntryTable",   "ger_message_data_static",   nes_decoder, 1)
 | |
|         message_tables[3]   = MessageTableDesc("sFraMessageEntryTable",   "fra_message_data_static",   nes_decoder, 1)
 | |
|         message_table_staff = MessageTableDesc("sStaffMessageEntryTable", "staff_message_data_static", nes_decoder, None)
 | |
|     elif config.text_lang == "CN":
 | |
|         message_tables[0]   = MessageTableDesc("sJpnMessageEntryTable",   "jpn_message_data_static",   jpn_decoder, None)
 | |
|         message_tables[1]   = MessageTableDesc("sNesMessageEntryTable",   "nes_message_data_static",   chn_decoder, None)
 | |
|         message_tables[2]   = None
 | |
|         message_tables[3]   = None
 | |
|         message_table_staff = MessageTableDesc("sStaffMessageEntryTable", "staff_message_data_static", nes_decoder, None)
 | |
|     else:
 | |
|         raise Exception(f"Unsupported text language: {config.text_lang}")
 | |
| 
 | |
|     messages = collect_messages(message_tables, baserom_segments_dir, config, code_vram, code_bin)
 | |
|     staff_messages = collect_messages([message_table_staff], baserom_segments_dir, config, code_vram, code_bin)
 | |
| 
 | |
|     message_data = []
 | |
| 
 | |
|     for text_id in sorted(messages.keys()):
 | |
|         if text_id in (0xFFFC,0xFFFD):
 | |
|             # Skip committed text ids
 | |
|             continue
 | |
|         message_data.append(messages[text_id].decode())
 | |
| 
 | |
|     message_data = "\n".join(message_data)
 | |
|     message_data_staff = "\n".join(staff_messages[text_id].decode() for text_id in sorted(staff_messages.keys()))
 | |
| 
 | |
|     (output_dir / "message_data.h").write_text(message_data)
 | |
|     (output_dir / "message_data_staff.h").write_text(message_data_staff)
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     main()
 |