Пример #1
0
class SpriteGroupModule(EbModule.EbModule):
    _name = "Sprite Groups"
    def __init__(self):
        self._grPtrTbl = EbTable(0xef133f)
        self._grPalTbl = EbTable(0xc30000)
        self._groups = None
    def freeRanges(self):
        return [(0x2f1a7f, 0x2f4a3f),
                (0x110000, 0x11ffff),
                (0x120000, 0x12ffff),
                (0x130000, 0x13ffff),
                (0x140000, 0x14ffff),
                (0x150000, 0x154fff)]
    def free(self):
        del(self._grPtrTbl)
        del(self._grPalTbl)
    def readFromRom(self, rom):
        self._grPtrTbl.readFromRom(rom)
        updateProgress(5)
        self._grPalTbl.readFromRom(rom)
        updateProgress(5)

        # Load the sprite groups
        self._groups = []
        pct = 40.0/self._grPtrTbl.height()
        for i in range(self._grPtrTbl.height()):
            # Note: this assumes that the SPT is written contiguously
            numSprites = 8
            # Assume that the last group only has 8 sprites
            if i < self._grPtrTbl.height()-1:
                numSprites = (self._grPtrTbl[i+1,0].val() -
                        self._grPtrTbl[i,0].val() - 9) / 2

            g = SpriteGroup(numSprites)
            g.readFromRom(rom, EbModule.toRegAddr(self._grPtrTbl[i,0].val()))
            self._groups.append(g)
            updateProgress(pct)
    def writeToProject(self, resourceOpener):
        # Write the palettes
        self._grPalTbl.writeToProject(resourceOpener)
        updateProgress(5)
        out = { }
        i = 0
        pct = 40.0/len(self._groups)
        for g in self._groups:
            out[i] = g.dump()
            img = g.toImage(self._grPalTbl[g.palette(),0].val())
            imgFile = resourceOpener("SpriteGroups/" + str(i).zfill(3), 'png')
            img.save(imgFile, 'png', transparency=0)
            imgFile.close()
            del(img)
            i += 1
            updateProgress(pct)
        yaml.dump(out, resourceOpener("sprite_groups", "yml"),
                Dumper=yaml.CSafeDumper)
        updateProgress(5)
    def readFromProject(self, resourceOpener):
        self._grPalTbl.readFromProject(resourceOpener)
        updateProgress(5)
        input = yaml.load(resourceOpener("sprite_groups", "yml"),
                Loader=yaml.CSafeLoader)
        numGroups = len(input)
        self._groups = []
        pct = 45.0/numGroups
        for i in range(numGroups):
            g = SpriteGroup(16)
            g.load(input[i])
            img = Image.open(
                    resourceOpener("SpriteGroups/" + str(i).zfill(3), "png"))
            g.fromImage(img)
            palData = img.getpalette()
            del(img)
            self._groups.append(g)
            pal = [ ]

            # Read the palette from the image
            for i in range(1, 16):
                pal.append((palData[i*3], palData[i*3+1], palData[i*3+2]))
            # Assign the palette number to the sprite
            for i in range(8):
                if pal == self._grPalTbl[i,0].val()[1:]:
                    g.setPalette(i)
                    break
            else:
                # Error, this image uses an invalid palette
                raise RuntimeException("Sprite Group #" + i
                        + "uses an invalid palette.")
            updateProgress(pct)
            
    def writeToRom(self, rom):
        numGroups = len(self._groups)
        self._grPtrTbl.clear(numGroups)
        with DataBlock(sum(map(
            lambda x: x.blockSize(), self._groups))) as block:
            loc = 0
            i = 0
            # Write all the groups to the block, and sprites to rom
            pct = 40.0 / numGroups
            for g in self._groups:
                g.writeSpritesToFree(rom)
                g.writeToBlock(block, loc)
                self._grPtrTbl[i,0].setVal(loc)
                loc += g.blockSize()
                i += 1
                updateProgress(pct)
            # Write the block to rom and correct the group pointers
            addr = EbModule.toSnesAddr(block.writeToFree(rom))
            for i in range(self._grPtrTbl.height()):
                self._grPtrTbl[i,0].setVal(
                        self._grPtrTbl[i,0].val() + addr)
        # Write the pointer table
        self._grPtrTbl.writeToRom(rom)
        updateProgress(5)
        # Write the palettes
        self._grPalTbl.writeToRom(rom)
        updateProgress(5)
Пример #2
0
class DoorModule(EbModule.EbModule):
    _name = "Doors"
    def __init__(self):
        self._ptrTbl = EbTable("DOOR_POINTER_TABLE")
        self._entries = [ ]
    def readFromRom(self, rom):
        self._ptrTbl.readFromRom(rom)
        updateProgress(5)
        pct = 45.0/(40*32)
        for i in range(self._ptrTbl.height()):
            loc = EbModule.toRegAddr(self._ptrTbl[i,0].val())
            entry = [ ]
            numDoors = rom.readMulti(loc, 2)
            loc += 2
            for j in range(numDoors):
                d = Door()
                try:
                    d.readFromRom(rom, loc)
                except ValueError:
                    # Invalid door entry. Some entries in EB are invalid.
                    # When we encounter one, just assume we've reached the end
                    # of this entry.
                    break
                entry.append(d)
                loc += 5
            self._entries.append(entry)
            i += 1
            updateProgress(pct)
    def writeToProject(self, resourceOpener):
        out = dict()
        x = y = 0
        rowOut = dict()
        pct = 45.0/(40*32)
        for entry in self._entries:
            if not entry:
                rowOut[x%32] = None
            else:
                rowOut[x%32] = map(lambda z: z.dump(), entry)
            if (x % 32) == 31:
                # Start new row
                out[y] = rowOut
                x = 0
                y += 1
                rowOut = dict()
            else:
                x += 1
            updateProgress(pct)
        with resourceOpener("map_doors", "yml") as f:
            s = yaml.dump(out, default_flow_style=False, Dumper=yaml.CSafeDumper)
            s = sub("Event Flag: (\d+)",
                    lambda i: "Event Flag: " + hex(int(i.group(0)[12:])), s)
            f.write(s)
        updateProgress(5)
    def readFromProject(self, resourceOpener):
        self._entries = []
        pct = 45.0/(40*32)
        with resourceOpener("map_doors", "yml") as f:
            updateProgress(5)
            input = yaml.load(f, Loader=yaml.CSafeLoader)
            for y in input:
                row = input[y]
                for x in row:
                    if row[x] == None:
                        self._entries.append(None)
                    else:
                        entry = []
                        for door in row[x]:
                            d = Door()
                            d.load(door)
                            entry.append(d)
                        self._entries.append(entry)
                    updateProgress(pct)
    def writeToRom(self, rom):
        self._ptrTbl.clear(32*40)
        destWriteLoc = 0xF0000
        destRangeEnd = 0xF58EE # TODO Is this correct? Can we go more?
        destLocs = dict()
        emptyEntryPtr = EbModule.toSnesAddr(rom.writeToFree([0, 0]))
        pct = 45.0/(40*32)
        i=0
        for entry in self._entries:
            if (entry == None) or (not entry):
                self._ptrTbl[i,0].setVal(emptyEntryPtr)
            else:
                entryLen = len(entry)
                writeLoc = rom.getFreeLoc(2 + entryLen*5)
                self._ptrTbl[i,0].setVal(EbModule.toSnesAddr(writeLoc))
                rom[writeLoc] = entryLen & 0xff
                rom[writeLoc+1] = entryLen >> 8
                writeLoc += 2
                for door in entry:
                    destWriteLoc += door.writeToRom(rom, writeLoc, destWriteLoc,
                            destRangeEnd, destLocs)
                    writeLoc += 5
            i += 1
            updateProgress(pct)
        self._ptrTbl.writeToRom(rom)
        # Mark any remaining space as free
        if destWriteLoc < destRangeEnd:
            rom.addFreeRanges([(destWriteLoc, destRangeEnd)])
        updateProgress(5)
