def __init__(self, rom: NintendoDSRom): self.rom = rom data = rom.iconBanner self.version = read_u16(data, 0x0) assert len(data) == ICON_BANNER_SIZE assert self.version == 1 # EoS should always use version 1 self.checksum = read_u16(data, 0x2) self.icon = Icon(read_bytes(data, 0x20, 0x200), read_bytes(data, 0x220, 0x20)) self.title_japanese = read_bytes( data, 0x240, 0x100).decode('UTF-16LE').rstrip('\x00') self.title_english = read_bytes( data, 0x340, 0x100).decode('UTF-16LE').rstrip('\x00') self.title_french = read_bytes(data, 0x440, 0x100).decode('UTF-16LE').rstrip('\x00') self.title_german = read_bytes(data, 0x540, 0x100).decode('UTF-16LE').rstrip('\x00') self.title_italian = read_bytes( data, 0x640, 0x100).decode('UTF-16LE').rstrip('\x00') self.title_spanish = read_bytes( data, 0x740, 0x100).decode('UTF-16LE').rstrip('\x00')
def _write_pair24(self, data: bytes): """Writes 4 bytes of 2 16 bit LE integers in pair24 encoding.""" assert len(data) == 4 int1 = read_u16(data, 0) int2 = read_u16(data, 2) pair24 = ((int1 & 0xff) << 16) + ((int2 & 0xf) << 12) + (int1 & 0xf00) + ((int2 & 0xff0) >> 4) if DEBUG: print(f"W {int1:02x} and {int2:02x} as {pair24:06x}") self.compressed_data[self.bytes_written:self.bytes_written+3] = pair24.to_bytes(3, 'big') self.bytes_written += 3
def list_from_mappa(cls, read: 'MappaBinReadContainer', pointer: int) -> List['MappaMonster']: monsters = [] while not cls._is_end_of_entries(read.data, pointer): monsters.append(MappaMonster( u8(read_u16(read.data, pointer + 0) // LEVEL_MULTIPLIER), read_u16(read.data, pointer + 2), read_u16(read.data, pointer + 4), read_u16(read.data, pointer + 6), )) pointer += 8 return monsters
def get_player_md_ids(overlay13: bytes, config: Pmd2Data) -> List[u16]: """Returns the monster.md indices of the player starter choices (total index, with gender form!)""" block = config.binaries['overlay/overlay_0013.bin'].symbols['StartersHeroIds'] ids = [] for i in range(block.begin, block.end, 2): ids.append(read_u16(overlay13, i)) return ids
def __init__(self, bitmap: bytes, palette: bytes): self.bitmap = bitmap self._palette = [] for i in range(0, len(palette) // 2): bgr = read_u16(palette, i * 2) self._palette.append((bgr & 0x001F) * 0x08) self._palette.append(((bgr & 0x03E0) >> 5) * 0x08) self._palette.append(((bgr & 0x7C00) >> 10) * 0x08)
def __init__(self, data: bytes, header_start: int): if not isinstance(data, memoryview): data = memoryview(data) self.list: List[Pmd2ScriptLevel] = [] # pointer_start = read_uintle(data, header_start, 4) # number_entries = read_uintle(data, header_start + 4, 4) for i in range(0, len(data) - header_start): start = header_start + (i * LEN_LEVEL_ENTRY) if data[start:start + 12] == b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa': break self.list.append(Pmd2ScriptLevel( id=i, mapty=read_u16(data, start + 0), nameid=read_u16(data, start + 2), mapid=read_u16(data, start + 4), weather=read_i16(data, start + 6), name=self._read_string(data, read_u32(data, start + 8)) ))
def test_container(self, _, in_bytes): model = self.handler().compress(in_bytes) model_bytes = model.to_bytes() self.assertEqual(len(model_bytes), model.cont_size(model_bytes)) self.assertEqual(read_u16(model_bytes, 5), len(model_bytes)) self.assertEqual(read_u32(model_bytes, 0x10), len(in_bytes)) self.assertTrue(model_bytes.startswith(b'PKDPX')) self.assertEqual( model_bytes, self.handler().serialize(self.handler().deserialize(model_bytes))) self.assertEqual(in_bytes, model.decompress())
def corrupt341(): """Corrupt 341: Dungeon tiles Beach cave 2? -- No? Tiles -> Chunk mappings or similar?""" img341 = dungeon_bin[341].decompress() img341new = bytearray(img341) # Decode XOR #XOR_ROW_LEN = 7200#18 * 7 #rows_decoded = [] #row_before = bytes(XOR_ROW_LEN) #for chunk in iter_bytes(img341, XOR_ROW_LEN): # xored = bytearray(a ^ b for (a, b) in zip(chunk, row_before)) # row_before = xored # rows_decoded.append(xored) dummy_map = [ TilemapEntry(10, False, False, 0), TilemapEntry(10, True, False, 0), TilemapEntry(10, False, True, 0), TilemapEntry(5, False, False, 0), TilemapEntry(5, True, False, 0), TilemapEntry(5, False, True, 0), TilemapEntry(10, False, False, 6), TilemapEntry(10, True, False, 6), TilemapEntry(10, False, True, 6) ] for j in range(1, 300): for i, m in enumerate(dummy_map): write_u16(img341new, m.to_int(), (j * 18) + 2 * i) all_tilemaps = [] for bytes2 in iter_bytes(img341new, 2): all_tilemaps.append(TilemapEntry.from_int(read_u16(bytes2, 0))) # Encode XOR #rows_encoded = [] #row_before = bytes(XOR_ROW_LEN) #for row in rows_decoded: # xored = bytes(a ^ b for (a, b) in zip(row, row_before)) # row_before = row # rows_encoded.append(xored) #img341new = bytes(itertools.chain.from_iterable(rows_encoded)) #assert img341 == img341new with open('/tmp/corrupt.bin', 'wb') as f: f.write(img341new) dungeon_bin[341] = FileType.COMMON_AT.compress(img341new)
def get_stolen_spawn_rate(ov10: bytes, config: Pmd2Data) -> u16: block = config.binaries['overlay/overlay_0010.bin'].symbols[ 'SpawnDelayStealing'] return read_u16(ov10, block.begin)
def _is_end_of_entries(cls, data: bytes, pointer): return read_u16(data, pointer + 6) == 0
def __init__(self, data: bytes = None): if data: self.length_decompressed = read_u16(data, 6) self.compressed_data = data[8:]
def get_oran_berry_hp(ov10: bytes, config: Pmd2Data) -> u16: block = config.binaries['overlay/overlay_0010.bin'].symbols[ 'ORAN_BERRY_HP_RESTORATION'] return read_u16(ov10, block.begin)
def get_life_seed_hp(ov10: bytes, config: Pmd2Data) -> u16: block = config.binaries['overlay/overlay_0010.bin'].symbols[ 'LIFE_SEED_HP_BOOST'] return read_u16(ov10, block.begin)
def from_mappa(cls, read: 'MappaBinReadContainer', pointer: int) -> 'MappaTrapList': weights = [] for i in range(pointer, pointer + 50, 2): weights.append(read_u16(read.data, i)) return MappaTrapList(weights)