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)
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)
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)
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)
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)