Exemplo n.º 1
0
    def __init__(self, stream: InputStream):
        self.contents = stream.get_u8()
        self.shop_graphic = (self.contents >> 4) & 0x0f
        self.shop_data_length = self.contents & 0x0f

        self.unused = []
        for unused in range(3):
            self.unused.append(stream.get_u8())
        self.pointer = stream.get_u32()
Exemplo n.º 2
0
    def __init__(self, stream: InputStream = None):
        if stream is None:
            self.enemy_id = 0
            self.min_count = 0
            self.max_count = 0
            self.unused = 0

        else:
            self.enemy_id = stream.get_u8()
            self.min_count = stream.get_u8()
            self.max_count = stream.get_u8()
            self.unused = stream.get_u8()
Exemplo n.º 3
0
    def __init__(self, stream: InputStream = None):
        if stream is None:
            self.identifier = 0
            self.event = 0
            self.x_pos = 0
            self.y_pos = 0

        else:
            self.identifier = stream.get_u16()
            self.event = stream.get_u16()
            self.x_pos = stream.get_u16()
            self.y_pos = stream.get_u16()
Exemplo n.º 4
0
    def __init__(self, stream: InputStream = None):
        if stream is None:
            self.config = 0
            self.unrunnable = 0
            self.surprise_chance = 0
            self.groups = []

        else:
            self.config = stream.get_u8()
            self.unrunnable = stream.get_u8()
            self.surprise_chance = stream.get_u16()
            self.groups = []
            for index in range(4):
                self.groups.append(EncounterGroup(stream))
Exemplo n.º 5
0
    def __init__(self, stream: InputStream = None):
        if stream is None:
            self.identifier = 0
            self.low_x = 0
            self.low_y = 0
            self.high_x = 0
            self.high_y = 0

        else:
            self.identifier = stream.get_u16()
            self.low_x = stream.get_u16()
            self.low_y = stream.get_u16()
            self.high_x = stream.get_u16()
            self.high_y = stream.get_u16()
Exemplo n.º 6
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)
Exemplo n.º 7
0
    def _as_ascii(stream: InputStream, symbolic_names: bool = False):
        working = ""
        while not stream.is_eos():
            char_code = stream.get_u8()
            if char_code > 0x80:
                char_code = (char_code << 8) | stream.get_u8()
            elif char_code == 0x25:
                char_code = (char_code << 8) | stream.get_u8()
                next_char = stream.get_u8()

                if char_code == 0x2532 and next_char == 0x64:
                    char_code = 0x253264
                else:
                    stream.unget_u8()
            elif char_code in TextBlock.TEXT_TABLE:
                char_code = char_code
            else:
                print(f"Unknown code encountered in string: {hex(char_code)}")

            to_append = TextBlock.TEXT_TABLE[
                char_code] if char_code in TextBlock.TEXT_TABLE else None
            if not symbolic_names:
                if to_append is None or (len(to_append) > 1
                                         and not to_append.startswith("\\")):
                    working += TextBlock._escape(char_code)
                else:
                    working += to_append
            else:
                if to_append is not None:
                    working += to_append
                else:
                    working += TextBlock._escape(char_code)

        return working
Exemplo n.º 8
0
    def __init__(self, map_id: int, stream: InputStream):
        self.header = None
        self.tiles = []
        self.npcs = []
        self.chests = []
        self.sprites = []
        self.shops = []
        self.dummy_chests = []

        data_type = stream.peek_u16()
        while data_type != 0xffff:
            if data_type == 0x0:

                if self.header is not None:
                    raise RuntimeError(
                        f"Warning: Map {hex(map_id)} has more than one header?"
                    )
                self.header = MapHeader(stream)
            elif data_type == 0x1:
                self.tiles.append(Tile(stream))
            elif data_type == 0x2:
                self.npcs.append(Npc(stream))
            elif data_type == 0x3:
                self.chests.append(Chest(stream))
            elif data_type == 0x4:
                self.sprites.append(Sprite(stream))
            elif data_type == 0x5:
                self.shops.append(Shop(stream))
            else:
                raise RuntimeError(f"Unknown type: {data_type}")

            data_type = stream.peek_u16()

        # Some treasure chests are basically placeholders for events. We want to
        # make a note of these chest IDs.
        if len(self.chests) > 0 and len(self.sprites) > 0:
            for index, chest in enumerate(self.chests):
                for sprite in self.sprites:
                    if chest.x_pos == sprite.x_pos and chest.y_pos == sprite.y_pos:
                        self.dummy_chests.append(chest.chest_id)
                        break
