#!/usr/bin/env python3 import argparse, os, struct actor_names = [ "ovl_Player_Actor", "ovl_En_Test", "ovl_En_GirlA", "ovl_En_Part", "ovl_En_Light", "ovl_En_Door", "ovl_En_Box", "ovl_En_Pametfrog", "ovl_En_Okuta", "ovl_En_Bom", "ovl_En_Wallmas", "ovl_En_Dodongo", "ovl_En_Firefly", "ovl_En_Horse", "ovl_En_Item00", "ovl_En_Arrow", "ovl_En_Elf", "ovl_En_Niw", "ovl_En_Tite", "", "ovl_En_Peehat", "ovl_En_Butte", "ovl_En_Insect", "ovl_En_Fish", "ovl_En_Holl", "ovl_En_Dinofos", "ovl_En_Hata", "ovl_En_Zl1", "ovl_En_Viewer", "ovl_En_Bubble", "ovl_Door_Shutter", "", "ovl_En_Boom", "ovl_En_Torch2", "ovl_En_Minifrog", "", "ovl_En_St", "", "ovl_En_A_Obj", "ovl_Obj_Wturn", "ovl_En_River_Sound", "", "ovl_En_Ossan", "", "", "ovl_En_Famos", "", "ovl_En_Bombf", "", "", "ovl_En_Am", "ovl_En_Dekubaba", "ovl_En_M_Fire1", "ovl_ovl_En_M_Thunder", "ovl_Bg_Breakwall", "", "ovl_Door_Warp1", "ovl_Obj_Syokudai", "ovl_Item_B_Heart", "ovl_En_Dekunuts", "ovl_En_Bbfall", "ovl_Arms_Hook", "ovl_En_Bb", "ovl_Bg_Keikoku_Spr", "", "ovl_En_Wood02", "", "ovl_En_Death", "ovl_En_Minideath", "", "", "ovl_En_Vm", "ovl_Demo_Effect", "ovl_Demo_Kankyo", "ovl_En_Floormas", "", "ovl_En_Rd", "ovl_Bg_F40_Flift", "", "ovl_Obj_Mure", "ovl_En_Sw", "ovl_Object_Kankyo", "", "", "ovl_En_Horse_Link_Child", "ovl_Door_Ana", "", "", "", "", "", "ovl_En_Encount1", "ovl_Demo_Tre_Lgt", "", "", "ovl_En_Encount2", "ovl_En_Fire_Rock", "ovl_Bg_Ctower_Rot", "ovl_Mir_Ray", "", "ovl_En_Sb", "ovl_En_Bigslime", "ovl_En_Karebaba", "ovl_En_In", "", "ovl_En_Ru", "ovl_En_Bom_Chu", "ovl_En_Horse_Game_Check", "ovl_En_Rr", "", "", "", "", "", "", "ovl_En_Fr", "", "", "", "", "", "ovl_En_Fishing", "ovl_Obj_Oshihiki", "ovl_Eff_Dust", "ovl_Bg_Umajump", "ovl_Arrow_Fire", "ovl_Arrow_Ice", "ovl_Arrow_Light", "ovl_Item_Etcetera", "ovl_Obj_Kibako", "ovl_Obj_Tsubo", "", "ovl_En_Ik", "", "", "", "", "ovl_Demo_Shd", "ovl_En_Dns", "ovl_Elf_Msg", "ovl_En_Honotrap", "ovl_En_Tubo_Trap", "ovl_Obj_Ice_Poly", "ovl_En_Fz", "ovl_En_Kusa", "ovl_Obj_Bean", "ovl_Obj_Bombiwa", "ovl_Obj_Switch", "", "ovl_Obj_Lift", "ovl_Obj_Hsblock", "ovl_En_Okarina_Tag", "", "ovl_En_Goroiwa", "", "", "ovl_En_Daiku", "ovl_En_Nwc", "ovl_Item_Inbox", "ovl_En_Ge1", "ovl_Obj_Blockstop", "ovl_En_Sda", "ovl_En_Clear_Tag", "", "ovl_En_Gm", "ovl_En_Ms", "ovl_En_Hs", "ovl_Bg_Ingate", "ovl_En_Kanban", "", "ovl_En_Attack_Niw", "", "", "", "ovl_En_Mk", "ovl_En_Owl", "ovl_En_Ishi", "ovl_Obj_Hana", "ovl_Obj_Lightswitch", "ovl_Obj_Mure2", "", "ovl_En_Fu", "", "", "ovl_En_Stream", "ovl_En_Mm", "", "", "ovl_En_Weather_Tag", "ovl_En_Ani", "", "ovl_En_Js", "", "", "", "", "ovl_En_Okarina_Effect", "ovl_En_Mag", "ovl_Elf_Msg2", "ovl_Bg_F40_Swlift", "", "", "ovl_En_Kakasi", "ovl_Obj_Makeoshihiki", "ovl_Oceff_Spot", "", "ovl_En_Torch", "", "ovl_Shot_Sun", "", "", "ovl_Obj_Roomtimer", "ovl_En_Ssh", "", "ovl_Oceff_Wipe", "ovl_Oceff_Storm", "ovl_Obj_Demo", "ovl_En_Minislime", "ovl_En_Nutsball", "", "", "", "", "ovl_Oceff_Wipe2", "ovl_Oceff_Wipe3", "", "ovl_En_Dg", "ovl_En_Si", "ovl_Obj_Comb", "ovl_Obj_Kibako2", "", "ovl_En_Hs2", "ovl_Obj_Mure3", "ovl_En_Tg", "", "", "ovl_En_Wf", "ovl_En_Skb", "", "ovl_En_Gs", "ovl_Obj_Sound", "ovl_En_Crow", "", "ovl_En_Cow", "", "", "ovl_Oceff_Wipe4", "", "ovl_En_Zo", "ovl_Obj_Makekinsuta", "ovl_En_Ge3", "", "ovl_Obj_Hamishi", "ovl_En_Zl4", "ovl_En_Mm2", "", "ovl_Door_Spiral", "", "ovl_Obj_Pzlblock", "ovl_Obj_Toge", "", "ovl_Obj_Armos", "ovl_Obj_Boyo", "", "", "ovl_En_Grasshopper", "", "ovl_Obj_Grass", "ovl_Obj_Grass_Carry", "ovl_Obj_Grass_Unit", "", "", "ovl_Bg_Fire_Wall", "ovl_En_Bu", "ovl_En_Encount3", "ovl_En_Jso", "ovl_Obj_Chikuwa", "ovl_En_Knight", "ovl_En_Warp_tag", "ovl_En_Aob_01", "ovl_En_Boj_01", "ovl_En_Boj_02", "ovl_En_Boj_03", "ovl_En_Encount4", "ovl_En_Bom_Bowl_Man", "ovl_En_Syateki_Man", "", "ovl_Bg_Icicle", "ovl_En_Syateki_Crow", "ovl_En_Boj_04", "ovl_En_Cne_01", "ovl_En_Bba_01", "ovl_En_Bji_01", "ovl_Bg_Spdweb", "", "", "ovl_En_Mt_tag", "ovl_Boss_01", "ovl_Boss_02", "ovl_Boss_03", "ovl_Boss_04", "ovl_Boss_05", "ovl_Boss_06", "ovl_Boss_07", "ovl_Bg_Dy_Yoseizo", "", "ovl_En_Boj_05", "", "", "ovl_En_Sob1", "", "", "ovl_En_Go", "", "ovl_En_Raf", "ovl_Obj_Funen", "ovl_Obj_Raillift", "ovl_Bg_Numa_Hana", "ovl_Obj_Flowerpot", "ovl_Obj_Spinyroll", "ovl_Dm_Hina", "ovl_En_Syateki_Wf", "ovl_Obj_Skateblock", "ovl_Obj_Iceblock", "ovl_En_Bigpamet", "ovl_En_Syateki_Dekunuts", "ovl_Elf_Msg3", "ovl_En_Fg", "ovl_Dm_Ravine", "ovl_Dm_Sa", "ovl_En_Slime", "ovl_En_Pr", "ovl_Obj_Toudai", "ovl_Obj_Entotu", "ovl_Obj_Bell", "ovl_En_Syateki_Okuta", "", "ovl_Obj_Shutter", "ovl_Dm_Zl", "ovl_En_Elfgrp", "ovl_Dm_Tsg", "ovl_En_Baguo", "ovl_Obj_Vspinyroll", "ovl_Obj_Smork", "ovl_En_Test2", "ovl_En_Test3", "ovl_En_Test4", "ovl_En_Bat", "ovl_En_Sekihi", "ovl_En_Wiz", "ovl_En_Wiz_Brock", "ovl_En_Wiz_Fire", "ovl_Eff_Change", "ovl_Dm_Statue", "ovl_Obj_Fireshield", "ovl_Bg_Ladder", "ovl_En_Mkk", "ovl_Demo_Getitem", "", "ovl_En_Dnb", "ovl_En_Dnh", "ovl_En_Dnk", "ovl_En_Dnq", "", "ovl_Bg_Keikoku_Saku", "ovl_Obj_Hugebombiwa", "ovl_En_Firefly2", "ovl_En_Rat", "ovl_En_Water_Effect", "ovl_En_Kusa2", "ovl_Bg_Spout_Fire", "", "ovl_Bg_Dblue_Movebg", "ovl_En_Dy_Extra", "ovl_En_Bal", "ovl_En_Ginko_Man", "ovl_En_Warp_Uzu", "ovl_Obj_Driftice", "ovl_En_Look_Nuts", "ovl_En_Mushi2", "ovl_En_Fall", "ovl_En_Mm3", "ovl_Bg_Crace_Movebg", "ovl_En_Dno", "ovl_En_Pr2", "ovl_En_Prz", "ovl_En_Jso2", "ovl_Obj_Etcetera", "ovl_En_Egol", "ovl_Obj_Mine", "ovl_Obj_Purify", "ovl_En_Tru", "ovl_En_Trt", "", "", "ovl_En_Test5", "ovl_En_Test6", "ovl_En_Az", "ovl_En_Estone", "ovl_Bg_Hakugin_Post", "ovl_Dm_Opstage", "ovl_Dm_Stk", "ovl_Dm_Char00", "ovl_Dm_Char01", "ovl_Dm_Char02", "ovl_Dm_Char03", "ovl_Dm_Char04", "ovl_Dm_Char05", "ovl_Dm_Char06", "ovl_Dm_Char07", "ovl_Dm_Char08", "ovl_Dm_Char09", "ovl_Obj_Tokeidai", "", "ovl_En_Mnk", "ovl_En_Egblock", "ovl_En_Guard_Nuts", "ovl_Bg_Hakugin_Bombwall", "ovl_Obj_Tokei_Tobira", "ovl_Bg_Hakugin_Elvpole", "ovl_En_Ma4", "ovl_En_Twig", "ovl_En_Po_Fusen", "ovl_En_Door_Etc", "ovl_En_Bigokuta", "ovl_Bg_Icefloe", "ovl_Obj_Ocarinalift", "ovl_En_Time_Tag", "ovl_Bg_Open_Shutter", "ovl_Bg_Open_Spot", "ovl_Bg_Fu_Kaiten", "ovl_Obj_Aqua", "ovl_En_Elforg", "ovl_En_Elfbub", "", "ovl_En_Fu_Mato", "ovl_En_Fu_Kago", "ovl_En_Osn", "ovl_Bg_Ctower_Gear", "ovl_En_Trt2", "ovl_Obj_Tokei_Step", "ovl_Bg_Lotus", "ovl_En_Kame", "ovl_Obj_Takaraya_Wall", "ovl_Bg_Fu_Mizu", "ovl_En_Sellnuts", "ovl_Bg_Dkjail_Ivy", "", "ovl_Obj_Visiblock", "ovl_En_Takaraya", "ovl_En_Tsn", "ovl_En_Ds2n", "ovl_En_Fsn", "ovl_En_Shn", "", "ovl_En_Stop_heishi", "ovl_Obj_Bigicicle", "ovl_En_Lift_Nuts", "ovl_En_Tk", "", "ovl_Bg_Market_Step", "ovl_Obj_Lupygamelift", "ovl_En_Test7", "ovl_Obj_Lightblock", "ovl_Mir_Ray2", "ovl_En_Wdhand", "ovl_En_Gamelupy", "ovl_Bg_Danpei_Movebg", "ovl_En_Snowwd", "ovl_En_Pm", "ovl_En_Gakufu", "ovl_Elf_Msg4", "ovl_Elf_Msg5", "ovl_En_Col_Man", "ovl_En_Talk_Gibud", "ovl_En_Giant", "ovl_Obj_Snowball", "ovl_Boss_Hakugin", "ovl_En_Gb2", "ovl_En_Onpuman", "ovl_Bg_Tobira01", "ovl_En_Tag_Obj", "ovl_Obj_Dhouse", "ovl_Obj_Hakaisi", "ovl_Bg_Hakugin_Switch", "", "ovl_En_Snowman", "ovl_TG_Sw", "ovl_En_Po_Sisters", "ovl_En_Pp", "ovl_En_Hakurock", "ovl_En_Hanabi", "ovl_Obj_Dowsing", "ovl_Obj_Wind", "ovl_En_Racedog", "ovl_En_Kendo_Js", "ovl_Bg_Botihasira", "ovl_En_Fish2", "ovl_En_Pst", "ovl_En_Poh", "ovl_Obj_Spidertent", "ovl_En_Zoraegg", "ovl_En_Kbt", "ovl_En_Gg", "ovl_En_Maruta", "ovl_Obj_Snowball2", "ovl_En_Gg2", "ovl_Obj_Ghaka", "ovl_En_Dnp", "ovl_En_Dai", "ovl_Bg_Goron_Oyu", "ovl_En_Kgy", "ovl_En_Invadepoh", "ovl_En_Gk", "ovl_En_An", "", "ovl_En_Bee", "ovl_En_Ot", "ovl_En_Dragon", "ovl_Obj_Dora", "ovl_En_Bigpo", "ovl_Obj_Kendo_Kanban", "ovl_Obj_Hariko", "ovl_En_Sth", "ovl_Bg_Sinkai_Kabe", "ovl_Bg_Haka_Curtain", "ovl_Bg_Kin2_Bombwall", "ovl_Bg_Kin2_Fence", "ovl_Bg_Kin2_Picture", "ovl_Bg_Kin2_Shelf", "ovl_En_Rail_Skb", "ovl_En_Jg", "ovl_En_Tru_Mt", "ovl_Obj_Um", "ovl_En_Neo_Reeba", "ovl_Bg_Mbar_Chair", "ovl_Bg_Ikana_Block", "ovl_Bg_Ikana_Mirror", "ovl_Bg_Ikana_Rotaryroom", "ovl_Bg_Dblue_Balance", "ovl_Bg_Dblue_Waterfall", "ovl_En_Kaizoku", "ovl_En_Ge2", "ovl_En_Ma_Yts", "ovl_En_Ma_Yto", "ovl_Obj_Tokei_Turret", "ovl_Bg_Dblue_Elevator", "ovl_Obj_Warpstone", "ovl_En_Zog", "ovl_Obj_Rotlift", "ovl_Obj_Jg_Gakki", "ovl_Bg_Inibs_Movebg", "ovl_En_Zot", "ovl_Obj_Tree", "ovl_Obj_Y2lift", "ovl_Obj_Y2shutter", "ovl_Obj_Boat", "ovl_Obj_Taru", "ovl_Obj_Hunsui", "ovl_En_Jc_Mato", "ovl_Mir_Ray3", "ovl_En_Zob", "ovl_Elf_Msg6", "ovl_Obj_Nozoki", "ovl_En_Toto", "ovl_En_Railgibud", "ovl_En_Baba", "ovl_En_Suttari", "ovl_En_Zod", "ovl_En_Kujiya", "ovl_En_Geg", "ovl_Obj_Kinoko", "ovl_Obj_Yasi", "ovl_En_Tanron1", "ovl_En_Tanron2", "ovl_En_Tanron3", "ovl_Obj_Chan", "ovl_En_Zos", "ovl_En_S_Goro", "ovl_En_Nb", "ovl_En_Ja", "ovl_Bg_F40_Block", "ovl_Bg_F40_Switch", "ovl_En_Po_Composer", "ovl_En_Guruguru", "ovl_Oceff_Wipe5", "ovl_En_Stone_heishi", "ovl_Oceff_Wipe6", "ovl_En_Scopenuts", "ovl_En_Scopecrow", "ovl_Oceff_Wipe7", "ovl_Eff_Kamejima_Wave", "ovl_En_Hg", "ovl_En_Hgo", "ovl_En_Zov", "ovl_En_Ah", "ovl_Obj_Hgdoor", "ovl_Bg_Ikana_Bombwall", "ovl_Bg_Ikana_Ray", "ovl_Bg_Ikana_Shutter", "ovl_Bg_Haka_Bombwall", "ovl_Bg_Haka_Tomb", "ovl_En_Sc_Ruppe", "ovl_Bg_Iknv_Doukutu", "ovl_Bg_Iknv_Obj", "ovl_En_Pamera", "ovl_Obj_HsStump", "ovl_En_Hidden_Nuts", "ovl_En_Zow", "ovl_En_Talk", "ovl_En_Al", "ovl_En_Tab", "ovl_En_Nimotsu", "ovl_En_Hit_Tag", "ovl_En_Ruppecrow", "ovl_En_Tanron4", "ovl_En_Tanron5", "ovl_En_Tanron6", "ovl_En_Daiku2", "ovl_En_Muto", "ovl_En_Baisen", "ovl_En_Heishi", "ovl_En_Demo_heishi", "ovl_En_Dt", "ovl_En_Cha", "ovl_Obj_Dinner", "ovl_Eff_Lastday", "ovl_Bg_Ikana_Dharma", "ovl_En_Akindonuts", "ovl_Eff_Stk", "ovl_En_Ig", "ovl_En_Rg", "ovl_En_Osk", "ovl_En_Sth2", "ovl_En_Yb", "ovl_En_Rz", "ovl_En_Scopecoin", "ovl_En_Bjt", "ovl_En_Bomjima", "ovl_En_Bomjimb", "ovl_En_Bombers", "ovl_En_Bombers2", "ovl_En_Bombal", "ovl_Obj_Moon_Stone", "ovl_Obj_Mu_Pict", "ovl_Bg_Ikninside", "ovl_Eff_Zoraband", "ovl_Obj_Kepn_Koya", "ovl_Obj_Usiyane", "ovl_En_Nnh", "ovl_Obj_Kzsaku", "ovl_Obj_Milk_Bin", "ovl_En_Kitan", "ovl_Bg_Astr_Bombwall", "ovl_Bg_Iknin_Susceil", "ovl_En_Bsb", "ovl_En_Recepgirl", "ovl_En_Thiefbird", "ovl_En_Jgame_Tsn", "ovl_Obj_Jgame_Light", "ovl_Obj_Yado", "ovl_Demo_Syoten", "ovl_Demo_Moonend", "ovl_Bg_Lbfshot", "ovl_Bg_Last_Bwall", "ovl_En_And", "ovl_En_Invadepoh_Demo", "ovl_Obj_Danpeilift", "ovl_En_Fall2", "ovl_Dm_Al", "ovl_Dm_An", "ovl_Dm_Ah", "ovl_Dm_Nb", "ovl_En_Drs", "ovl_En_Ending_Hero", "ovl_Dm_Bal", "ovl_En_Paper", "ovl_En_Hint_Skb", "ovl_Dm_Tag", "ovl_En_Bh", "ovl_En_Ending_Hero2", "ovl_En_Ending_Hero3", "ovl_En_Ending_Hero4", "ovl_En_Ending_Hero5", "ovl_En_Ending_Hero6", "ovl_Dm_Gm", "ovl_Obj_Swprize", "ovl_En_Invisible_Ruppe", "ovl_Obj_Ending", "ovl_En_Rsn", ] script_dir = os.path.dirname(os.path.realpath(__file__)) repo = script_dir + os.sep + ".." + os.sep + ".." + os.sep def as_word(b, off=0): return struct.unpack(">I", b[off:off+4])[0] def as_word_list(b): return [i[0] for i in struct.iter_unpack(">I", b)] def null_or_ptr(w): return (w == 0) or (w >= 0x80000000 and w < 0x81000000) # (name, vrom_st, vrom_end, vram_st, vram_end) def read_actor_ovl_tbl(): actortbl = [] with open(repo + "baserom/code","rb") as codefile: codefile.seek(0x109510) # actor overlay table offset into code entry = as_word_list(codefile.read(0x20)) i = 0 while (entry[4] == 0x00000000 and all([null_or_ptr(e) for e in entry[2:4]]) and ((entry[7] & 0xFFFF) == 0) and (null_or_ptr(entry[5]))): actortbl.append((actor_names[i], entry[0], entry[1], entry[2], entry[3])) entry = as_word_list(codefile.read(0x20)) i += 1 actortbl[0] = ['ovl_Player_Actor', 0xCA7F00, 0xCDCF60, 0x8082DA90, 0x80862B70 ] return actortbl actor_tbl = read_actor_ovl_tbl() def resolve_symbol(address): """ Returns (overlay file path, file offset) from a given VRAM address """ for entry in actor_tbl: if address >= 0x80000000: if entry[3] <= address < entry[4]: return repo + "baserom" + os.sep + entry[0], address - entry[3] else: if entry[1] <= address < entry[2]: return repo + "baserom" + os.sep + entry[0], address - entry[1] else: raise RuntimeError('Symbol not found in actor overlay table file ranges. Are you sure the file is an actor overlay?') def HexParse(s): return int(s, 16) if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('address', help="VRAM or VROM address to get overlay file and offset for", type=HexParse) args = parser.parse_args() file_path,offset = resolve_symbol(args.address) print(f"0x{args.address:08X} is 0x{offset:X} into {file_path}")