metadata = {} for i in range(len(vanillaMusicData)): addr = musicDataTable+i*3 ptr = snes_to_pc(rom.readLong(addr)) if i < len(vanillaMusicData)-1: # vanilla data ptrs are conveniently sorted endptr = snes_to_pc(rom.readLong(addr+3)) else: endptr = musicDataEnd rom.seek(addr) nspc_path = "%s/vanilla_%06x_%06x.nspc" % (nspc_dir, ptr, endptr-1) print("Writing %s ..." % nspc_path) rom.seek(ptr) with open(nspc_path, "wb") as nspc: nspc.write(rom.read(endptr-ptr)) musicdata = vanillaMusicData[i] for j in range(len(musicdata)): track, spc_path, group = musicdata[j] h,t=os.path.split(nspc_path) metadata[track] = { 'nspc_path':os.path.join(os.path.split(h)[1], t), 'data_index':i, 'track_index':j, 'original_author':'Kenji Yamamoto', 'port_author': '', 'description': "Original track from vanilla Super Metroid", "group": group } if spc_path is not None: metadata[track]['spc_path'] = spc_path
def readRooms(romFileName): romFile = RealROM(romFileName) for roomInfo in rooms: romFile.seek(roomInfo['Address']) data = romFile.read(RoomHeader.Size) roomInfo['RoomIndex'] = data[RoomHeader.RoomIndex] roomInfo['Area'] = data[RoomHeader.Area] roomInfo['MapX'] = data[RoomHeader.MapX] roomInfo['MapY'] = data[RoomHeader.MapY] roomInfo['Width'] = data[RoomHeader.Width] roomInfo['Height'] = data[RoomHeader.Height] roomInfo['UpScroller'] = data[RoomHeader.UpScroller] roomInfo['DownScroller'] = data[RoomHeader.DownScroller] roomInfo['SpecialGfxBitflag'] = data[RoomHeader.SpecialGfxBitflag] roomInfo['DoorsPtr'] = snes_to_pc( concatBytes(data[RoomHeader.DoorsPtr1], data[RoomHeader.DoorsPtr2], 0x8F)) #print("") #print("{} ({}) ({} x {}) in area: {}".format(roomInfo['Name'], hex(roomInfo['Address']), hex(roomInfo['Width']), hex(roomInfo['Height']), Areas.id2name[roomInfo['Area']])) readDoorsPtrs(romFile, roomInfo) readDoorsData(romFile, roomInfo) roomsGraph = {} for roomInfo in rooms: nodeName = removeChars(roomInfo['Name'], "][ '-") address = roomInfo['Address'] & 0xFFFF roomsGraph[address] = { 'Name': nodeName, 'Area': roomInfo['Area'], 'Width': roomInfo['Width'], 'Height': roomInfo['Height'], 'Doors': {} } for doorData in roomInfo["DoorData"]: roomsGraph[address]['Doors'][doorData['doorPtr']] = { 'roomPtr': doorData['roomPtr'], 'exitScreenX': doorData['screenX'], 'exitScreenY': doorData['screenY'], 'exitDirection': doorData['direction'] } # get screen data from corresponding door for (entryRoomAddress, entryRoom) in roomsGraph.items(): for entryDoorData in entryRoom["Doors"].values(): exitRoomAddress = entryDoorData['roomPtr'] exitRoom = roomsGraph[exitRoomAddress] found = False for exitDoorData in exitRoom['Doors'].values(): #if entryRoom['Name'] in ['GrappleTutorialRoom1', 'GrappleBeamRoom']: #print("entry doors count: {} exit doors count: {}".format(len(entryRoom["Doors"]), len(exitRoom['Doors']))) #print("{}/{} -> {}/{} ({})".format(entryRoom['Name'], hex(entryRoomAddress), exitRoom['Name'], hex(exitDoorData['roomPtr']), roomsGraph[exitDoorData['roomPtr']]['Name'])) if exitDoorData['roomPtr'] == entryRoomAddress: #if entryRoom['Name'] in ['GrappleTutorialRoom1', 'GrappleBeamRoom']: #print("exitDoorData['roomPtr'] {} == entryRoomAddress {}".format(hex(exitDoorData['roomPtr']), hex(entryRoomAddress))) for entryDoorData in entryRoom['Doors'].values(): if entryDoorData['roomPtr'] == exitRoomAddress: entryDoorData['entryScreenX'] = exitDoorData[ 'exitScreenX'] entryDoorData['entryScreenY'] = exitDoorData[ 'exitScreenY'] entryDoorData['entryDirection'] = exitDoorData[ 'exitDirection'] found = True #else: #if entryRoom['Name'] in ['GrappleTutorialRoom1', 'GrappleBeamRoom']: #print("exitDoorData['roomPtr'] {} != entryRoomAddress {}".format(hex(exitDoorData['roomPtr']), hex(entryRoomAddress))) #if found == False: #print("door not found ({} -> {})".format(entryRoom['Name'], exitRoom['Name'])) #print("-----------------------------------------------------------------------------") #print(roomsGraph) print("""digraph { size="30,30!"; graph [overlap=orthoxy, splines=false, nodesep="1"]; node [shape="plaintext",fontsize=30]; edge [color="#0025fa80"]; """) for (address, roomInfo) in roomsGraph.items(): if roomInfo['Area'] == Areas.Tourian: src = roomInfo['Name'] print("{} [label = {}];".format( roomInfo['Name'], genLabel(roomInfo['Name'], roomInfo["Width"], roomInfo["Height"]))) for doorData in roomInfo["Doors"].values(): dstInfo = roomsGraph[doorData['roomPtr']] dst = dstInfo['Name'] print("{}:x{}{}:{} -> {}:x{}{}:{};".format( src, doorData.get('entryScreenX'), doorData.get('entryScreenY'), getDir(doorData.get('entryDirection')), dst, doorData.get('exitScreenX'), doorData.get('exitScreenY'), getDir(doorData.get('exitDirection')))) print("}")
minAddr, maxAddr = (0xffffffff, 0x0) # compare nspc data and dump if different than expected for dataId, expected_nspc in expected_table.items(): with open(expected_nspc, 'rb') as f: expected_music_data = f.read() sz = len(expected_music_data) snesAddr = rom.readLong(tableAddr + dataId) if snesAddr + sz > maxAddr: maxAddr = snesAddr + sz if snesAddr < minAddr: minAddr = snesAddr print("Data $%02x, $%06x - $%06x" % (dataId, snesAddr, snesAddr + sz - 1)) addr = snes_to_pc(snesAddr) rom.seek(addr) music_data = rom.read(sz) if music_data != expected_music_data: print("Music data $%02x differ from the one of %s !" % (dataId, expected_nspc)) out_nspc = "track_%02x.nspc" % dataId print("Dumping it in %s ..." % out_nspc) with open(out_nspc, 'wb') as f: f.write(music_data) else: # check if some block headers are cross-bank def isCrossBank(off): endBankOffset = (snesAddr + off + 4) & 0x7fff return endBankOffset == 1 or endBankOffset == 3 offending = [ off for off in nspcInfo[expected_nspc]['block_headers_offsets']