Пример #3
0
class BattleBgModule(EbModule.EbModule):
    _name = "Battle Backgrounds"
    _ASMPTRS_GFX = [0x2d1ba, 0x2d4dc, 0x2d8c3, 0x4a3ba]
    _ASMPTRS_ARR = [0x2d2c1, 0x2d537, 0x2d91f, 0x4a416]
    _ASMPTRS_PAL = [0x2d3bb, 0x2d61b, 0x2d7e8, 0x2d9e8, 0x4a4d0]
    def __init__(self):
        self._bbgGfxPtrTbl = EbTable("BATTLEBG_GFX_POINTERS")
        self._bbgArrPtrTbl = EbTable("BATTLEBG_ARR_POINTERS")
        self._bbgPalPtrTbl = EbTable("BATTLEBG_PALETTE_POINTERS")
        self._bbgScrollTbl = EbTable("BG_SCROLLING_TABLE")
        self._bbgDistorTbl = EbTable("BG_DISTORTION_TABLE")
        self._bbgTbl = EbTable("BG_DATA_TABLE")
    def free(self):
        del(self._bbgGfxPtrTbl)
        del(self._bbgArrPtrTbl)
        del(self._bbgPalPtrTbl)
        del(self._bbgTbl)

        del(self._bbgGfxArrs)
        del(self._bbgPals)
    def readFromRom(self, rom):
        self._bbgTbl.readFromRom(rom)
        pct = 50.0/(6+self._bbgTbl.height())
        self._bbgGfxPtrTbl.readFromRom(rom,
                EbModule.toRegAddr(EbModule.readAsmPointer(rom,
                    self._ASMPTRS_GFX[0])))
        updateProgress(pct)
        self._bbgArrPtrTbl.readFromRom(rom,
                EbModule.toRegAddr(EbModule.readAsmPointer(rom, 
                    self._ASMPTRS_ARR[0])))
        updateProgress(pct)
        self._bbgPalPtrTbl.readFromRom(rom,
                EbModule.toRegAddr(EbModule.readAsmPointer(rom, 
                    self._ASMPTRS_PAL[0])))
        updateProgress(pct)

        self._bbgGfxArrs = [ None for i in range(self._bbgGfxPtrTbl.height()) ]
        self._bbgPals = [ None for i in range(self._bbgPalPtrTbl.height()) ]
        updateProgress(pct)
        self._bbgScrollTbl.readFromRom(rom)
        updateProgress(pct)
        self._bbgDistorTbl.readFromRom(rom)
        updateProgress(pct)
        for i in range(self._bbgTbl.height()):
            gfxNum = self._bbgTbl[i,0].val()
            colorDepth = self._bbgTbl[i,2].val()
            if (self._bbgGfxArrs[gfxNum] == None):
                # Max size used in rom: 421 (2bpp) 442 (4bpp)
                tg = EbTileGraphics(512, 8, colorDepth)
                with EbCompressedData() as tgb:
                    tgb.readFromRom(rom, EbModule.toRegAddr(
                        self._bbgGfxPtrTbl[gfxNum,0].val()))
                    tg.readFromBlock(tgb)
                a = EbArrangement(32, 32)
                with EbCompressedData() as ab:
                    ab.readFromRom(rom, EbModule.toRegAddr(
                        self._bbgArrPtrTbl[gfxNum,0].val()))
                    a.readFromBlock(ab)
                
                self._bbgGfxArrs[gfxNum] = (tg, a)
            palNum = self._bbgTbl[i,1].val()
            if (self._bbgPals[palNum] == None):
                with DataBlock(32) as pb:
                    pb.readFromRom(rom,
                            EbModule.toRegAddr(self._bbgPalPtrTbl[palNum,0].val()))
                    p = EbPalettes(1, 16)
                    p.readFromBlock(pb)
                    self._bbgPals[palNum] = p
            updateProgress(pct)
    def writeToProject(self, resourceOpener):
        pct = 50.0/(3+self._bbgTbl.height())
        self._bbgTbl.writeToProject(resourceOpener, hiddenColumns=[0,1])
        updateProgress(pct)
        self._bbgScrollTbl.writeToProject(resourceOpener)
        updateProgress(pct)
        self._bbgDistorTbl.writeToProject(resourceOpener)
        updateProgress(pct)
        # Export BGs by table entry
        for i in range(self._bbgTbl.height()):
            (tg, a) = self._bbgGfxArrs[self._bbgTbl[i,0].val()]
            pal = self._bbgTbl[i,1].val()
            img = a.toImage(tg, self._bbgPals[pal])
            imgFile = resourceOpener('BattleBGs/' + str(i).zfill(3), 'png')
            img.save(imgFile, 'png')
            imgFile.close()
            del(img)
            updateProgress(pct)
    def readFromProject(self, resourceOpener):
        self._bbgTbl.readFromProject(resourceOpener)
        pct = 50.0/(2+self._bbgTbl.height())
        self._bbgScrollTbl.readFromProject(resourceOpener)
        updateProgress(pct)
        self._bbgDistorTbl.readFromProject(resourceOpener)
        updateProgress(pct)
        self._bbgGfxArrs = []
        self._bbgPals = []
        for i in range(self._bbgTbl.height()):
            img = Image.open(
                    resourceOpener('BattleBGs/' + str(i).zfill(3), 'png'))

            np = EbPalettes(1, 16)
            colorDepth = self._bbgTbl[i,2].val()
            # Max size used in rom: 421 (2bpp) 442 (4bpp)
            ntg = EbTileGraphics(512, 8, colorDepth)
            na = EbArrangement(32, 32)
            na.readFromImage(img, np, ntg)
            j=0
            for (tg, a) in self._bbgGfxArrs:
                if (tg == ntg) and (a == na):
                    self._bbgTbl[i,0].setVal(j)
                    break
                j += 1
            else:
                self._bbgGfxArrs.append((ntg, na))
                self._bbgTbl[i,0].setVal(j)
            j=0
            for p in self._bbgPals:
                if (p == np):
                    self._bbgTbl[i,1].setVal(j)
                    break
                j += 1
            else:
                self._bbgPals.append((np))
                self._bbgTbl[i,1].setVal(j)
            updateProgress(pct)
    def freeRanges(self):
        return [(0xa0000,0xadca0), (0xb0000, 0xbd899)]
    def writeToRom(self, rom):
        self._bbgGfxPtrTbl.clear(len(self._bbgGfxArrs))
        self._bbgArrPtrTbl.clear(len(self._bbgGfxArrs))
        self._bbgPalPtrTbl.clear(len(self._bbgPals))

        # Write gfx+arrs
        i = 0
        pct = (50.0/3)/len(self._bbgGfxArrs)
        for (tg, a) in self._bbgGfxArrs:
            with EbCompressedData(tg.sizeBlock()) as tgb:
                tg.writeToBlock(tgb)
                self._bbgGfxPtrTbl[i,0].setVal(EbModule.toSnesAddr(
                    tgb.writeToFree(rom)))
            with EbCompressedData(a.sizeBlock()) as ab:
                a.writeToBlock(ab)
                self._bbgArrPtrTbl[i,0].setVal(EbModule.toSnesAddr(
                    ab.writeToFree(rom)))
            i += 1
            updateProgress(pct)
        EbModule.writeAsmPointers(rom, self._ASMPTRS_GFX,
                EbModule.toSnesAddr(self._bbgGfxPtrTbl.writeToFree(rom)))
        EbModule.writeAsmPointers(rom, self._ASMPTRS_ARR,
                EbModule.toSnesAddr(self._bbgArrPtrTbl.writeToFree(rom)))

        # Write pals
        i = 0
        pct = (50.0/3)/len(self._bbgPals)
        for p in self._bbgPals:
            with DataBlock(32) as pb:
                p.writeToBlock(pb)
                self._bbgPalPtrTbl[i,0].setVal(EbModule.toSnesAddr(
                    pb.writeToFree(rom)))
            i += 1
            updateProgress(pct)
        EbModule.writeAsmPointers(rom, self._ASMPTRS_PAL,
                EbModule.toSnesAddr(self._bbgPalPtrTbl.writeToFree(rom)))

        # Write the data table
        pct = (50.0/3)/3
        self._bbgTbl.writeToRom(rom)
        updateProgress(pct)
        self._bbgScrollTbl.writeToRom(rom)
        updateProgress(pct)
        self._bbgDistorTbl.writeToRom(rom)
        updateProgress(pct)
