예제 #1
0
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
예제 #2
0
 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)
예제 #4
0
 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
예제 #6
0
    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)
예제 #7
0
    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
예제 #8
0
 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)
예제 #9
0
    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
예제 #10
0
 def __init__(self, values, storage=Word):
     self.values = [snes_to_pc(value) for value in values]
     self.storage = storage
예제 #11
0
 def __init__(self, value, storage=Word):
     self.value = snes_to_pc(value)
     self.storage = storage
예제 #12
0
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)]
예제 #13
0
#!/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")
예제 #16
0
    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 = [
예제 #17
0
                          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)
예제 #18
0
 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)
예제 #23
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)
예제 #26
0
 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)
예제 #27
0
#!/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)),