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 readFromProject(self, resourceOpener): # Clear the labels dict EbModule.labelsDict.clear() # Read the summary file sumFile = resourceOpener('ccscript/summary', 'txt') summary = sumFile.readlines() sumFile.close() # Only do anything if the summary file is not empty if len(summary) > 0: self._usedRange = (EbModule.toRegAddr(int(summary[7][30:36], 16)), EbModule.toRegAddr(int(summary[8][30:36], 16))) modName = None inModuleSection = False # False = before section, True = in section for line in summary: line = line.rstrip() if inModuleSection: if line.startswith('-'): inModuleSection = False else: labelKey = modName + "." + line.split(' ',1)[0] labelVal = int(line[-6:],16) EbModule.labelsDict[labelKey] = labelVal elif line.startswith("-") and modName != None: inModuleSection = True elif line.startswith("Labels in module "): modName = line[17:] updateProgress(50)
def readGasFromRom(self, rom): with EbCompressedData() as cb: cb.readFromRom(rom, EbModule.toRegAddr( EbModule.readAsmPointer(rom, self._ASMPTR_GAS_GFX))) self._gas_gfx.readFromBlock(cb) with EbCompressedData() as cb: cb.readFromRom(rom, EbModule.toRegAddr( EbModule.readAsmPointer(rom, self._ASMPTR_GAS_ARR))) self._gas_arr.readFromBlock(cb) with EbCompressedData() as cb: cb.readFromRom(rom, EbModule.toRegAddr( EbModule.readAsmPointer(rom, self._ASMPTR_GAS_PAL1))) self._gas_pal1.readFromBlock(cb) with EbCompressedData() as cb: cb.readFromRom(rom, EbModule.toRegAddr( EbModule.readAsmPointer(rom, self._ASMPTR_GAS_PAL2))) self._gas_pal2.readFromBlock(cb) with EbCompressedData() as cb: cb.readFromRom(rom, EbModule.toRegAddr( EbModule.readAsmPointer(rom, self._ASMPTR_GAS_PAL3))) self._gas_pal3.readFromBlock(cb)
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 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)
def writeToBlock(self, block, loc=0): for t in self._tiles: if self._bpp == 2: loc += EbModule.write2BPPArea( t, block._data, loc, 0, 0) elif self._bpp == 4: loc += EbModule.write4BPPArea( t, block._data, loc, 0, 0)
def readCreditsFontFromRom(self, rom): self._cpal.readFromBlock(rom, loc=self._ADDR_CREDITS_PAL) with EbCompressedData() as cb: cb.readFromRom(rom, EbModule.toRegAddr( EbModule.readAsmPointer( rom, self._ASMPTR_CREDITS_GFX))) self._cfont.readFromBlock(cb)
def setFromImage(self, img, x, y, pals, palNum, indexed=False): # Check for normal tile newTile = None imgData = img.load() if indexed: newTile = [ array('B', [ imgData[i,j] for j in xrange(y, self._tileSize + y) ]) for i in xrange(x, self._tileSize + x) ] else: newTile = [ array('B', [ pals.getColorFromRGB(palNum,imgData[i,j]) for j in xrange(y, self._tileSize + y) ]) for i in xrange(x, self._tileSize + x) ] # Note: newTile is an array of columns # Check for non-flipped tile try: tIndex = self._usedDict[EbModule.hashArea(newTile)] return (False, False, tIndex) except KeyError: pass # Check for only horizontally flipped tile try: tIndex = self._usedDict[EbModule.hashArea(reversed(newTile))] return (False, True, tIndex) except KeyError: pass # Check for vertically and horizontally flipped tile for col in newTile: col.reverse() try: tIndex = self._usedDict[EbModule.hashArea(reversed(newTile))] return (True, True, tIndex) except KeyError: pass # Check for only vertically flipped tile tH = EbModule.hashArea(newTile) try: tIndex = self._usedDict[tH] return (True, False, tIndex) except KeyError: pass # We need to add a new tile if self._usedTiles >= self._numTiles: # TODO ERROR: Not enough room for a new tile return (False, False, 0) # Remember, newTile is still vflipped self._tiles.append(newTile) self._usedDict[tH] = self._usedTiles self._usedTiles += 1 return (True, False, self._usedTiles-1)
def readFromBlock(self, block, width, height, loc=0): self._w = width self._h = height self._data = map(lambda x: array('B', [0] * self._h), range(self._w)) for i in range(self._h / 8): for j in range(self._w / 8): EbModule.read4BPPArea(self._data, block, loc, j*8, i*8) loc += 32
def writeToRom(self, rom): for (cat, items) in self.ENTRY_LOCS: catDict = self._data[cat] for (desc, loc, size) in items: EbModule.writeStandardText(rom, loc, catDict[desc], size) if (cat == "Status Window") and (len(catDict[desc]) < size): rom.write(loc+len(catDict[desc]), [00] * (size-len(catDict[desc]))) updateProgress(self._pct)
def writeToBlock(self, block, loc=0): offset = loc for q in range(0, self._height/32): for r in range(0, self._width/32): for a in range(0, 4): for j in range(0,4): EbModule.write4BPPArea( self._sprite, block, offset, (j + r * 4) * 8, (a + q * 4) * 8) offset += 32
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): for f in self._fonts: f.writeToRom(rom) updateProgress(self._pct) self._cpal.writeToBlock(rom, loc=self._ADDR_CREDITS_PAL) with EbCompressedData(self._cfont.sizeBlock()) as cb: self._cfont.writeToBlock(cb) EbModule.writeAsmPointer(rom, self._ASMPTR_CREDITS_GFX, EbModule.toSnesAddr(cb.writeToFree(rom))) updateProgress(self._pct)
def readTownMapIconsFromRom(self, rom): self._townmap_icons_pal.readFromBlock(rom, loc=EbModule.toRegAddr( EbModule.readAsmPointer(rom, self._ASMPTR_TOWN_MAP_ICON_PAL))) with EbCompressedData() as cb: cb.readFromRom(rom, EbModule.toRegAddr( EbModule.readAsmPointer(rom, self._ASMPTR_TOWN_MAP_ICON_GFX))) self._townmap_icons.readFromBlock(cb)
def writeToBlock(self, block, addr): i=0 for subp in self.subpals: EbModule.writePalette(block, addr + i, subp) i += 32 #block.writeMulti(addr, self.flag, 2) #block.writeMulti(addr+0x20, self.flagPalPtr, 2) block[addr] = self.flag & 0xff block[addr+1] = self.flag >> 8 block[addr+0x20] = self.flagPalPtr & 0xff block[addr+0x21] = self.flagPalPtr >> 8 block[addr+0x40] = self.spritePalNum block[addr+0x60] = self.flashEffect return 0xc0
def readFromBlock(self, block, width, height, loc=0): self._width = width self._height = height self._sprite = map(lambda x: array('B', [0] * height), range(0, width)) offset = loc for q in range(0, height/32): for r in range(0, width/32): for a in range(0, 4): for j in range(0, 4): EbModule.read4BPPArea(self._sprite, block, offset, (j + r * 4) * 8, (a + q * 4) * 8) offset += 32 self._spriteHash = EbModule.hashArea(self._sprite)
def writeToRom(self, rom): addr = self._gfxAddr for char in self._chars: for j in range(0, self._charW, 8): addr += EbModule.write1BPPArea(char, rom, addr, self._charH, j, 0) rom.write(self._widthsAddr, self._charWidths)
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)
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 readFromRom(self, rom): with EbCompressedData() as block: block.readFromRom(rom, EbModule.toRegAddr( rom.readMulti(self._ptrLoc, 4))) self._arr.readFromBlock(block, 64) self._pals.readFromBlock(block, 0) self._gfx.readFromBlock(block, 2048+64)
def readFromRom(self, rom): for (cat, items) in self.ENTRY_LOCS: catDict = {} for (desc, loc, size) in items: catDict[desc] = EbModule.readStandardText(rom, loc, size) self._data[cat] = catDict updateProgress(self._pct)
def writeToRom(self, rom): if self._data["Enable Skip"]: rom[0x1faae] = 0x5c loc = rom.getFreeLoc(10 + 4*5*5 + 3*6*5) rom.writeMulti(0x1faaf, EbModule.toSnesAddr(loc), 3) rom.write(loc, [0x48, 0x08, 0xe2, 0x20]) loc += 4 loc = self.writeLoaderAsm(rom, loc, self._data["Name1"], 5, 0xce, 0x99) loc = self.writeLoaderAsm(rom, loc, self._data["Name2"], 5, 0x2d, 0x9a) loc = self.writeLoaderAsm(rom, loc, self._data["Name3"], 5, 0x8c, 0x9a) loc = self.writeLoaderAsm(rom, loc, self._data["Name4"], 5, 0xeb, 0x9a) loc = self.writeLoaderAsm(rom, loc, self._data["Pet"], 6, 0x19, 0x98) loc = self.writeLoaderAsm(rom, loc, self._data["Food"], 6, 0x1f, 0x98) loc = self.writeLoaderAsm(rom, loc, self._data["Thing"], 6, 0x29, 0x98) if self._data["Enable Summary"]: rom.write(loc, [0x28, 0x68, 0x5c, 0xc0, 0xfa, 0xc1]) else: rom.write(loc, [0x28, 0x68, 0x5c, 0x05, 0xfd, 0xc1]) updateProgress(50)
def writeSpritesToFree(self, rom): if self._numSprites == 0: self._spritePtrs = [] return spritePtrs = [ ] # Make a set of unique sprites uniqueSprites = [ ] for spf in self._sprites: sp = spf[0] try: spritePtrs.append((uniqueSprites.index(sp), False)) except ValueError: # Regular sprite not in uniques sp.hflip() try: spritePtrs.append((uniqueSprites.index(sp), True)) except ValueError: # Flipped sprite not in uniques uniqueSprites.append(sp) spritePtrs.append((uniqueSprites.index(sp), True)) # Find a free block loc = rom.getFreeLoc(sum(map(lambda x: x.blockSize(), uniqueSprites)),15) self._bank = EbModule.toSnesAddr(loc) >> 16 locStart = loc & 0xffff # Write each sprite uniqueSpriteAddrs = [ ] spBlockSize = uniqueSprites[0].blockSize() for uS in uniqueSprites: uS.writeToBlock(rom, loc) loc += spBlockSize # Output a list of pointers self._spritePtrs = map(lambda (n,f): (locStart + n*spBlockSize) | f, spritePtrs) for i in range(len(spritePtrs)): self._spritePtrs[i] |= (self._sprites[i][1]<<1)
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 writeToRom(self, rom): with EbCompressedData(self._gfx.sizeBlock()) as gb: self._gfx.writeToBlock(gb) EbModule.writeAsmPointer(rom, self._gfxPtrLoc, EbModule.toSnesAddr(gb.writeToFree(rom))) with EbCompressedData(self._arr.sizeBlock()) as ab: self._arr.writeToBlock(ab) EbModule.writeAsmPointer(rom, self._arrPtrLoc, EbModule.toSnesAddr(ab.writeToFree(rom))) with EbCompressedData(self._pals.sizeBlock()) as pb: self._pals.writeToBlock(pb) EbModule.writeAsmPointer(rom, self._palPtrLoc, EbModule.toSnesAddr(pb.writeToFree(rom)))
def readFromBlock(self, block, loc=0): off = loc self._tiles = [] for i in xrange(self._numTiles): try: tile = [array('B', [0]*self._tileSize) for i in xrange(self._tileSize)] if self._bpp == 2: off += EbModule.read2BPPArea( tile, block._data, off, 0, 0) elif self._bpp == 4: off += EbModule.read4BPPArea( tile, block._data, off, 0, 0) except IndexError: pass # Load an empty tile if it's out of range of the data self._tiles.append(tile) self._usedTiles = self._numTiles
def writeToRom(self, rom): # Arrangement space is 2048 bytes long since it's 32x32x2 in VRAM with EbCompressedData(self._pals.sizeBlock() + 2048 + self._gfx.sizeBlock()) as block: self._pals.writeToBlock(block, 0) self._arr.writeToBlock(block, 64) self._gfx.writeToBlock(block, 2048+64) newAddr = block.writeToFree(rom) rom.writeMulti(self._ptrLoc, EbModule.toSnesAddr(newAddr), 4)
def writeToRom(self, rom): for (t, a, asmPtrs, regPtrs, regPtrsOff) in self._tables: try: addr = EbModule.toSnesAddr(t.writeToFree(rom)) except Exception as inst: print t._name raise inst for asmPtr in asmPtrs: EbModule.writeAsmPointer(rom, asmPtr, addr) for regPtr in regPtrs: rom.writeMulti(regPtr, addr, 3) for (ptr, off) in regPtrsOff: rom.writeMulti(ptr, addr + off, 3) # Hardcoded number of entries in PSI Ability Table # if t._addr == 0xd58a50: # rom.writeMulti(0x1c843, t.height(), 2) updateProgress(self._pct)
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 fromImage(self, img): self._width, self._height = img.size self._sprite = [] imgData = img.load() for x in range(0, self._width): col = array('B', [0]*self._height) for y in range(0, self._height): col[y] = imgData[x,y] self._sprite.append(col) self._spriteHash = EbModule.hashArea(self._sprite)