Пример #4
0
class MapModule(EbModule.EbModule):
    _name = "Map"
    _MAP_PTRS_PTR_ADDR = 0xa1db
    _LOCAL_TSET_ADDR = 0x175000
    _MAP_HEIGHT = 320
    _MAP_WIDTH = 256

    def __init__(self):
        self._tiles = []
        self._mapSecTsetPalsTbl = EbTable(0xD7A800)
        self._mapSecMusicTbl = EbTable(0xDCD637)
        self._mapSecMiscTbl = EbTable(0xD7B200)
        self._mapSecTownMapTbl = EbTable(0xEFA70F)

        self.teleport = ValuedIntTableEntry(None, None,
                ["Enabled", "Disabled"])
        self.townmap = ValuedIntTableEntry(None, None,
                ["None", "Onett", "Twoson", "Threed", "Fourside", "Scaraba",
                "Summers", "None 2"])
        self.setting = ValuedIntTableEntry(None, None,
                ["None", "Indoors", "Exit Mouse usable",
                "Lost Underworld sprites", "Magicant sprites", "Robot sprites",
                "Butterflies", "Indoors and Butterflies"])

        self.townmap_image = ValuedIntTableEntry(None, None,
                ["None", "Onett", "Twoson", "Threed", "Fourside", "Scaraba",
                "Summers" ])
        self.townmap_arrow = ValuedIntTableEntry(None, None,
                ["None", "Up", "Down", "Right", "Left"])
    def readFromRom(self, rom):
        # Read map tiles
        map_ptrs_addr = \
            EbModule.toRegAddr(rom.readMulti(self._MAP_PTRS_PTR_ADDR, 3))
        map_addrs = map(lambda x: \
            EbModule.toRegAddr(rom.readMulti(map_ptrs_addr+x*4,4)), \
            range(8))
        self._tiles = map(
                lambda y: rom.readList(map_addrs[y%8] + ((y>>3)<<8),
                    self._MAP_WIDTH).tolist(),
                range(self._MAP_HEIGHT))
        k = self._LOCAL_TSET_ADDR
        for i in range(self._MAP_HEIGHT>>3):
            for j in range(self._MAP_WIDTH):
                self._tiles[i<<3][j] |= (rom[k] & 3) << 8
                self._tiles[(i<<3)|1][j] |= ((rom[k] >> 2) & 3) << 8
                self._tiles[(i<<3)|2][j] |= ((rom[k] >> 4) & 3) << 8
                self._tiles[(i<<3)|3][j] |= ((rom[k] >> 6) & 3) << 8
                self._tiles[(i<<3)|4][j] |= (rom[k+0x3000] & 3) << 8
                self._tiles[(i<<3)|5][j] |= ((rom[k+0x3000] >> 2) & 3) << 8
                self._tiles[(i<<3)|6][j] |= ((rom[k+0x3000] >> 4) & 3) << 8
                self._tiles[(i<<3)|7][j] |= ((rom[k+0x3000] >> 6) & 3) << 8
                k += 1
        updateProgress(25)
        # Read sector data
        self._mapSecTsetPalsTbl.readFromRom(rom)
        updateProgress(25.0/4)
        self._mapSecMusicTbl.readFromRom(rom)
        updateProgress(25.0/4)
        self._mapSecMiscTbl.readFromRom(rom)
        updateProgress(25.0/4)
        self._mapSecTownMapTbl.readFromRom(rom)
        updateProgress(25.0/4)
    def writeToRom(self, rom):
        map_ptrs_addr = \
            EbModule.toRegAddr(rom.readMulti(self._MAP_PTRS_PTR_ADDR, 3))
        map_addrs = map(lambda x: \
            EbModule.toRegAddr(rom.readMulti(map_ptrs_addr+x*4,4)), \
            range(8))
        for i in range(self._MAP_HEIGHT):
            rom.write(map_addrs[i%8] + ((i>>3)<<8), map(lambda x: x & 0xff,
                self._tiles[i]))
        k = self._LOCAL_TSET_ADDR
        for i in range(self._MAP_HEIGHT>>3):
            for j in range(self._MAP_WIDTH):
                c = ((self._tiles[i<<3][j] >> 8)
                        | ((self._tiles[(i<<3)|1][j] >> 8) << 2)
                        | ((self._tiles[(i<<3)|2][j] >> 8) << 4)
                        | ((self._tiles[(i<<3)|3][j] >> 8) << 6))
                rom.write(k, c)
                c = ((self._tiles[(i<<3)|4][j] >> 8)
                        | ((self._tiles[(i<<3)|5][j] >> 8) << 2)
                        | ((self._tiles[(i<<3)|6][j] >> 8) << 4)
                        | ((self._tiles[(i<<3)|7][j] >> 8) << 6))
                rom.write(k+0x3000, c)
                k += 1
        updateProgress(25)
        # Write sector data
        self._mapSecTsetPalsTbl.writeToRom(rom)
        updateProgress(25.0/4)
        self._mapSecMusicTbl.writeToRom(rom)
        updateProgress(25.0/4)
        self._mapSecMiscTbl.writeToRom(rom)
        updateProgress(25.0/4)
        self._mapSecTownMapTbl.writeToRom(rom)
        updateProgress(25.0/4)
    def writeToProject(self, resourceOpener):
        # Write map tiles
        with resourceOpener("map_tiles", "map") as f:
            for row in self._tiles:
                f.write(hex(row[0])[2:].zfill(3))
                for tile in row[1:]:
                    f.write(" ")
                    f.write(hex(tile)[2:].zfill(3))
                f.write("\n")
        updateProgress(25.0)
        # Write sector data
        out = dict()
        for i in range(self._mapSecTsetPalsTbl.height()):
            self.teleport.setVal(self._mapSecMiscTbl[i,0].val() >> 7)
            self.townmap.setVal((self._mapSecMiscTbl[i,0].val() >> 3) & 7)
            self.setting.setVal(self._mapSecMiscTbl[i,0].val() & 3)
            self.townmap_image.setVal(self._mapSecTownMapTbl[i,0].val() & 0xf)
            self.townmap_arrow.setVal(self._mapSecTownMapTbl[i,0].val() >> 4)
            out[i] = {
                    "Tileset": self._mapSecTsetPalsTbl[i,0].val() >> 3,
                    "Palette": self._mapSecTsetPalsTbl[i,0].val() & 7,
                    "Music": self._mapSecMusicTbl[i,0].dump(),
                    "Teleport": self.teleport.dump(),
                    "Town Map": self.townmap.dump(),
                    "Setting": self.setting.dump(),
                    "Item": self._mapSecMiscTbl[i,1].dump(),
                    "Town Map Image": self.townmap_image.dump(),
                    "Town Map Arrow": self.townmap_arrow.dump(),
                    "Town Map X": self._mapSecTownMapTbl[i,1].dump(),
                    "Town Map Y": self._mapSecTownMapTbl[i,2].dump() }
        updateProgress(12.5)
        with resourceOpener("map_sectors", "yml") as f:
            yaml.dump(out, f, Dumper=yaml.CSafeDumper, default_flow_style=False)
        updateProgress(12.5)
    def readFromProject(self, resourceOpener):
        # Read map data
        with resourceOpener("map_tiles", "map") as f:
            self._tiles = map(lambda y:
                    map(lambda x: int(x, 16), y.split(" ")),
                    f.readlines())
        updateProgress(25)
        # Read sector data
        self._mapSecTsetPalsTbl.clear(2560)
        self._mapSecMusicTbl.clear(2560)
        self._mapSecMiscTbl.clear(2560)
        self._mapSecTownMapTbl.clear(2560)
        pct = (25.0/2560)
        with resourceOpener("map_sectors", "yml") as f:
            input = yaml.load(f, Loader=yaml.CSafeLoader)
            for i in input:
                entry = input[i]
                self._mapSecTsetPalsTbl[i,0].setVal(
                        (entry["Tileset"] << 3) | entry["Palette"])
                self._mapSecMusicTbl[i,0].load(entry["Music"])
                self._mapSecMiscTbl[i,1].load(entry["Item"])
                self.teleport.load(entry["Teleport"])
                self.townmap.load(entry["Town Map"])
                self.setting.load(entry["Setting"])
                self._mapSecMiscTbl[i,0].setVal((self.teleport.val() << 7)
                        | (self.townmap.val() << 3) | self.setting.val())
                self.townmap_image.load(entry["Town Map Image"])
                self.townmap_arrow.load(entry["Town Map Arrow"])
                self._mapSecTownMapTbl[i,0].setVal(
                        (self.townmap_arrow.val() << 4) |
                        (self.townmap_image.val() & 0xf))
                self._mapSecTownMapTbl[i,1].load(entry["Town Map X"])
                self._mapSecTownMapTbl[i,2].load(entry["Town Map Y"])
                updateProgress(pct)
    def upgradeProject(self, oldVersion, newVersion, rom, resourceOpenerR,
            resourceOpenerW):
        global updateProgress
        def replaceField(fname, oldField, newField, valueMap):
            if newField == None:
                newField = oldField
            valueMap = dict((k, v) for k,v in valueMap.iteritems())
            with resourceOpenerR(fname, 'yml') as f:
                data = yaml.load(f, Loader=yaml.CSafeLoader)
                for i in data:
                    if data[i][oldField] in valueMap:
                        data[i][newField] = valueMap[data[i][oldField]].lower()
                    else:
                        data[i][newField] = data[i][oldField]
                    if newField != oldField:
                        del data[i][oldField]
            with resourceOpenerW(fname, 'yml') as f:
                yaml.dump(data, f, Dumper=yaml.CSafeDumper,
                        default_flow_style=False)

        if oldVersion == newVersion:
            updateProgress(100)
            return
        elif oldVersion <= 2:
            replaceField("map_sectors", "Town Map", None,
                    { "scummers": "summers" })

            # Need to add the Town Map Image/Arrow/X/Y fields
            tmp = updateProgress
            updateProgress = lambda x: None
            self.readFromRom(rom)
            updateProgress = tmp

            with resourceOpenerR("map_sectors", 'yml') as f:
                data = yaml.load(f, Loader=yaml.CSafeLoader)
                for i in data:
                    self.townmap_image.setVal(self._mapSecTownMapTbl[i,0].val() & 0xf)
                    self.townmap_arrow.setVal(self._mapSecTownMapTbl[i,0].val() >> 4)
                    data[i]["Town Map Image"] = self.townmap_image.dump()
                    data[i]["Town Map Arrow"] = self.townmap_arrow.dump()
                    data[i]["Town Map X"] = self._mapSecTownMapTbl[i,1].dump()
                    data[i]["Town Map Y"] = self._mapSecTownMapTbl[i,2].dump()
            with resourceOpenerW("map_sectors", 'yml') as f:
                yaml.dump(data, f, Dumper=yaml.CSafeDumper,
                        default_flow_style=False)

            self.upgradeProject(3, newVersion, rom, resourceOpenerR,
                    resourceOpenerW)
        else:
            self.upgradeProject(oldVersion+1, newVersion, rom, resourceOpenerR,
                                                            resourceOpenerW)
