class Door: # Types: Switch, Rope/Ladder, Door, Escalator, Stairway, Object, Person _TYPE_NAMES = ["switch", "rope/ladder", "door", "escalator", "stairway", "object", "person"] def readFromRom(self, rom, addr): self._y = rom[addr] self._x = rom[addr+1] self._type = rom[addr+2] ptr = rom.readMulti(addr+3, 2) if self._type == 1: # Rope/Ladder self._isRope = (ptr == 0x8000) elif (self._type == 3) or (self._type == 4): # Escalator and Stairs if ptr == 0x8000: stairDir = 4 else: stairDir = ptr / 0x100 self._stairDir = ValuedIntTableEntry(None, None, ["NW", "NE", "SW", "SE", "Nowhere"]) self._stairDir.setVal(stairDir) elif self._type == 2: # Door ptr |= 0xF0000 #self._destTextPtr = rom.readMulti(ptr, 4) self._destTextPtr = PointerTableEntry(None, 4) self._destTextPtr.setVal(rom.readMulti(ptr, 4)) if ((self._destTextPtr.val() != 0) and ((self._destTextPtr.val() < 0xc00000) or (self._destTextPtr.val() > 0xffffff))): raise ValueError("Invalid Door") self._destFlag = rom.readMulti(ptr+4, 2) self._destY = rom[ptr+6] self._destY |= (rom[ptr+7] & 0x3f) << 8 #self._destDir = (rom[ptr+7] & 0xc0) >> 6 self._destDir = ValuedIntTableEntry(None, None, ["Down", "Up", "Right", "Left"]) self._destDir.setVal((rom[ptr+7] & 0xc0) >> 6) self._destX = rom.readMulti(ptr+8, 2) self._destStyle = rom[ptr+10] elif self._type == 0: # Switch ptr |= 0xF0000 self._destFlag = rom.readMulti(ptr, 2) #self._destTextPtr = rom.readMulti(ptr+2, 4) self._destTextPtr = PointerTableEntry(None, 4) self._destTextPtr.setVal(rom.readMulti(ptr+2, 4)) if ((self._destTextPtr.val() != 0) and ((self._destTextPtr.val() < 0xc00000) or (self._destTextPtr.val() > 0xffffff))): raise ValueError("Invalid Switch") elif (self._type == 5) or (self._type == 6): # Object and Person ptr |= 0xF0000 #self._destTextPtr = rom.readmulti(ptr, 4) self._destTextPtr = PointerTableEntry(None, 4) self._destTextPtr.setVal(rom.readMulti(ptr, 4)) else: raise ValueError("Unknown type " + str(self._type)) def getTypeAsString(self): if self._type == 1: if self._isRope: return "rope" else: return "ladder" else: return Door._TYPE_NAMES[self._type] def setTypeFromString(self, str): str = str.lower() if str == "rope": self._type = 1 self._isRope = True elif str == "ladder": self._type = 1 self._isRope = False else: self._type = Door._TYPE_NAMES.index(str) def dump(self): out = { "X": self._x, "Y": self._y, "Type": self.getTypeAsString() } if (self._type == 3) or (self._type == 4): # Stairs/Escalator out["Direction"] = self._stairDir.dump() elif self._type == 2: # Door out["Text Pointer"] = self._destTextPtr.dump() out["Event Flag"] = self._destFlag out["Destination X"] = self._destX out["Destination Y"] = self._destY out["Direction"] = self._destDir.dump() out["Style"] = self._destStyle elif self._type == 0: # Switch out["Text Pointer"] = self._destTextPtr.dump() out["Event Flag"] = self._destFlag elif (self._type == 5) or (self._type == 6): out["Text Pointer"] = self._destTextPtr.dump() return out def load(self, input): self._x = input["X"] self._y = input["Y"] self.setTypeFromString(input["Type"]) if (self._type == 3) or (self._type == 4): # Stairs/Escalator self._stairDir = ValuedIntTableEntry(None, None, ["NW", "NE", "SW", "SE", "Nowhere"]) self._stairDir.load(input["Direction"]) elif self._type == 2: # Door self._destTextPtr = PointerTableEntry(None, 4) self._destTextPtr.load(input["Text Pointer"]) self._destFlag = input["Event Flag"] self._destX = input["Destination X"] self._destY = input["Destination Y"] self._destDir = ValuedIntTableEntry(None, None, ["Down", "Up", "Right", "Left"]) self._destDir.load(input["Direction"]) self._destStyle = input["Style"] elif self._type == 0: # Switch self._destTextPtr = PointerTableEntry(None, 4) self._destTextPtr.load(input["Text Pointer"]) self._destFlag = input["Event Flag"] elif (self._type == 5) or (self._type == 6): self._destTextPtr = PointerTableEntry(None, 4) self._destTextPtr.load(input["Text Pointer"]) def writeToRom(self, rom, addr, destWriteLoc, destRangeEnd, destLocs): rom[addr] = self._y rom[addr+1] = self._x rom[addr+2] = self._type if self._type == 1: # Rope/Ladder rom[addr+3] = 0 rom[addr+4] = (0x80 if self._isRope else 0) return 0 elif (self._type == 3) or (self._type == 4): # Escalator and Stairs rom[addr+3] = 0 rom[addr+4] = (0x80 if (self._stairDir.val() == 4) else self._stairDir.val()) return 0 elif self._type == 2: # Door with DataBlock(11) as destBlock: # Write data to block destTextPtr = self._destTextPtr.val() destBlock[0] = destTextPtr & 0xff destBlock[1] = (destTextPtr>>8) & 0xff destBlock[2] = (destTextPtr>>16) & 0xff destBlock[3] = (destTextPtr>>24) & 0xff destBlock[4] = self._destFlag & 0xff destBlock[5] = (self._destFlag >> 8) & 0xff destBlock[6] = self._destY & 0xff destBlock[7] = (self._destY >> 8) | (self._destDir.val() << 6) destBlock[8] = self._destX & 0xff destBlock[9] = self._destX >> 8 destBlock[10] = self._destStyle # Check for any pre-existing matching destinations destHash = destBlock.hash() try: destAddr = destLocs[destHash] rom[addr+3] = destAddr & 0xff rom[addr+4] = destAddr >> 8 return 0 except KeyError: # Need to write a new destination if (destWriteLoc + 11) > destRangeEnd: # TODO Error, not enough space raise RunetimeError("Not enough door destination space") destBlock.writeToRom(rom, destWriteLoc) destLocs[destHash] = destWriteLoc & 0xffff rom[addr+3] = destWriteLoc & 0xff rom[addr+4] = (destWriteLoc >> 8) & 0xff return 11 elif self._type == 0: # Switch with DataBlock(6) as destBlock: # Write the data to block destBlock[0] = self._destFlag & 0xff destBlock[1] = self._destFlag >> 8 destTextPtr = self._destTextPtr.val() destBlock[2] = destTextPtr & 0xff destBlock[3] = (destTextPtr>>8) & 0xff destBlock[4] = (destTextPtr>>16) & 0xff destBlock[5] = (destTextPtr>>24) & 0xff # Check for any pre-existing matching destinations destHash = destBlock.hash() try: destAddr = destLocs[destHash] rom[addr+3] = destAddr & 0xff rom[addr+4] = destAddr >> 8 return 0 except KeyError: # Need to write a new destination if (destWriteLoc + 6) > destRangeEnd: # TODO Error, not enough space raise RunetimeError("Not enough door destination space") destBlock.writeToRom(rom, destWriteLoc) destLocs[destHash] = destWriteLoc & 0xffff rom[addr+3] = destWriteLoc & 0xff rom[addr+4] = (destWriteLoc >> 8) & 0xff return 6 elif (self._type == 5) or (self._type == 6): # Switch with DataBlock(4) as destBlock: # Write the data to block destTextPtr = self._destTextPtr.val() destBlock[0] = destTextPtr & 0xff destBlock[1] = (destTextPtr>>8) & 0xff destBlock[2] = (destTextPtr>>16) & 0xff destBlock[3] = (destTextPtr>>24) & 0xff # Check for any pre-existing matching destinations destHash = destBlock.hash() try: destAddr = destLocs[destHash] rom[addr+3] = destAddr & 0xff rom[addr+4] = destAddr >> 8 return 0 except KeyError: # Need to write a new destination if (destWriteLoc + 4) > destRangeEnd: # TODO Error, not enough space raise RunetimeError("Not enough door destination space") destBlock.writeToRom(rom, destWriteLoc) destLocs[destHash] = destWriteLoc & 0xffff rom[addr+3] = destWriteLoc & 0xff rom[addr+4] = (destWriteLoc >> 8) & 0xff return 4
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 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)
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)