class MapSpriteModule(EbModule.EbModule): _name = "Map Sprites" _PTR_LOC = 0x2261 def __init__(self): self._ptrTbl = EbTable("SPRITE_PLACEMENT_PTR_TABLE") self._entries = [ ] def readFromRom(self, rom): ptr = EbModule.toRegAddr(rom.readMulti(self._PTR_LOC, 3)) updateProgress(5) self._ptrTbl.readFromRom(rom, ptr) pct = 45.0/(40*32) for i in range(self._ptrTbl.height()): loc = self._ptrTbl[i,0].val() # Format: AA AA [BB BB YY XX] # AA = # of entries. BB = TPT. YY = y pos. XX = x pos. if loc != 0: loc |= 0x0F0000 entry = [ ] size = rom.readMulti(loc, 2) loc += 2 for i in range(size): entry.append(SpritePlacement( rom.readMulti(loc, 2), rom[loc+3], rom[loc+2])) loc += 4 self._entries.append(entry) else: self._entries.append(None) updateProgress(pct) def writeToProject(self, resourceOpener): out = dict() x = y = 0 rowOut = dict() pct = 45.0/(40*32) for entry in self._entries: if entry != None: rowOut[x%32] = map( lambda sp: { "NPC ID": sp.npcID, "X": sp.x, "Y": sp.y }, entry) else: rowOut[x%32] = None if (x % 32) == 31: # Start next row out[y] = rowOut x = 0 y += 1 rowOut = dict() else: x += 1 updateProgress(pct) with resourceOpener("map_sprites", "yml") as f: yaml.dump(out, f, Dumper=yaml.CSafeDumper) updateProgress(5) def readFromProject(self, resourceOpener): self._entries = [] pct = 45.0/(40*32) with resourceOpener("map_sprites", "yml") as f: input = yaml.load(f, Loader=yaml.CSafeLoader) updateProgress(5) for y in input: row = input[y] for x in row: if row[x] == None: self._entries.append(None) else: self._entries.append(map(lambda x: SpritePlacement( x["NPC ID"], x["X"], x["Y"]), row[x])) updateProgress(pct) def writeToRom(self, rom): self._ptrTbl.clear(32*40) writeLoc = 0xf61e7 writeRangeEnd = 0xf8984 i = 0 pct = 45.0/(40*32) for entry in self._entries: if (entry == None) or (not entry): self._ptrTbl[i,0].setVal(0) else: entryLen = len(entry) with DataBlock(2 + entryLen*4) as block: block[0] = entryLen & 0xff block[1] = entryLen >> 8 j = 2 for sprite in entry: block[j] = sprite.npcID & 0xff block[j+1] = sprite.npcID >> 8 block[j+2] = sprite.y block[j+3] = sprite.x j += 4 if writeLoc + len(block) > writeRangeEnd: # TODO Error, not enough space raise RuntimeError("Not enough map sprite space") else: block.writeToRom(rom, writeLoc) self._ptrTbl[i,0].setVal(writeLoc & 0xffff) writeLoc += len(block) updateProgress(pct) i += 1 loc = self._ptrTbl.writeToFree(rom) rom.writeMulti(self._PTR_LOC, EbModule.toSnesAddr(loc), 3) # Mark any remaining space as free if writeLoc < writeRangeEnd: rom.addFreeRanges([(writeLoc, writeRangeEnd)]) 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 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 TownMapIconModule(EbModule.EbModule): _name = "Town Map Icon Positions" _ASMPTR_PTR_TBL = 0x4d464 def __init__(self): self._ptrTbl = EbTable(0xE1F491) self._entries = [ ] self._entryIdField = ValuedIntTableEntry(None, None, ["Onett", "Twoson", "Threed", "Fourside", "Scaraba", "Summers"]) self._iconField = ValuedIntTableEntry(None, None, ["0", "Hamburger Shop", "Bakery", "Hotel", "Restaurant", "Hospital", "Shop", "Dept Store", "Bus Stop", "South to Twoson", "North to Onett", "South to Threed", "West to Twoson", "East to Desert", "West to Desert", "East to Toto", "Hint", "Ness", "Small Ness", "North", "South", "West", "East" ]) def freeRanges(self): return [(0x21f491, 0x21f580)] # Pointer Table and Data def readFromRom(self, rom): self._ptrTbl.readFromRom(rom, EbModule.toRegAddr(EbModule.readAsmPointer(rom, self._ASMPTR_PTR_TBL))) updateProgress(5) for i in range(self._ptrTbl.height()): loc = EbModule.toRegAddr(self._ptrTbl[i,0].val()) entry = [] while True: x = rom[loc] if x == 0xff: break y = rom[loc+1] icon = rom[loc+2] flag = rom.readMulti(loc+3, 2) entry.append((x, y, icon, flag)) loc += 5 self._entries.append(entry) i += 1 updateProgress(45) def writeToRom(self, rom): self._ptrTbl.clear(6) i = 0 for entry in self._entries: writeLoc = rom.getFreeLoc(len(entry)*5 + 1) self._ptrTbl[i,0].setVal( EbModule.toSnesAddr(writeLoc)) for (x, y, icon, flag) in entry: rom[writeLoc] = x rom[writeLoc+1] = y rom[writeLoc+2] = icon rom.writeMulti(writeLoc+3, flag, 2) writeLoc += 5 rom[writeLoc] = 0xff i += 1 updateProgress(45) EbModule.writeAsmPointer(rom, self._ASMPTR_PTR_TBL, EbModule.toSnesAddr( self._ptrTbl.writeToFree(rom))) updateProgress(5) def readFromProject(self, resourceOpener): self._entries = [None] * 6 with resourceOpener("TownMaps/icon_positions", "yml") as f: data = yaml.load(f, Loader=yaml.CSafeLoader) for name in data: entry = [] for subEntry in data[name]: self._iconField.load(subEntry["Icon"]) entry.append(( subEntry["X"], subEntry["Y"], self._iconField.val(), subEntry["Event Flag"])) self._entryIdField.load(name) self._entries[self._entryIdField.val()] = entry updateProgress(50) def writeToProject(self, resourceOpener): out = dict() i = 0 for entry in self._entries: outEntry = [] for (x, y, icon, flag) in entry: self._iconField.setVal(icon) outEntry.append({ "X": x, "Y": y, "Icon": self._iconField.dump(), "Event Flag": flag }) self._entryIdField.setVal(i) out[self._entryIdField.dump()] = outEntry i += 1 updateProgress(25) with resourceOpener("TownMaps/icon_positions", "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(25) def upgradeProject(self, oldVersion, newVersion, rom, resourceOpenerR, resourceOpenerW): global updateProgress if oldVersion == newVersion: updateProgress(100) return elif oldVersion <= 2: tmp = updateProgress updateProgress = lambda x: None self.readFromRom(rom) self.writeToProject(resourceOpenerW) updateProgress = tmp self.upgradeProject(3, newVersion, rom, resourceOpenerR, resourceOpenerW) else: self.upgradeProject(oldVersion+1, newVersion, rom, resourceOpenerR, resourceOpenerW)
class MapMusicModule(EbModule.EbModule): _ASMPTR = 0x6939 _name = "Map Music" def __init__(self): self._ptrTbl = EbTable(0xCF58EF) self._entries = [] def readFromRom(self, rom): self._ptrTbl.readFromRom(rom, EbModule.toRegAddr(rom.readMulti(self._ASMPTR, 3))) updateProgress(25) for i in range(self._ptrTbl.height()): loc = 0xf0000 | self._ptrTbl[i,0].val() entry = [ ] flag = 1 while flag != 0: flag = rom.readMulti(loc, 2) music = rom[loc+2] entry.append((flag, music)) loc += 4 self._entries.append(entry) updateProgress(25) def writeToRom(self, rom): self._ptrTbl.clear(165) writeLoc = 0xf58ef writeRangeEnd = 0xf61e5 # TODO Can re-use bank space from doors i=0 for entry in self._entries: entryLen = len(entry)*4 if writeLoc+entryLen > writeRangeEnd: raise RuntimeError("Not enough room for map music") self._ptrTbl[i,0].setVal(writeLoc & 0xffff) i += 1 for (flag, music) in entry: rom.writeMulti(writeLoc, flag, 2) rom[writeLoc+2] = music rom[writeLoc+3] = 0 writeLoc += 4 updateProgress(25) rom.writeMulti(self._ASMPTR, EbModule.toSnesAddr(self._ptrTbl.writeToFree(rom)), 3) if writeLoc < writeRangeEnd: rom.addFreeRanges([(writeLoc, writeRangeEnd)]) updateProgress(25) def writeToProject(self, resourceOpener): out = dict() i = 0 for entry in self._entries: outEntry = [] for (flag, music) in entry: outEntry.append({ "Event Flag": flag, "Music": music }) out[i] = outEntry i += 1 updateProgress(25) with resourceOpener("map_music", "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(25) def readFromProject(self, resourceOpener): with resourceOpener("map_music", "yml") as f: input = yaml.load(f, Loader=yaml.CSafeLoader) for i in input: entry = [] for subEntry in input[i]: entry.append((subEntry["Event Flag"], subEntry["Music"])) self._entries.append(entry) updateProgress(50)
class MapEventModule(EbModule.EbModule): _name = "Map Events" _PTR_LOC = 0x70d _PTR_BANK_LOC = 0x704 def __init__(self): self._ptrTbl = EbTable(0xD01598) self._entries = [ ] def freeRanges(self): return [(0x101598, 0x10187f)] def readFromRom(self, rom): self._ptrTbl.readFromRom(rom, EbModule.toRegAddr(rom.readMulti(self._PTR_LOC, 3))) updateProgress(5) bank = (rom[self._PTR_BANK_LOC] - 0xc0) << 16 pct = 45.0/20 for i in range(20): addr = bank | self._ptrTbl[i,0].val() tsetEntry = [] while (rom.readMulti(addr, 2) != 0): flag = rom.readMulti(addr, 2) num = rom.readMulti(addr+2, 2) addr += 4 changes = [] for j in range(num): changes.append((rom.readMulti(addr, 2), rom.readMulti(addr+2, 2))) addr += 4 tsetEntry.append((flag, changes)) self._entries.append(tsetEntry) updateProgress(pct) def writeToProject(self, resourceOpener): out = dict() i = 0 for entry in self._entries: entryOut = [] for (flag, changes) in entry: changeOut = { "Event Flag": flag } changeOut["Changes"] = changes entryOut.append(changeOut) if entryOut == []: out[i] = None else: out[i] = entryOut i += 1 updateProgress(25) with resourceOpener("map_changes", "yml") as f: s = yaml.dump(out, Dumper=yaml.CSafeDumper) s = sub("Event Flag: (\d+)", lambda i: "Event Flag: " + hex(int(i.group(0)[12:])), s) f.write(s) updateProgress(25) def readFromProject(self, resourceOpener): with resourceOpener("map_changes", "yml") as f: input = yaml.load(f, Loader=yaml.CSafeLoader) for mtset in input: entry = [] entryIn = input[mtset] if (entryIn != None): for csetIn in entryIn: entry.append((csetIn["Event Flag"], csetIn["Changes"])) self._entries.append(entry) updateProgress(50.0/20) def writeToRom(self, rom): self._ptrTbl.clear(20) blockSize = 0 for entry in self._entries: for (flag, set) in entry: blockSize += 4 + 4*len(set) blockSize += 2 if blockSize > 0xffff: raise RuntimeError("Too many map changes") loc = rom.getFreeLoc(blockSize) rom[self._PTR_BANK_LOC] = (loc >> 16) + 0xc0 i = 0 for entry in self._entries: self._ptrTbl[i,0].setVal(loc & 0xffff) for (flag, set) in entry: rom.writeMulti(loc, flag, 2) rom.writeMulti(loc+2, len(set), 2) loc += 4 for (before, after) in set: rom.writeMulti(loc, before, 2) rom.writeMulti(loc+2, after, 2) loc += 4 rom[loc] = 0 rom[loc+1] = 0 loc += 2 i += 1 updateProgress(45.0/20) ptrTblLoc = self._ptrTbl.writeToFree(rom) rom.writeMulti(self._PTR_LOC, EbModule.toSnesAddr(ptrTblLoc), 3) updateProgress(5)