Пример #5
0
class EnemyModule(EbModule.EbModule):
    _name = "Enemies"
    _ASMPTR_GFX = 0x2ee0b
    _REGPTR_GFX = [ 0x2ebe0, 0x2f014, 0x2f065 ]
    _ASMPTR_PAL = 0x2ef74
    def __init__(self):
        self._enemyCfgTable = EbTable(0xd59589)
        self._bsPtrTbl = EbTable(0xce62ee)
        self._bsPalsTable = EbTable(0xce6514)
        self._enemyGroupTbl = EbTable(0xD0C60D)
        self._enemyGroupBgTbl = EbTable(0xCBD89A)

        self._bsprites = [ ]
        self._bsPals = [ ]
        self._enemyGroups = [ ]
    def readFromRom(self, rom):
        self._bsPtrTbl.readFromRom(rom,
                EbModule.toRegAddr(EbModule.readAsmPointer(rom,
                    self._ASMPTR_GFX)))
        self._bsPalsTable.readFromRom(rom,
                EbModule.toRegAddr(EbModule.readAsmPointer(rom,
                    self._ASMPTR_PAL)))
        pct = 45.0/(self._bsPtrTbl.height()
                + self._bsPalsTable.height() + 1)
        self._enemyCfgTable.readFromRom(rom)
        updateProgress(pct)
        # Read the palettes
        for i in range(self._bsPalsTable.height()):
            pal = EbPalettes(1,16)
            pal.set(0, self._bsPalsTable[i,0].val())
            self._bsPals.append(pal)
            updateProgress(pct)
        # Read the sprites
        for i in range(self._bsPtrTbl.height()):
            with EbCompressedData() as bsb:
                bsb.readFromRom(rom,
                        EbModule.toRegAddr(self._bsPtrTbl[i,0].val()))
                bs = EbBattleSprite()
                bs.readFromBlock(bsb, self._bsPtrTbl[i,1].val())
                self._bsprites.append(bs)
            updateProgress(pct)

        # Read the group data
        self._enemyGroupTbl.readFromRom(rom)
        self._enemyGroupBgTbl.readFromRom(rom)
        self._enemyGroups = [ ]
        pct = 5.0/self._enemyGroupTbl.height()
        for i in range(self._enemyGroupTbl.height()):
            group = [ ]
            ptr = EbModule.toRegAddr(self._enemyGroupTbl[i,0].val())
            while(rom[ptr] != 0xff):
                group.append((rom.readMulti(ptr+1,2), rom[ptr]))
                ptr += 3
            self._enemyGroups.append(group)
            updateProgress(pct)
    def freeRanges(self):
        return [(0x0d0000, 0x0dffff), # Battle Sprites
                (0x0e0000, 0x0e6913), # Battle Sprites Cont'd & Btl Spr. Pals
                (0x10d52d, 0x10dfb3)] # Enemy Group Data
    def writeToRom(self, rom):
        pct = 40.0/(len(self._bsprites) + len(self._bsPals) + 3)
        # Write the main table
        self._enemyCfgTable.writeToRom(rom)
        updateProgress(pct)
        # Write the gfx ptr table
        self._bsPtrTbl.clear(len(self._bsprites))
        i = 0
        for bs in self._bsprites:
            with EbCompressedData(bs.sizeBlock()) as bsb:
                bs.writeToBlock(bsb)
                self._bsPtrTbl[i,0].setVal(EbModule.toSnesAddr(
                    bsb.writeToFree(rom)))
            self._bsPtrTbl[i,1].setVal(bs.size())
            i += 1
            updateProgress(pct)
        gfxAddr = EbModule.toSnesAddr(self._bsPtrTbl.writeToFree(rom))
        EbModule.writeAsmPointer(rom, self._ASMPTR_GFX, gfxAddr)
        updateProgress(pct)
        for p in self._REGPTR_GFX:
            rom.writeMulti(p, gfxAddr, 3)
        # Write the pal table
        self._bsPalsTable.clear(len(self._bsPals))
        i = 0
        for p in self._bsPals:
            self._bsPalsTable[i,0].setVal(p.getSubpal(0))
            i += 1
            updateProgress(pct)
        EbModule.writeAsmPointer(rom, self._ASMPTR_PAL,
                EbModule.toSnesAddr(self._bsPalsTable.writeToFree(rom)))
        updateProgress(pct)
        # Write the groups
        self._enemyGroupBgTbl.writeToRom(rom)
        updateProgress(5)
        i=0
        for group in self._enemyGroups:
            loc = rom.getFreeLoc(len(group)*3 + 1)
            self._enemyGroupTbl[i,0].setVal(EbModule.toSnesAddr(loc))
            i += 1
            for enemyID, amount in group:
                rom[loc] = amount
                rom[loc+1] = enemyID & 0xff
                rom[loc+2] = enemyID >> 8
                loc += 3
            rom[loc] = 0xff
        self._enemyGroupTbl.writeToRom(rom)
        updateProgress(5)
    def writeToProject(self, resourceOpener):
        pct = 40.0/(self._enemyCfgTable.height() + 1)
        # First, write the Enemy Configuration Table
        self._enemyCfgTable.writeToProject(resourceOpener, [4,14])
        updateProgress(pct)

        # Next, write the battle sprite images
        for i in range(self._enemyCfgTable.height()):
            if self._enemyCfgTable[i,4].val() > 0:
                self._bsprites[self._enemyCfgTable[i,4].val()-1].writeToProject(
                        resourceOpener, i,
                        self._bsPals[self._enemyCfgTable[i,14].val()].getSubpal(0))
            updateProgress(pct)

        # Now write the groups
        out = dict()
        i = 0
        pct = 5.0/len(self._enemyGroups)
        for group in self._enemyGroups:
            entry = dict()
            for j in range(1,4):
                field = self._enemyGroupTbl[i,j]
                entry[field.name] = field.dump()
            for j in range(2):
                field = self._enemyGroupBgTbl[i,j]
                entry[field.name] = field.dump()
            enemyList = dict()
            j = 0
            for enemyID, amount in group:
                enemyEntry = dict()
                enemyEntry["Enemy"] = enemyID
                enemyEntry["Amount"] = amount
                enemyList[j] = enemyEntry
                j += 1
            entry["Enemies"] = enemyList
            out[i] = entry
            i += 1
            updateProgress(pct)
        with resourceOpener("enemy_groups", "yml") as f:
            yaml.dump(out, f, Dumper=yaml.CSafeDumper)
        updateProgress(5)
    def readFromProject(self, resourceOpener):
        # First, read the Enemy Configuration Table
        self._enemyCfgTable.readFromProject(resourceOpener)
        pct = 40.0/(self._enemyCfgTable.height())

        # Second, read the Battle Sprites
        bsHashes = dict()
        bsNextNum = 1
        palNextNum = 0
        for i in range(self._enemyCfgTable.height()):
            bs = EbBattleSprite()
            pal = EbPalettes(1,16)
            try:
                bs.readFromProject(resourceOpener, i, pal)
                # Add the battle sprite
                try:
                    #self._enemyCfgTable[i,4].set(self._bsprites.index(bs))
                    bsNum = bsHashes[bs._sprite._spriteHash]
                    self._enemyCfgTable[i,4].setVal(bsNum)
                except KeyError:
                    self._bsprites.append(bs)
                    self._enemyCfgTable[i,4].setVal(bsNextNum)
                    bsHashes[bs._sprite._spriteHash] = bsNextNum
                    bsNextNum += 1
                # Add the palette
                # TODO should probably use hash table here too?
                #      then again, I don't think it's actually a bottleneck
                try:
                    self._enemyCfgTable[i,14].setVal(self._bsPals.index(pal))
                except ValueError:
                    self._bsPals.append(pal)
                    self._enemyCfgTable[i,14].setVal(palNextNum)
                    palNextNum += 1
            except IOError:
                # No battle sprite PNG
                self._enemyCfgTable[i,4].setVal(0)
                self._enemyCfgTable[i,14].setVal(0)
            updateProgress(pct)

        # Third, read the groups
        self._enemyGroupTbl.readFromProject(resourceOpener, "enemy_groups")
        updateProgress(2)
        self._enemyGroupBgTbl.readFromProject(resourceOpener, "enemy_groups")
        updateProgress(2)
        self._enemyGroups = [ ]
        pct = 4.0/484
        with resourceOpener("enemy_groups", "yml") as f:
            input = yaml.load(f, Loader=yaml.CSafeLoader)
            updateProgress(2)
            for group in input:
                tmp1 = input[group]["Enemies"]
                enemyList = [ ]
                i = 0
                for enemy in tmp1:
                    tmp2 = tmp1[i]
                    enemyList.append((tmp2["Enemy"], tmp2["Amount"]))
                    i += 1
                self._enemyGroups.append(enemyList)
                updateProgress(pct)