Exemplo n.º 9
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)}")
Exemplo n.º 10
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])
Exemplo n.º 11
0
    def __init__(self, stream: InputStream, length: int):
        self.magic = []
        self.armor = []
        self.weapons = []
        self.items = []

        # There's no byte code for magic, so start there and change based on the data
        active = self.magic

        read_length = 0
        while read_length < length:
            data = stream.get_u8()
            if data == 0xfc:
                active = self.armor
            elif data == 0xfd:
                active = self.weapons
            elif data == 0xfe:
                active = self.items
            else:
                active.append(data)
                read_length += 1
Exemplo n.º 12
0
    def __init__(self, stream: InputStream = None):
        if stream is None:
            self.identifier = 0
            self.event = 0
            self.x_pos = 0
            self.y_pos = 0
            self.sprite_id = 0
            self.move_speed = 0
            self.facing = 0
            self.in_room = 0

        else:
            self.identifier = stream.get_u16()
            self.event = stream.get_u16()
            self.x_pos = stream.get_u16()
            self.y_pos = stream.get_u16()
            self.sprite_id = stream.get_u16()
            self.move_speed = stream.get_u16()
            self.facing = stream.get_u16()
            self.in_room = stream.get_u16()
Exemplo n.º 13
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])
Exemplo n.º 14
0
 def read(stream: InputStream):
     chest_data = stream.get_u32()
     if chest_data & 0x80000000 == 0:
         return MoneyChest(chest_data)
     else:
         return ItemChest(chest_data)
Exemplo n.º 15
0
 def __getitem__(self, index):
     return TextBlock._as_ascii(
         InputStream(self.strings[index], check_alignment=False))
Exemplo n.º 16
0
 def __setitem__(self, index, value):
     self.strings[index] = TextBlock._encode_text(
         InputStream(value, check_alignment=False))
Exemplo n.º 17
0
 def encode_text(text: str) -> bytearray:
     data = bytearray()
     for char in text:
         data.append(ord(char))
     return TextBlock._encode_text(InputStream(data))
Exemplo n.º 18
0
    def __init__(self, stream: InputStream = None):
        if stream is None:
            self.base_hp = 0
            self.base_mp = 0
            self.starting_spell_level = 0
            self.base_strength = 0
            self.base_agility = 0
            self.base_intellect = 0
            self.base_stamina = 0
            self.base_luck = 0
            self.base_accuracy = 0
            self.base_evade = 0
            self.base_mdef = 0
            self.weapon_id = 0
            self.armor_id = 0
            self.unused = 0

        else:
            self.base_hp = stream.get_u16()
            self.base_mp = stream.get_u16()
            self.starting_spell_level = stream.get_u8()
            self.base_strength = stream.get_u8()
            self.base_agility = stream.get_u8()
            self.base_intellect = stream.get_u8()
            self.base_stamina = stream.get_u8()
            self.base_luck = stream.get_u8()
            self.base_accuracy = stream.get_u8()
            self.base_evade = stream.get_u8()
            self.base_mdef = stream.get_u8()
            self.weapon_id = stream.get_u8()
            self.armor_id = stream.get_u8()
            self.unused = stream.get_u8()
Exemplo n.º 19
0
    def __init__(self, stream: InputStream = None):
        if stream is None:
            self.exp_reward = 0
            self.gil_reward = 0
            self.max_hp = 0
            self.morale = 0
            self.unused_ai = 0
            self.evasion = 0
            self.pdef = 0
            self.hit_count = 0
            self.acc = 0
            self.atk = 0
            self.agi = 0
            self.intel = 0
            self.crit_rate = 0
            self.status_atk_elem = 0
            self.status_atk_ailment = 0
            self.family = 0
            self.mdef = 0
            self.unused = 0
            self.elem_weakness = 0
            self.elem_resists = 0
            self.drop_type = 0
            self.drop_id = 0
            self.drop_chance = 0
            self.padding = []

        else:
            self.exp_reward = stream.get_u16()
            self.gil_reward = stream.get_u16()
            self.max_hp = stream.get_u16()
            self.morale = stream.get_u8()
            self.unused_ai = stream.get_u8()
            self.evasion = stream.get_u8()
            self.pdef = stream.get_u8()
            self.hit_count = stream.get_u8()
            self.acc = stream.get_u8()
            self.atk = stream.get_u8()
            self.agi = stream.get_u8()
            self.intel = stream.get_u8()
            self.crit_rate = stream.get_u8()
            self.status_atk_elem = stream.get_u16()
            self.status_atk_ailment = stream.get_u8()
            self.family = stream.get_u8()
            self.mdef = stream.get_u8()
            self.unused = stream.get_u8()
            self.elem_weakness = stream.get_u16()
            self.elem_resists = stream.get_u16()
            self.drop_type = stream.get_u8()
            self.drop_id = stream.get_u8()
            self.drop_chance = stream.get_u8()
            self.padding = []
            for index in range(3):
                self.padding.append(stream.get_u8())