def getAddressesToRead(plando=False): addresses = { "locations": [], "patches": [], "transitions": [], "misc": [], "ranges": [] } # locations for loc in locations: addresses["locations"].append(loc.Address) # patches for (patch, values) in RomReader.patches.items(): addresses["patches"].append(values["address"]) # transitions for ap in accessPoints: if ap.Internal == True: continue addresses["transitions"].append(0x10000 | ap.ExitInfo['DoorPtr']) # misc # majors split addresses["misc"] += Addresses.getWeb('majorsSplit') # escape timer addresses["misc"] += Addresses.getWeb('escapeTimer') # start ap addresses["misc"] += Addresses.getWeb('startAP') # random doors addresses["misc"] += DoorsManager.getAddressesToRead() # objectives addresses["misc"] += Objectives.getAddressesToRead() # ranges [low, high] ## old doorasm for old seeds addresses["ranges"] += [snes_to_pc(0x8feb00), snes_to_pc(0x8fee60)] maxDoorAsmPatchLen = 22 customDoorsAsm = Addresses.getOne('customDoorsAsm') addresses["ranges"] += [ customDoorsAsm, customDoorsAsm + (maxDoorAsmPatchLen * len([ap for ap in accessPoints if ap.Internal == False])) ] # split locs addresses["ranges"] += Addresses.getRange('locIdsByArea') addresses["ranges"] += Addresses.getRange('scavengerOrder') if plando == True: # plando addresses addresses["ranges"] += Addresses.getRange('plandoAddresses') # plando transitions (4 bytes per transitions, ap#/2 transitions) plandoTransitions = Addresses.getOne('plandoTransitions') addresses["ranges"] += [ plandoTransitions, plandoTransitions + ((len(addresses["transitions"]) / 2) * 4) ] return addresses
def __init__(self, start, length=-1, end=-1): self.start = snes_to_pc(start) if length != -1: self.end = self.start + length self.length = length else: self.end = snes_to_pc(end) self.length = self.end - self.start
def addExtraAddress(track, snesAddress=None, pcAddress=None): assert (snesAddress is None) != (pcAddress is None) if "pc_addresses" not in metadata[track]: metadata[track]["pc_addresses"] = [] if pcAddress is None: pcAddress = snes_to_pc(snesAddress) metadata[track]["pc_addresses"].append(pcAddress)
def __init__(self, romFile, magic=None): self.romFile = romFile self.race = None # default to morph ball location self.nothingId = 0x1a self.nothingAddr = snes_to_pc(0x8f86de) if magic is not None: from rom.race_mode import RaceModeReader self.race = RaceModeReader(self, magic)
def readDoorsPtrs(romFile, roomInfo): size = roomInfo['DoorCount'] * 2 doorsPtr = roomInfo['DoorsPtr'] romFile.seek(doorsPtr) data = romFile.read(size) doorPtrs = [] for n in range(0, roomInfo['DoorCount']): doorPtrs.append( snes_to_pc(concatBytes(data[2 * n], data[2 * n + 1], 0x83))) roomInfo['DoorPtrs'] = doorPtrs
def loadEnemies(self): # loop on room state then on enemy set self.enemyIds = set() enemySetPtrs = set() for roomStateHeader in self.roomStateHeaders: # on standard states, we only want the ship anyway if roomStateHeader.headerType == StateType.Standard: enemySetPtrs.add( snes_to_pc(self.roomStates[ roomStateHeader.roomStatePtr].enemySetPtr)) print("enemySetPtrs: {}".format([hex(p) for p in enemySetPtrs])) for enemySetPtr in enemySetPtrs: self.rom.seek(enemySetPtr) enemyId = 0 for i in range(32): enemyId = self.rom.readWord() if enemyId == 0xFFFF: break Xpos = self.rom.readWord() Ypos = self.rom.readWord() initParam = self.rom.readWord() properties = self.rom.readWord() extraProperties = self.rom.readWord() param1 = self.rom.readWord() param2 = self.rom.readWord() self.enemyIds.add((enemyId, Xpos, Ypos)) print("enemy ids: {}".format([(hex(i), hex(j), hex(k)) for i, j, k in self.enemyIds])) self.enemies = [] for enemyId, Xpos, Ypos in self.enemyIds: dataAddr = snes_to_pc(0xA00000 + enemyId) enemy = Enemy(self.rom, dataAddr, enemyId, Xpos, Ypos) self.enemies.append(enemy)
def loadScavengerOrder(self, locations): order = [] locIdsDict = self.genLocIdsDict(locations) self.romFile.seek(snes_to_pc(0xA1F5D8)) while True: data = self.romFile.readWord() locId = (data & 0xFF00) >> 8 if locId == 0xFF: break loc = locIdsDict[locId] order.append(loc) # check that there's no nothing in the loc assert loc.itemName != "Nothing", "Nothing detected in scav loc {}".format(loc.Name) return order
def writeSplitLocs(self, split, itemLocs, progItemLocs): majChozoCheck = lambda itemLoc: itemLoc.Item.Class == split and itemLoc.Location.isClass( split) fullCheck = lambda itemLoc: itemLoc.Location.Id is not None splitChecks = { 'Full': fullCheck, 'Scavenger': fullCheck, 'Major': majChozoCheck, 'Chozo': majChozoCheck, 'FullWithHUD': lambda itemLoc: itemLoc.Item.Category not in ['Energy', 'Ammo', 'Boss'] } itemLocCheck = lambda itemLoc: itemLoc.Item.Category != "Nothing" and splitChecks[ split](itemLoc) for area, addr in locIdsByAreaAddresses.items(): locs = [ il.Location for il in itemLocs if itemLocCheck(il) and il.Location.GraphArea == area ] self.log.debug("writeSplitLocs. area=" + area) self.log.debug(str([loc.Name for loc in locs])) self.romFile.seek(addr) for loc in locs: self.romFile.writeByte(loc.Id) self.romFile.writeByte(0xff) if split == "Scavenger": # write required major item order self.romFile.seek(snes_to_pc(0xA1F5D8)) for itemLoc in progItemLocs: self.romFile.writeWord((itemLoc.Location.Id << 8) | itemLoc.Location.HUD) # bogus loc ID | "HUNT OVER" index self.romFile.writeWord(0xff10)
def load(self): self.headerSize = 11 self.rom.seek(self.dataAddr) curAddr = self.dataAddr self.roomIndex = self.rom.readByte() self.area = self.rom.readByte() self.mapX = self.rom.readByte() self.MapY = self.rom.readByte() self.width = self.rom.readByte() self.height = self.rom.readByte() self.upScroller = self.rom.readByte() self.downScroller = self.rom.readByte() self.specialGfxBitflag = self.rom.readByte() # LoROM address self.doorsPtr = self.rom.readWord() self.roomStateHeaders = [] curAddr += self.headerSize roomStateHeader = RoomStateHeader(self.rom, curAddr) curAddr += roomStateHeader.size() self.roomStateHeaders.append(roomStateHeader) while roomStateHeader.headerType != StateType.Standard: roomStateHeader = RoomStateHeader(self.rom, curAddr) curAddr += roomStateHeader.size() self.roomStateHeaders.append(roomStateHeader) self.roomStates = {} for roomStateHeader in self.roomStateHeaders: roomState = RoomState(self.rom, snes_to_pc(roomStateHeader.roomStatePtr)) self.roomStates[roomStateHeader.roomStatePtr] = roomState # choose one of the standard state as the state we're going to use if roomStateHeader.headerType == StateType.Standard: self.defaultRoomState = roomState
def __init__(self, values, storage=Word): self.values = [snes_to_pc(value) for value in values] self.storage = storage
def __init__(self, value, storage=Word): self.value = snes_to_pc(value) self.storage = storage
from rom.leveldata import LevelData, Ship, Room vanilla = sys.argv[1] hack = sys.argv[2] fixEscape = len(sys.argv) > 2 print("fix escape: {}".format(fixEscape)) # copy vanilla in tmpfile tmpfile = '/tmp/vanilla.sfc' copyfile(vanilla, tmpfile) # extract data from hack addresses = { "tilesAddr": { "vanilla": [snes_to_pc(0xADB600), snes_to_pc(0xADC600)], "hack": [snes_to_pc(0xADB600), snes_to_pc(0xADC600)] }, "palettesAddr": { "vanilla": [snes_to_pc(0xA2A59E), snes_to_pc(0xA2A5BE)], "hack": [snes_to_pc(0xA2A59E), snes_to_pc(0xA2A5BE)] }, "glowSpritemapsInstructionList": { "vanilla": [snes_to_pc(0x8dca4e), snes_to_pc(0x8DCAAA)], "hack": [snes_to_pc(0x8dca4e), snes_to_pc(0x8DCAAA)]
#!/usr/bin/python3 import sys, os # we're in directory 'tools/' we have to update sys.path sys.path.append(os.path.dirname(sys.path[0])) from rom.rom import snes_to_pc for addr10 in sys.argv[1:]: addr16 = int(addr10, 16) print("{} -> {}".format(hex(addr16), hex(snes_to_pc(addr16))))
else: return (firstData, None) def getMd5Sum(data): return hashlib.md5(bytes(data)).hexdigest() # read table tracksTable = {} for trackName, data in vanillaTracks.items(): if 'pc_addresses' not in data: continue addr = data['pc_addresses'][0] dataId = rom.readByte(addr) addr = snes_to_pc(rom.readLong(tableAddr + dataId)) #print("dataId: {} - addr: {} for song: {}".format(hex(dataId), hex(addr), trackName)) tracksTable[addr] = {"trackName": trackName, "dataId": dataId} # get nspc data in rom and compute its md5 sum for addr in sorted(tracksTable.keys()): trackData = tracksTable[addr] #print("{} {:4} {}".format(hex(pc_to_snes(addr)), hex(trackData["dataId"]), trackData["trackName"])) nspcData = readNspcData(rom, addr) if nspcData[0] is None and nspcData[1] is None: print(" Warning: no nspc end found for {}".format( trackData["trackName"])) tracksTable[addr]["nspcData"] = [None] tracksTable[addr]["nspc_md5sum"] = [None] continue
lineLength = 64 firstChar = 2 * 2 baseAddr = 0xB6F200 + lineLength * 8 + firstChar texts = ["1. {} kraid", "2. {} phantoon", "3. {} draygon", "4. {} ridley"] kill_synonyms = [ "massacre", "slaughter", "slay", "wipe out", "annihilate", "eradicate", "erase", "exterminate", "finish", "neutralize", "obliterate", "destroy", "wreck", "smash", "crush", "end", "eliminate", "terminate" ] romFile = RealROM(sys.argv[1]) alreadyUsed = [] for i, text in enumerate(texts): verb = random.choice(kill_synonyms) while verb in alreadyUsed: verb = random.choice(kill_synonyms) alreadyUsed.append(verb) text = text.format(verb) print(text) addr = baseAddr + i * lineLength * 4 romFile.seek(snes_to_pc(addr)) for c in text: romFile.writeWord(0x3800 + char2tile[c]) romFile.close() print("text written")
shipColors = [(0, 0, 0)] + list(shipColors) paletteFinal = [] paletteFinalRGB = [] for color in shipColors: paletteFinalRGB += color paletteFinal.append(RGB_24_to_15(color)) print("final palette, {} colors: {}".format(len(paletteFinal), [hex(c) for c in paletteFinal])) print("final palette RGB: {}".format(paletteFinalRGB)) # if all 16 colors are used disable the glowing color if len(shipColors) == maxColors and not enableShipGlowCustom: glowListAddr = snes_to_pc(0x8DCA52) vanillaRom.seek(glowListAddr) vanillaRom.writeWord(0x0005) # set color vanillaRom.writeWord(paletteFinal[-1]) # glow color vanillaRom.writeWord(0xC595) # done vanillaRom.writeWord(0xC61E) # goto CA52 vanillaRom.writeWord(0xCA52) if enableShipGlowCustom: # we need to have the glowing color as last color in the palette finalGlowColor = RGB_24_to_15(shipGlowCustomColor) # if not all 16 colors are filled, add dummy colors if len(shipColors) < 16: colorsToAdd = 16 - len(shipColors) #dummyColorRGB = genDummyColor(shipColors) dummyColorRGB = [
address + nextLine) address += 2 # fill remain with space for i in range(vanillaTextLenght - len(text)): romFile.writeWord(tileStart + char2tileUpperUp[' '], address) romFile.writeWord(tileStart + char2tileUpperDown[' '], address + nextLine) address += 2 # update 'no data' message #; NO DATA #$81:B4AC 000F, 2077, 2078, 200F, 206D, 206A, 207D, 206A, 200F, 200F, 200F, FFFF # first word is 000F, not an actual char startAddress = snes_to_pc(0x81B4AC + 2) updateLowerText(romFile, startAddress, 'no dude') # update 'samus a' message # ; SAMUS A # $81:B436 202B, 200A, 2026, 202D, 202B, 200F, 200A, FFFE, # 203B, 201A, 2036, 2010, 203B, 200F, 201A, FFFF startAddress = snes_to_pc(0x81B436) updateUpperText(romFile, startAddress, 'dude a', len('samus a')) # update 'samus data' message # ; SAMUS DATA # $81:B40A dw 202B, 200A, 2026, 202D, 202B, 200F, 200D, 200A, 202C, 200A, FFFE, # 203B, 201A, 2036, 2010, 203B, 200F, 201D, 201A, 2011, 201A, FFFF startAddress = snes_to_pc(0x81B40A)
def ship_to_pc(self, addr): return snes_to_pc(self.bank + addr)
def extractRGB(color): R = ((color) % 32) G = ((color // 32) % 32) B = ((color // 1024) % 32) return (R, G, B) def readPalette(rom, addr): rom.seek(addr) palette = [] for i in range(16): palette.append(extractRGB(rom.readWord())) return palette paletteAddr = snes_to_pc(0x8DD6BA) + 6 palettes = [] for i in range(16): addr = paletteAddr + 0x24 * i palettes.append(readPalette(rom, addr)) # the one with the final colors is the last one basePalette = palettes[-1] #for palette in palettes: # print(palette) # compute % inc/dec relative to base palette evolution = [] for palette in palettes[:-1]: paletteEvol = []
# - path to nspc directory. *has* to be one level deeper than music base dir # - path to JSON metadata file to write. # will also parse room state headers, and list pointers where # music data/track has to be written, ie track number >= 5 # also lists the extra pointers for area rando, all of this # stored in the JSON metadata from rom.rom import RealROM, snes_to_pc from rom.ips import IPS_Patch vanilla=sys.argv[1] nspc_dir=sys.argv[2] json_path=sys.argv[3] rom=RealROM(vanilla) musicDataTable = snes_to_pc(0x8FE7E4) musicDataEnd = snes_to_pc(0xDED1C0) # tracks pointed music table, in that order # array is songs in music data: (name, spc_path) vanillaMusicData = [ # Song 0: intro, # Song 1: menu theme [("Title sequence intro", "vanilla/title_menu.spc", "Vanilla Soundtrack"), ("Menu theme", None, "Vanilla Soundtrack")], # Song 0: thunder - zebes asleep, # Song 1: thunder - zebes awake, # Song 2: no thunder (morph room...) [("Crateria Landing - Thunder, Zebes asleep", "vanilla/crateria_arrival.spc", "Vanilla Soundtrack"), ("Crateria Landing - Thunder, Zebes awake", "vanilla/crateria_rainstorm.spc", "Vanilla Soundtrack"), ("Crateria Landing - No Thunder", "vanilla/crateria_underground.spc", "Vanilla Soundtrack")], # Song 0: Main theme,
updateTable(dataId, vTrack, vTrack) 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
#!/usr/bin/python3 import sys, os, argparse from shutil import copyfile # we're in directory 'tools/' we have to update sys.path sys.path.append(os.path.dirname(sys.path[0])) from rom.rom import RealROM, snes_to_pc, pc_to_snes vanillaRom = RealROM(sys.argv[1]) # if last two tiles are used we also have to copy them to escape tiles escapeTilesAddr = snes_to_pc(0x94C800) vanillaRom.seek(escapeTilesAddr) # a 16 8x8 4bpp tiles row size rowSize = 32 * 16 for _ in range(32 * 4): vanillaRom.writeByte(0) lastRow8Addr = escapeTilesAddr + rowSize vanillaRom.seek(lastRow8Addr) for _ in range(32 * 4): vanillaRom.writeByte(0)
('Maridia Map Room', 'Crab Hole Bottom Right') ] vanillaEscapeAnimalsTransitions = [ ('Flyway Right 0', 'Bomb Torizo Room Left'), ('Flyway Right 1', 'Bomb Torizo Room Left'), ('Flyway Right 2', 'Bomb Torizo Room Left'), ('Flyway Right 3', 'Bomb Torizo Room Left'), ('Bomb Torizo Room Left Animals', 'Flyway Right') ] escapeSource = 'Tourian Escape Room 4 Top Right' escapeTargets = ['Green Brinstar Main Shaft Top Left', 'Basement Left', 'Business Center Mid Left', 'Crab Hole Bottom Right'] locIdsByAreaAddresses = { "Ceres": snes_to_pc(0xA1F568), "Crateria": snes_to_pc(0xA1F569), "GreenPinkBrinstar": snes_to_pc(0xA1F57B), "RedBrinstar": snes_to_pc(0xA1F58C), "WreckedShip": snes_to_pc(0xA1F592), "Kraid": snes_to_pc(0xA1F59E), "Norfair": snes_to_pc(0xA1F5A2), "Crocomire": snes_to_pc(0xA1F5B2), "LowerNorfair": snes_to_pc(0xA1F5B8), "WestMaridia": snes_to_pc(0xA1F5C3), "EastMaridia": snes_to_pc(0xA1F5CB), "Tourian": snes_to_pc(0xA1F5D7) } def getAccessPoint(apName, apList=None): if apList is None:
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("}")
#!/usr/bin/python3 import sys, os # we're in directory 'tools/' we have to update sys.path sys.path.append(os.path.dirname(sys.path[0])) # extract ship tiles & layout & palette from hack, generate an ips in the end. from rom.rom import RealROM, snes_to_pc from rom.compression import Compressor vanilla = sys.argv[1] tileAddr = snes_to_pc(0x95A82F) tilemapAddr = snes_to_pc(0x96FE69) vanillaRom = RealROM(vanilla) _, tileData = Compressor().decompress(vanillaRom, tileAddr) _, tilemapData = Compressor().decompress(vanillaRom, tilemapAddr) tileBytes = [b.to_bytes(1, byteorder='little') for b in tileData] with open('ship7.gfx', 'wb') as ship: for byte in tileBytes: ship.write(byte) tilemapBytes = [b.to_bytes(1, byteorder='little') for b in tilemapData] with open('ship7.tilemap', 'wb') as tilemap: for byte in tilemapBytes: tilemap.write(byte)
def writeSplitLocs(self, itemLocs, split): listAddresses = { "Ceres": snes_to_pc(0xA1F568), "Crateria": snes_to_pc(0xA1F569), "GreenPinkBrinstar": snes_to_pc(0xA1F57B), "RedBrinstar": snes_to_pc(0xA1F58C), "WreckedShip": snes_to_pc(0xA1F592), "Kraid": snes_to_pc(0xA1F59E), "Norfair": snes_to_pc(0xA1F5A2), "Crocomire": snes_to_pc(0xA1F5B2), "LowerNorfair": snes_to_pc(0xA1F5B8), "WestMaridia": snes_to_pc(0xA1F5C3), "EastMaridia": snes_to_pc(0xA1F5CB), "Tourian": snes_to_pc(0xA1F5D7) } majChozoCheck = lambda itemLoc: (itemLoc.Item.Class == split and split in itemLoc.Location.Class) splitChecks = { 'Full': lambda itemLoc: itemLoc.Location.Id is not None, 'Major': majChozoCheck, 'Chozo': majChozoCheck, 'FullWithHUD': lambda itemLoc: itemLoc.Item.Category not in ['Energy', 'Ammo', 'Boss'] } itemLocCheck = lambda itemLoc: itemLoc.Item.Category != "Nothing" and splitChecks[split](itemLoc) for area,addr in listAddresses.items(): ids = [il.Location.Id for il in itemLocs if itemLocCheck(il) and il.Location.GraphArea == area] self.romFile.seek(addr) for idByte in ids: self.romFile.writeByte(idByte) self.romFile.writeByte(0xff)
#!/usr/bin/python3 import sys, os # now that we're in directory 'tools/' we have to update sys.path sys.path.append(os.path.dirname(sys.path[0])) from rom.ips import IPS_Patch from rom.rom import snes_to_pc, pc_to_snes ips=sys.argv[1] low=snes_to_pc(int(sys.argv[2], 16)) high=snes_to_pc(int(sys.argv[3], 16)) ext = os.path.splitext(ips)[-1].lower() if ext != ".ips": sys.stderr.write("Wrong ips extension") sys.exit(1) # load ips patch = IPS_Patch.load(ips) patch_dict = patch.toDict() # remove overlapping data filtered_dict = {} for keyLow, data in patch_dict.items(): dataLength = len(data) keyHigh = keyLow + dataLength if keyHigh < low or keyLow > high: print("[{}, {}] we have {} bytes of data".format(hex(pc_to_snes(keyLow)),