Пример #6
0
class TilesetModule(EbModule.EbModule):
    _name = "Tilesets"
    def __init__(self):
        self._gfxPtrTbl = EbTable("MAP_DATA_TILESET_PTR_TABLE")
        self._arrPtrTbl = EbTable("MAP_DATA_TILE_ARRANGEMENT_PTR_TABLE")
        self._colPtrTbl = EbTable("MAP_DATA_TILE_COLLISION_PTR_TABLE")
        self._mapTsetTbl = EbTable("TILESET_TABLE")
        self._palPtrTbl = EbTable("MAP_PALETTE_PTR_TABLE")
        self._tsets = [ Tileset() for i in range(20) ]
    def freeRanges(self):
        return [(0x17c600, 0x17fbe7),
                (0x190000, 0x19fc17),
                (0x1b0000, 0x1bf2ea),
                (0x1c0000, 0x1cd636),
                (0x1d0000, 0x1dfecd),
                (0x1e0000, 0x1ef0e6),
                (0x1f0000, 0x1fc242)]
    def readFromRom(self, rom):
        self._gfxPtrTbl.readFromRom(rom)
        updateProgress(2)
        self._arrPtrTbl.readFromRom(rom)
        updateProgress(2)
        self._colPtrTbl.readFromRom(rom)
        updateProgress(2)
        self._mapTsetTbl.readFromRom(rom)
        updateProgress(2)
        self._palPtrTbl.readFromRom(rom)
        updateProgress(2)

        # Read tilesets
        pct = 30.0/len(self._tsets)
        i=0
        for tset in self._tsets:
            # Read data
            tset.readMinitilesFromRom(rom,
                    EbModule.toRegAddr(self._gfxPtrTbl[i,0].val()))
            tset.readArrangementsFromRom(rom,
                    EbModule.toRegAddr(self._arrPtrTbl[i,0].val()))
            tset.readCollisionsFromRom(rom,
                    EbModule.toRegAddr(self._colPtrTbl[i,0].val()))
            i += 1
            updateProgress(pct)

        # Read palettes
        pct = 10.0/self._mapTsetTbl.height()
        for i in range(self._mapTsetTbl.height()):
            drawTset = self._mapTsetTbl[i,0].val()
            # Each map tset has 8 maximum palettes
            # We'll just assume they all use 8 and read the garbage
            #romLoc = self._palPtrTbl[i,0].val()
            #for j in xrange(8):
            #    # Read the palette
            #    self._tsets[drawTset].readPaletteFromRom(rom, i, j,
            #            EbModule.toRegAddr(romLoc))
            #    romLoc += 0xc0

            # OK, as it turns out, all palettes need to be in the 1A bank
            # So we actually need to conserve space and not read garbage
            # Estimate the number of palettes for this map tileset
            if i == 31:
                #k = 0xDAFAA7 - self._palPtrTbl[i,0].val()
                k = 7
            else:
                k = self._palPtrTbl[i+1,0].val() - self._palPtrTbl[i,0].val()
                k /= 0xc0
            # Add the palettes
            romLoc = EbModule.toRegAddr(self._palPtrTbl[i,0].val())
            for j in range(k):
                # Read the palette
                self._tsets[drawTset].readPaletteFromRom(rom, i, j, romLoc)
                romLoc += 0xc0
            updateProgress(pct)

    def writeToRom(self, rom):
        numTsets = len(self._tsets)
        self._gfxPtrTbl.clear(numTsets)
        self._arrPtrTbl.clear(numTsets)
        self._colPtrTbl.clear(numTsets)
        self._mapTsetTbl.clear(32)
        self._palPtrTbl.clear(32)

        # Write gfx & arrs
        pct = 30.0/numTsets
        i=0
        for tset in self._tsets:
            self._gfxPtrTbl[i,0].setVal(EbModule.toSnesAddr(
                tset.writeMinitilesToFree(rom)))
            self._arrPtrTbl[i,0].setVal(EbModule.toSnesAddr(
               tset.writeArrangementsToFree(rom)))
            i += 1
            updateProgress(pct)
        self._gfxPtrTbl.writeToRom(rom)
        updateProgress(2)
        self._arrPtrTbl.writeToRom(rom)
        updateProgress(2)

        # Write collissions
        pct = 6.0/numTsets
        colLocs = dict()
        colWriteLoc = 0x180000
        colRangeEnd = 0x18f05d
        i=0
        for tset in self._tsets:
            with DataBlock(len(tset.col)*2) as colTable:
                j=0
                for c in tset.col:
                    hash = crc32(c)
                    try:
                        addr = colLocs[hash]
                    except KeyError:
                        if (colWriteLoc + 16) > colRangeEnd:
                            # TODO Error, not enough space for collisions
                            print "Ran out of collision space"
                            raise Exception
                            addr = 0
                        else:
                            colLocs[hash] = colWriteLoc
                            addr = colWriteLoc
                            rom.write(colWriteLoc, c)
                            colWriteLoc += 16
                    colTable[j] = addr & 0xff
                    colTable[j+1] = (addr >> 8) & 0xff
                    j += 2
                self._colPtrTbl[i,0].setVal(EbModule.toSnesAddr(
                    colTable.writeToFree(rom)))
                i += 1
            updateProgress(pct)
        self._colPtrTbl.writeToRom(rom)
        updateProgress(1)

        # Write the palettes, they need to be in the DA bank
        pct = 7.0/32
        palWriteLoc = 0x1a0000
        palRangeEnd = 0x1afaa6 # can we go more?
        # Write maps/drawing tilesets associations and map tset pals
        for i in range(32): # For each map tileset
            # Find the drawing tileset number for this map tileset
            drawTset = -1
            j = 0
            for tset in self._tsets:
                for (mt,mp,pal) in tset.pals:
                    if mt == i:
                        drawTset = j
                        break
                if drawTset != -1:
                    break
                j += 1
            else:
                # TODO Error, this drawing tileset isn't associated
                drawTset = 0
            self._mapTsetTbl[i,0].setVal(drawTset)
            # Write the palette data for this map tileset
            mtset_pals = [(mp,pal) for (mt,mp,pal)
                    in self._tsets[drawTset].pals if mt == i]
            mtset_pals.sort()
            # Let's take the easy way out and just write redundant flag pals
            # This will waste space but oh well
            # First, write the flag pals
            for (mp,pal) in mtset_pals:
                if pal.flag != 0:
                    if palWriteLoc + 0xc0 > palRangeEnd:
                        # TODO Error, not enough space for all these palettes
                        raise RuntimeError("Too many palettes")
                    pal.flagPal.writeToBlock(rom, palWriteLoc)
                    pal.flagPalPtr = palWriteLoc & 0xffff
                    palWriteLoc += 0xc0
            self._palPtrTbl[i,0].setVal(EbModule.toSnesAddr(palWriteLoc))
            # Now write the regular pals
            for (mp,pal) in mtset_pals:
                if palWriteLoc + 0xc0 > palRangeEnd:
                    # TODO Error, not enough space for all these palettes
                    raise RuntimeException("Too many palettes")
                pal.writeToBlock(rom, palWriteLoc)
                palWriteLoc += 0xc0
            updateProgress(pct)
        self._mapTsetTbl.writeToRom(rom)
        updateProgress(1)
        self._palPtrTbl.writeToRom(rom)
        updateProgress(1)

        # Might as well use any extra leftover space
        ranges = [(colWriteLoc, colRangeEnd), (palWriteLoc, palRangeEnd)]
        ranges = [(a,b) for (a,b) in ranges if a < b]
        rom.addFreeRanges(ranges)

    def writeToProject(self, resourceOpener):
        # Dump an additional YML with color0 data
        out = dict()
        for i in range(0,32): # For each map tset
            entry = dict()
            tset = None
            for ts in self._tsets:
                if ts.hasMapTileset(i):
                    tset = ts
                    break
            for (pN,p) in [(mp,p) for (mt,mp,p) in tset.pals if mt == i]:
                entry[pN] = p.dump()
            out[i] = entry
        with resourceOpener('map_palette_settings', 'yml') as f:
            s = yaml.dump(out, default_flow_style=False,
                    Dumper=yaml.CSafeDumper)
            s = sub("Event Flag: (\d+)",
                    lambda i: "Event Flag: " + hex(int(i.group(0)[12:])), s)
            f.write(s)
        updateProgress(5)

        # Dump the FTS files
        pct=45.0/len(self._tsets)
        i=0
        for tset in self._tsets:
            with resourceOpener('Tilesets/' + str(i).zfill(2), 'fts') as f:
                tset.writeToFTS(f)
            i += 1
            updateProgress(pct)
    def readFromProject(self, resourceOpener):
        i=0
        pct = 45.0/len(self._tsets)
        for tset in self._tsets:
            with resourceOpener('Tilesets/' + str(i).zfill(2), 'fts') as f:
                tset.readFromFTS(f)
            i += 1
            updateProgress(pct)
        with resourceOpener('map_palette_settings', 'yml') as f:
            input = yaml.load(f, Loader=yaml.CSafeLoader)
            for mtset in input: # For each map tileset
                # Get the draw (normal) tileset
                tset = None
                for ts in self._tsets:
                    if ts.hasMapTileset(mtset):
                        tset = ts
                        break
                # For each map palette
                mtset_pals = [(mp,p) for (mt,mp,p) in tset.pals if mt == mtset]
                for (pN,mtset_pal) in mtset_pals:
                    entry = input[mtset][pN]
                    mtset_pal.flag = entry["Event Flag"]
                    mtset_pal.flashEffect = entry["Flash Effect"]
                    mtset_pal.spritePalNum = entry["Sprite Palette"]
                    if mtset_pal.flag != 0:
                        mtset_pal.flagPal = MapPalette()
                        mtset_pal.flagPal.setFromString(entry["Event Palette"])
                        mtset_pal.flagPal.spritePalNum = entry["Sprite Palette"]
                updateProgress(5.0/32)
