def build(self): stream = OutputStream() written_length = 0 if len(self._magic) > 0: for magic_id in self._magic: stream.put_u8(magic_id) written_length += 1 if len(self._armor) > 0: stream.put_u8(0xfc) for item_id in self._armor: stream.put_u8(item_id) written_length += 1 if len(self._weapons) > 0: stream.put_u8(0xfd) for item_id in self._weapons: stream.put_u8(item_id) written_length += 1 if len(self._items) > 0: stream.put_u8(0xfe) for item_id in self._items: stream.put_u8(item_id) written_length += 1 if written_length > 0xf: raise RuntimeError( f"Error: Too many items in shop: {written_length}") return ShopInventory(InputStream(stream.get_buffer()), written_length)
def open_bytestream(self, offset: int, size: int = -1, check_alignment: bool = True) -> InputStream: """ Opens a InputStream to read over part of the ROM. :param offset: Offset of the start of the InputStream :param size: Number of bytes to include :param check_alignment: Whether non-byte reads should checked that they are word aligned :return: The InputStream """ if 0 <= offset < len(self.rom_data): data = self.rom_data[offset:] if size < 0 else self.rom_data[ offset:(offset + size)] return InputStream(data, check_alignment=check_alignment) raise RuntimeError( f"Index out of bounds {hex(offset)} vs {len(self.rom_data)}")
def get_event(self, offset: int) -> InputStream: """ Creates an InputStream from a simple event. Note: This does *not* follow jumps. Many events only include one "end of event" command at the end, and this method will work to read them. Some SoC events, however, include multiple end of event commands, and this method would only read to the first one. :param offset: Offset of the start of the event. :return: InputStream representing the event. """ end_offset = offset last_cmd = -1 while last_cmd != 0: cmd_len = self.rom_data[end_offset + 1] last_cmd = self.rom_data[end_offset] end_offset += cmd_len return InputStream(self.rom_data[offset:end_offset])
def get_stream(self, offset: int, end_marker: bytearray) -> InputStream: """ Gets an InputStream from the ROM. This should primarily be used where the data is not null terminated (use `get_string` then), and is of variable length. Many events could be read using this method and a bytearray of [0x0, 0x4, 0xff, 0xff] for example, but `get_event` should be used in that case. :param offset: The offset of the start of the stream. :param end_marker: The end marker. :return: InputStream representing the data. """ end_offset = offset markers_found = 0 while markers_found < len(end_marker): if self.rom_data[end_offset] == end_marker[markers_found]: markers_found += 1 else: markers_found = 0 end_offset += 1 return InputStream(self.rom_data[offset:end_offset])
def encode_text(text: str) -> bytearray: data = bytearray() for char in text: data.append(ord(char)) return TextBlock._encode_text(InputStream(data))
def __setitem__(self, index, value): self.strings[index] = TextBlock._encode_text( InputStream(value, check_alignment=False))
def __getitem__(self, index): return TextBlock._as_ascii( InputStream(self.strings[index], check_alignment=False))