コード例 #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()
コード例 #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()
コード例 #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()
コード例 #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))
コード例 #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()
コード例 #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)
コード例 #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
コード例 #8
0
ファイル: maps.py プロジェクト: nic0lette/ffr-hmsj
    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
コード例 #9
0
ファイル: rom.py プロジェクト: nic0lette/ffr-hmsj
 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)}")
コード例 #10
0
ファイル: rom.py プロジェクト: nic0lette/ffr-hmsj
    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])
コード例 #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
コード例 #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()
コード例 #13
0
ファイル: rom.py プロジェクト: nic0lette/ffr-hmsj
    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])
コード例 #14
0
ファイル: maps.py プロジェクト: nic0lette/ffr-hmsj
 def read(stream: InputStream):
     chest_data = stream.get_u32()
     if chest_data & 0x80000000 == 0:
         return MoneyChest(chest_data)
     else:
         return ItemChest(chest_data)
コード例 #15
0
 def __getitem__(self, index):
     return TextBlock._as_ascii(
         InputStream(self.strings[index], check_alignment=False))
コード例 #16
0
 def __setitem__(self, index, value):
     self.strings[index] = TextBlock._encode_text(
         InputStream(value, check_alignment=False))
コード例 #17
0
 def encode_text(text: str) -> bytearray:
     data = bytearray()
     for char in text:
         data.append(ord(char))
     return TextBlock._encode_text(InputStream(data))
コード例 #18
0
ファイル: classes.py プロジェクト: nic0lette/ffr-hmsj
    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()
コード例 #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())