Пример #7
0
class MapEnemyModule(EbModule.EbModule):
    _name = "Map Enemies"

    def __init__(self):
        self._mapGroupPtrTbl = EbTable("ENEMY_PLACEMENT_GROUPS_PTR_TABLE")
        self._mapEnemyTbl = EbTable("ENEMY_PLACEMENT_DATA")

    def freeRanges(self):
        return [(0x10BBAC, 0x10C6AC)]  # Groups data

    def readFromRom(self, rom):
        self._mapEnemyTbl.readFromRom(rom)
        updateProgress(2.5)
        self._mapGroupPtrTbl.readFromRom(rom)
        updateProgress(2.5)

        # Read the groups
        pct = 45.0 / (self._mapGroupPtrTbl.height())
        self._mapGroups = []
        for i in range(self._mapGroupPtrTbl.height()):
            loc = EbModule.toRegAddr(self._mapGroupPtrTbl[i, 0].val())
            flag = rom.readMulti(loc, 2)
            rate1 = rom[loc + 2]
            rate2 = rom[loc + 3]
            loc += 4

            # Read the enemies/probabilities
            group1 = []
            if rate1 > 0:
                sum = 0
                while sum < 8:
                    prob = rom[loc]
                    enemy = rom.readMulti(loc + 1, 2)
                    sum += prob
                    loc += 3
                    group1.append((prob, enemy))
            group2 = []
            if rate2 > 0:
                sum = 0
                while sum < 8:
                    prob = rom[loc]
                    enemy = rom.readMulti(loc + 1, 2)
                    sum += prob
                    loc += 3
                    group2.append((prob, enemy))

            # Add to the list
            self._mapGroups.append((flag, rate1, rate2, group1, group2))
            updateProgress(pct)

    def writeToRom(self, rom):
        self._mapEnemyTbl.writeToRom(rom)
        updateProgress(2.5)
        self._mapGroupPtrTbl.clear(len(self._mapGroups))
        updateProgress(2.5)

        pct = 42.5 / len(self._mapGroups)
        i = 0
        for (flag, rate1, rate2, subg1, subg2) in self._mapGroups:
            size = 4
            if rate1 > 0:
                size += len(subg1) * 3
            if rate2 > 0:
                size += len(subg2) * 3
            loc = rom.getFreeLoc(size)
            self._mapGroupPtrTbl[i, 0].setVal(EbModule.toSnesAddr(loc))

            rom.writeMulti(loc, flag, 2)
            rom[loc + 2] = rate1
            rom[loc + 3] = rate2
            loc += 4
            for prob, egroup in subg1:
                rom[loc] = prob
                rom.writeMulti(loc + 1, egroup, 2)
                loc += 3
            for prob, egroup in subg2:
                rom[loc] = prob
                rom.writeMulti(loc + 1, egroup, 2)
                loc += 3
            i += 1
            updateProgress(pct)
        self._mapGroupPtrTbl.writeToRom(rom)
        updateProgress(2.5)

    def writeToProject(self, resourceOpener):
        self._mapEnemyTbl.writeToProject(resourceOpener)
        updateProgress(2.5)

        # Write the groups
        pct = 42.5 / len(self._mapGroups)
        out = dict()
        i = 0
        for (flag, rate1, rate2, group1, group2) in self._mapGroups:
            # Generate first enemy/prob list
            g1out = dict()
            j = 0
            for prob, enemy in group1:
                g1out[j] = {"Enemy Group": enemy, "Probability": prob}
                j += 1
            g2out = dict()
            j = 0
            for prob, enemy in group2:
                g2out[j] = {"Enemy Group": enemy, "Probability": prob}
                j += 1
            out[i] = {
                "Event Flag": flag,
                "Sub-Group 1 Rate": rate1,
                "Sub-Group 1": g1out,
                "Sub-Group 2 Rate": rate2,
                "Sub-Group 2": g2out,
            }
            i += 1
            updateProgress(pct)
        s = yaml.dump(out, Dumper=yaml.CSafeDumper)
        updateProgress(2.5)
        s = sub("Event Flag: (\d+)", lambda i: "Event Flag: " + hex(int(i.group(0)[12:])), s)
        with resourceOpener("map_enemy_groups", "yml") as f:
            f.write(s)
        updateProgress(2.5)

    def readFromProject(self, resourceOpener):
        self._mapEnemyTbl.readFromProject(resourceOpener)
        updateProgress(5)

        pct = 40.0 / 203
        self._mapGroups = []
        with resourceOpener("map_enemy_groups", "yml") as f:
            input = yaml.load(f, Loader=yaml.CSafeLoader)
            updateProgress(5)
            for gid in input:
                group = input[gid]
                flag = group["Event Flag"]
                rate1 = group["Sub-Group 1 Rate"]
                rate2 = group["Sub-Group 2 Rate"]

                subg1 = []
                if rate1 > 0:
                    for eid in group["Sub-Group 1"]:
                        entry = group["Sub-Group 1"][eid]
                        subg1.append((entry["Probability"], entry["Enemy Group"]))
                subg2 = []
                if rate2 > 0:
                    for eid in group["Sub-Group 2"]:
                        entry = group["Sub-Group 2"][eid]
                        subg2.append((entry["Probability"], entry["Enemy Group"]))
                self._mapGroups.append((flag, rate1, rate2, subg1, subg2))
                updateProgress(pct)
