Пример #1
0
    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)
Пример #2
0
 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)}")
Пример #3
0
    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])
Пример #4
0
    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])
Пример #5
0
 def encode_text(text: str) -> bytearray:
     data = bytearray()
     for char in text:
         data.append(ord(char))
     return TextBlock._encode_text(InputStream(data))
Пример #6
0
 def __setitem__(self, index, value):
     self.strings[index] = TextBlock._encode_text(
         InputStream(value, check_alignment=False))
Пример #7
0
 def __getitem__(self, index):
     return TextBlock._as_ascii(
         InputStream(self.strings[index], check_alignment=False))