Пример #8
0
class MapModule(EbModule.EbModule):
    _name = "Map"
    _MAP_PTRS_PTR_ADDR = 0xa1db
    _LOCAL_TSET_ADDR = 0x175000
    _MAP_HEIGHT = 320
    _MAP_WIDTH = 256

    def __init__(self):
        self._tiles = []
        self._mapSecTsetPalsTbl = EbTable("GLOBAL_MAP_TILESETPALETTE_DATA")
        self._mapSecMusicTbl = EbTable("MAP_DATA_PER-SECTOR_MUSIC")
        self._mapSecMiscTbl = EbTable("MAP_DATA_PER-SECTOR_ATTRIBUTES_TABLE")
        self.teleport = ValuedIntTableEntry(None, None,
                ["Enabled", "Disabled"])
        self.townmap = ValuedIntTableEntry(None, None,
                ["None", "Onett", "Twoson", "Threed", "Fourside", "Scaraba",
                "Scummers", "None 2"])
        self.setting = ValuedIntTableEntry(None, None,
                ["None", "Indoors", "Exit Mouse usable",
                "Lost Underworld sprites", "Magicant sprites", "Robot sprites",
                "Butterflies", "Indoors and Butterflies"])
    def readFromRom(self, rom):
        # Read map tiles
        map_ptrs_addr = \
            EbModule.toRegAddr(rom.readMulti(self._MAP_PTRS_PTR_ADDR, 3))
        map_addrs = map(lambda x: \
            EbModule.toRegAddr(rom.readMulti(map_ptrs_addr+x*4,4)), \
            range(8))
        self._tiles = map(
                lambda y: rom.readList(map_addrs[y%8] + ((y>>3)<<8),
                    self._MAP_WIDTH).tolist(),
                range(self._MAP_HEIGHT))
        k = self._LOCAL_TSET_ADDR
        for i in range(self._MAP_HEIGHT>>3):
            for j in range(self._MAP_WIDTH):
                self._tiles[i<<3][j] |= (rom[k] & 3) << 8
                self._tiles[(i<<3)|1][j] |= ((rom[k] >> 2) & 3) << 8
                self._tiles[(i<<3)|2][j] |= ((rom[k] >> 4) & 3) << 8
                self._tiles[(i<<3)|3][j] |= ((rom[k] >> 6) & 3) << 8
                self._tiles[(i<<3)|4][j] |= (rom[k+0x3000] & 3) << 8
                self._tiles[(i<<3)|5][j] |= ((rom[k+0x3000] >> 2) & 3) << 8
                self._tiles[(i<<3)|6][j] |= ((rom[k+0x3000] >> 4) & 3) << 8
                self._tiles[(i<<3)|7][j] |= ((rom[k+0x3000] >> 6) & 3) << 8
                k += 1
        updateProgress(25)
        # Read sector data
        self._mapSecTsetPalsTbl.readFromRom(rom)
        updateProgress(25.0/3)
        self._mapSecMusicTbl.readFromRom(rom)
        updateProgress(25.0/3)
        self._mapSecMiscTbl.readFromRom(rom)
        updateProgress(25.0/3)
    def writeToRom(self, rom):
        map_ptrs_addr = \
            EbModule.toRegAddr(rom.readMulti(self._MAP_PTRS_PTR_ADDR, 3))
        map_addrs = map(lambda x: \
            EbModule.toRegAddr(rom.readMulti(map_ptrs_addr+x*4,4)), \
            range(8))
        for i in range(self._MAP_HEIGHT):
            rom.write(map_addrs[i%8] + ((i>>3)<<8), map(lambda x: x & 0xff,
                self._tiles[i]))
        k = self._LOCAL_TSET_ADDR
        for i in range(self._MAP_HEIGHT>>3):
            for j in range(self._MAP_WIDTH):
                c = ((self._tiles[i<<3][j] >> 8)
                        | ((self._tiles[(i<<3)|1][j] >> 8) << 2)
                        | ((self._tiles[(i<<3)|2][j] >> 8) << 4)
                        | ((self._tiles[(i<<3)|3][j] >> 8) << 6))
                rom.write(k, c)
                c = ((self._tiles[(i<<3)|4][j] >> 8)
                        | ((self._tiles[(i<<3)|5][j] >> 8) << 2)
                        | ((self._tiles[(i<<3)|6][j] >> 8) << 4)
                        | ((self._tiles[(i<<3)|7][j] >> 8) << 6))
                rom.write(k+0x3000, c)
                k += 1
        updateProgress(25)
        # Write sector data
        self._mapSecTsetPalsTbl.writeToRom(rom)
        updateProgress(25.0/3)
        self._mapSecMusicTbl.writeToRom(rom)
        updateProgress(25.0/3)
        self._mapSecMiscTbl.writeToRom(rom)
        updateProgress(25.0/3)
    def writeToProject(self, resourceOpener):
        # Write map tiles
        with resourceOpener("map_tiles", "map") as f:
            for row in self._tiles:
                f.write(hex(row[0])[2:].zfill(3))
                for tile in row[1:]:
                    f.write(" ")
                    f.write(hex(tile)[2:].zfill(3))
                f.write("\n")
        updateProgress(25.0)
        # Write sector data
        out = dict()
        for i in range(self._mapSecTsetPalsTbl.height()):
            self.teleport.setVal(self._mapSecMiscTbl[i,0].val() >> 7)
            self.townmap.setVal((self._mapSecMiscTbl[i,0].val() >> 3) & 7)
            self.setting.setVal(self._mapSecMiscTbl[i,0].val() & 3)
            out[i] = {
                    "Tileset": self._mapSecTsetPalsTbl[i,0].val() >> 3,
                    "Palette": self._mapSecTsetPalsTbl[i,0].val() & 7,
                    "Music": self._mapSecMusicTbl[i,0].dump(),
                    "Teleport": self.teleport.dump(),
                    "Town Map": self.townmap.dump(),
                    "Setting": self.setting.dump(),
                    "Item": self._mapSecMiscTbl[i,1].dump() }
        updateProgress(12.5)
        with resourceOpener("map_sectors", "yml") as f:
            yaml.dump(out, f, Dumper=yaml.CSafeDumper, default_flow_style=False)
        updateProgress(12.5)
    def readFromProject(self, resourceOpener):
        # Read map data
        with resourceOpener("map_tiles", "map") as f:
            self._tiles = map(lambda y:
                    map(lambda x: int(x, 16), y.split(" ")),
                    f.readlines())
        updateProgress(25)
        # Read sector data
        self._mapSecTsetPalsTbl.clear(2560)
        self._mapSecMusicTbl.clear(2560)
        self._mapSecMiscTbl.clear(2560)
        pct = (25.0/2560)
        with resourceOpener("map_sectors", "yml") as f:
            input = yaml.load(f, Loader=yaml.CSafeLoader)
            for i in input:
                entry = input[i]
                self._mapSecTsetPalsTbl[i,0].setVal(
                        (entry["Tileset"] << 3) | entry["Palette"])
                self._mapSecMusicTbl[i,0].load(entry["Music"])
                self._mapSecMiscTbl[i,1].load(entry["Item"])
                self.teleport.load(entry["Teleport"])
                self.townmap.load(entry["Town Map"])
                self.setting.load(entry["Setting"])
                self._mapSecMiscTbl[i,0].setVal((self.teleport.val() << 7)
                        | (self.townmap.val() << 3) | self.setting.val())
                updateProgress(pct)
Пример #9
0
class SpriteGroupModule(EbModule.EbModule):
    _name = "Sprite Groups"
    def __init__(self):
        self._grPtrTbl = EbTable(0xef133f)
        self._grPalTbl = EbTable(0xc30000)
        self._groups = None
    def freeRanges(self):
        return [(0x2f1a7f, 0x2f4a3f),
                (0x110000, 0x11ffff),
                (0x120000, 0x12ffff),
                (0x130000, 0x13ffff),
                (0x140000, 0x14ffff),
                (0x150000, 0x154fff)]
    def free(self):
        del(self._grPtrTbl)
        del(self._grPalTbl)
    def readFromRom(self, rom):
        self._grPtrTbl.readFromRom(rom)
        updateProgress(5)
        self._grPalTbl.readFromRom(rom)
        updateProgress(5)

        # Load the sprite groups
        self._groups = []
        pct = 40.0/self._grPtrTbl.height()
        for i in range(self._grPtrTbl.height()):
            # Note: this assumes that the SPT is written contiguously
            numSprites = 8
            # Assume that the last group only has 8 sprites
            if i < self._grPtrTbl.height()-1:
                numSprites = (self._grPtrTbl[i+1,0].val() -
                        self._grPtrTbl[i,0].val() - 9) / 2

            g = SpriteGroup(numSprites)
            g.readFromRom(rom, EbModule.toRegAddr(self._grPtrTbl[i,0].val()))
            self._groups.append(g)
            updateProgress(pct)
    def writeToProject(self, resourceOpener):
        # Write the palettes
        self._grPalTbl.writeToProject(resourceOpener)
        updateProgress(5)
        out = { }
        i = 0
        pct = 40.0/len(self._groups)
        for g in self._groups:
            out[i] = g.dump()
            img = g.toImage(self._grPalTbl[g.palette(),0].val())
            imgFile = resourceOpener("SpriteGroups/" + str(i).zfill(3), 'png')
            img.save(imgFile, 'png', transparency=0)
            imgFile.close()
            del(img)
            i += 1
            updateProgress(pct)
        yaml.dump(out, resourceOpener("sprite_groups", "yml"),
                Dumper=yaml.CSafeDumper)
        updateProgress(5)
    def readFromProject(self, resourceOpener):
        self._grPalTbl.readFromProject(resourceOpener)
        updateProgress(5)
        input = yaml.load(resourceOpener("sprite_groups", "yml"),
                Loader=yaml.CSafeLoader)
        numGroups = len(input)
        self._groups = []
        pct = 45.0/numGroups
        for i in range(numGroups):
            g = SpriteGroup(16)
            g.load(input[i])
            try:
                img = Image.open(
                        resourceOpener("SpriteGroups/" + str(i).zfill(3), "png"))
            except IOError:
                print "Could not load Sprite Group #" + str(i)
                raise

            if img.mode != 'P':
                raise RuntimeError("SpriteGroups/" +
                        str(i).zfill(3) + " is not an indexed PNG.")

            g.fromImage(img)
            palData = img.getpalette()
            del(img)
            self._groups.append(g)
            pal = [ ]

            # Read the palette from the image
            for j in range(1, 16):
                pal.append((palData[j*3], palData[j*3+1], palData[j*3+2]))
            # Assign the palette number to the sprite
            for j in range(8):
                if pal == self._grPalTbl[j,0].val()[1:]:
                    g.setPalette(j)
                    break
            else:
                # Error, this image uses an invalid palette
                for j in range(8):
                    print j, ":", self._grPalTbl[j,0].val()[1:]
                raise RuntimeError("Sprite Group #" + str(i)
                        + " uses an invalid palette: " + str(pal))
            updateProgress(pct)
            
    def writeToRom(self, rom):
        numGroups = len(self._groups)
        self._grPtrTbl.clear(numGroups)
        with DataBlock(sum(map(
            lambda x: x.blockSize(), self._groups))) as block:
            loc = 0
            i = 0
            # Write all the groups to the block, and sprites to rom
            pct = 40.0 / numGroups
            for g in self._groups:
                g.writeSpritesToFree(rom)
                g.writeToBlock(block, loc)
                self._grPtrTbl[i,0].setVal(loc)
                loc += g.blockSize()
                i += 1
                updateProgress(pct)
            # Write the block to rom and correct the group pointers
            addr = EbModule.toSnesAddr(block.writeToFree(rom))
            for i in range(self._grPtrTbl.height()):
                self._grPtrTbl[i,0].setVal(
                        self._grPtrTbl[i,0].val() + addr)
        # Write the pointer table
        self._grPtrTbl.writeToRom(rom)
        updateProgress(5)
        # Write the palettes
        self._grPalTbl.writeToRom(rom)
        updateProgress(5)
    def upgradeProject(self, oldVersion, newVersion, rom, resourceOpenerR,
            resourceOpenerW):
        def replaceField(fname, oldField, newField, valueMap):
            if newField == None:
                newField = oldField
            valueMap = dict((k, v) for k,v in valueMap.iteritems())
            with resourceOpenerR(fname, 'yml') as f:
                data = yaml.load(f, Loader=yaml.CSafeLoader)
                for i in data:
                    if data[i][oldField] in valueMap:
                        data[i][newField] = valueMap[data[i][oldField]].lower()
                    else:
                        data[i][newField] = data[i][oldField]
                    if newField != oldField:
                        del data[i][oldField]
            with resourceOpenerW(fname, 'yml') as f:
                yaml.dump(data, f, Dumper=yaml.CSafeDumper)
        def replaceFieldName(fname, oldField, newField):
            if newField == None:
                newField = oldField
            with resourceOpenerR(fname, 'yml') as f:
                data = yaml.load(f, Loader=yaml.CSafeLoader)
                for i in data:
                    data[i][newField] = data[i][oldField]
                    del data[i][oldField]
            with resourceOpenerW(fname, 'yml') as f:
                yaml.dump(data, f, Dumper=yaml.CSafeDumper)

        if oldVersion == newVersion:
            updateProgress(100)
            return
        elif oldVersion == 2:
            replaceField("sprite_groups",
                    "Unknown A", "Size",
                    { 0: "16x16",
                        1: "16x16 2",
                        2: "24x16",
                        3: "32x16",
                        4: "48x16",
                        5: "16x24",
                        6: "24x24",
                        7: "16x32",
                        8: "32x32",
                        9: "48x32",
                        10: "24x40",
                        11: "16x48",
                        12: "32x48",
                        13: "48x48",
                        14: "64x48",
                        15: "64x64",
                        16: "64x80" })
            replaceFieldName("sprite_groups", "Unknown B", "Collision Settings")
            self.upgradeProject(oldVersion+1, newVersion, rom, resourceOpenerR,
                    resourceOpenerW)
        elif oldVersion == 1:
            self.upgradeProject(oldVersion+1, newVersion, rom, resourceOpenerR,
                    resourceOpenerW)