예제 #1
0
    def __init__(self, num_tiles, tile_width=8, tile_height=8):
        """Creates a new EbGraphicTileset.
        :param num_tiles: the number of tiles in this tileset
        :param tile_width: width in pixels of each of the tileset's individual tiles
        :param tile_height: height in pixels of each of the tileset's individual tiles"""
        if num_tiles <= 0:
            raise InvalidArgumentError(
                "Couldn't create EbGraphicTileset with invalid num_tiles[{}]".
                format(num_tiles))
        self.num_tiles_maximum = num_tiles

        if tile_width <= 0:
            raise InvalidArgumentError(
                "Couldn't create EbGraphicTileset with invalid tile_width[{}]".
                format(tile_width))
        elif (tile_width % 8) != 0:
            raise InvalidArgumentError((
                "Couldn't create EbGraphicTileset with a tile_height[{}] that is not a "
                "multiple of 8").format(tile_height))
        self.tile_width = tile_width

        if tile_height <= 0:
            raise InvalidArgumentError(
                "Couldn't create EbGraphicTileset with invalid tile height[{}]"
                .format(tile_height))
        self.tile_height = tile_height

        self.tiles = []
        self._num_tiles_used = 0
        self._used_tiles = dict()
예제 #2
0
 def __init__(self, width, height):
     """Creates a new EbTileArrangement.
     :param width: the width of the arrangement in tiles
     :param height: the height of the arrangement in tiles"""
     if width <= 0:
         raise InvalidArgumentError("Couldn't create EbTileArrangement with invalid width[{}]".format(width))
     self.width = width
     if height <= 0:
         raise InvalidArgumentError("Couldn't create EbTileArrangement with invalid height[{}]".format(height))
     self.height = height
     self.arrangement = [[EbTileArrangementItem() for x in range(self.width)] for y in range(self.height)]
예제 #3
0
def setup_eb_palette_from_image(palette, img, tile_width, tile_height):
    num_subpalettes = palette.num_subpalettes
    subpalette_length = palette.subpalette_length

    width, height = img.size
    rgb_image = img.convert("RGB")
    rgb_image_data = rgb_image.load()
    del rgb_image

    # First, get a list of all the unique sets of colors in each tile
    color_sets = []

    for x in xrange(0, width, tile_width):
        for y in xrange(0, height, tile_height):
            new_color_set = set()

            for tile_x in xrange(x, x + tile_width):
                for tile_y in xrange(y, y + tile_height):
                    r, g, b = rgb_image_data[tile_x, tile_y]
                    r &= 0xf8
                    g &= 0xf8
                    b &= 0xf8
                    new_color_set.add((r, g, b))

            if len(new_color_set) > subpalette_length:
                raise InvalidArgumentError(
                    "Too many unique colors in the {}x{} box at ({},{}) in the image to fit into {} subpalettes,"
                    " each having {} colors".format(tile_width, tile_height, x,
                                                    y, num_subpalettes,
                                                    subpalette_length))

            for i, color_set in enumerate(color_sets):
                if new_color_set.issubset(color_set):
                    break
                elif new_color_set.issuperset(color_set):
                    color_sets[i] = new_color_set
                    break
            else:
                color_sets.append(new_color_set)

    # Next, find a way to fit all the sets of colors into a palette
    color_sets = join_sets(color_sets, num_subpalettes, subpalette_length)
    if color_sets is None:
        raise InvalidArgumentError(
            "Too many unique colors in the image to fit into {} subpalettes, each having {} colors"
            .format(num_subpalettes, subpalette_length))

    for subpalette_id, color_set in enumerate(color_sets):
        for color_id, rgb in enumerate(color_set):
            palette[subpalette_id, color_id].from_tuple(rgb)

    return palette
예제 #4
0
    def from_image_data(self, image_data, y):
        x1, x2, x3, x4 = None, None, None, None
        for x in range(256):
            if x1 is None:
                if image_data[x, y] == 1:
                    x1 = x
            elif x2 is None:
                if image_data[x, y] == 0:
                    x2 = x - 1
            elif x3 is None:
                if image_data[x, y] == 1:
                    x3 = x
            elif x4 is None:
                if image_data[x, y] == 0:
                    x4 = x - 1
            else:
                if image_data[x, y] == 1:
                    raise InvalidArgumentError(
                        "There are more than two lines on the same row at y={}"
                        .format(y))

        if x1 is None:
            self.x1 = 0xff
            self.x2 = 0
        elif x2 is None:
            self.x1 = x1
            self.x2 = 0xff
        else:
            if x1 == x2:
                raise InvalidArgumentError(
                    "Line at ({},{}) must be at least 2 pixels wide".format(
                        x1, y))
            self.x1 = x1
            self.x2 = x2

        if x3 is None:
            self.x3 = 0xff
            self.x4 = 0
        elif x4 is None:
            self.x3 = x3
            self.x4 = 0xff
        else:
            if x3 == x4:
                raise InvalidArgumentError(
                    "Line at ({},{}) must be at least 2 pixels wide".format(
                        x1, y))
            self.x3 = x3
            self.x4 = x4
예제 #5
0
 def __getitem__(self, key):
     subpalette_number, color_number = key
     if subpalette_number < 0 or color_number < 0 or subpalette_number >= self.num_subpalettes \
             or color_number >= self.subpalette_length:
         raise InvalidArgumentError("Could not get color[{},{}] from palette of size[{},{}]".format(
             subpalette_number, color_number, self.num_subpalettes, self.subpalette_length))
     return self.subpalettes[subpalette_number][color_number]
예제 #6
0
 def __init__(self, address=None, size=3):
     if size is None or size <= 0:
         raise InvalidArgumentError(
             "Cannot create pointer with non-positive size[%d]" % size)
     self.size = 3
     if address is not None:
         self.address = address
예제 #7
0
def eb_table_from_offset(offset,
                         single_column=None,
                         matrix_dimensions=None,
                         hidden_columns=None,
                         num_rows=None,
                         name=None):
    if hidden_columns is None:
        hidden_columns = []

    try:
        schema_specification = _EB_SCHEMA_MAP[offset]
    except KeyError:
        raise InvalidArgumentError(
            "Could not setup EbTable from unknown offset[{:#x}]".format(
                offset))

    if single_column:
        schema = single_column
    else:
        schema = EbRowTableEntry.from_schema_specification(
            schema_specification=schema_specification["entries"],
            hidden_columns=hidden_columns)

    if matrix_dimensions:
        matrix_width, matrix_height = matrix_dimensions
        return MatrixTable(schema=schema,
                           matrix_height=matrix_height,
                           name=name or schema_specification["name"],
                           size=schema_specification["size"])
    else:
        return Table(schema=schema,
                     name=name or schema_specification["name"],
                     size=schema_specification["size"],
                     num_rows=num_rows)
예제 #8
0
 def __getitem__(self, key):
     x, y = key
     if x < 0 or y < 0 or x >= self.width or y >= self.height:
         raise InvalidArgumentError(
             "Couldn't get arrangement item[{},{}] from arrangement of size[{}x{}]"
             .format(x, y, self.width, self.height))
     return self.arrangement[y][x]
예제 #9
0
    def __init__(self, num_subpalettes, subpalette_length, rgb_list=None):
        """Creates a new EbPalette.
        :param num_subpalettes: the number of subpalettes within the palette.
        :param subpalette_length: the number of colors within each subpalette."""
        if num_subpalettes <= 0:
            raise InvalidArgumentError("Couldn't create EbPalette with invalid num_subpalettes[{}]".format(
                num_subpalettes))
        self.num_subpalettes = num_subpalettes
        if subpalette_length <= 0:
            raise InvalidArgumentError("Couldn't create EbPalette with invalid subpalette_length[{}]".format(
                subpalette_length))
        self.subpalette_length = subpalette_length

        self.subpalettes = [[EbColor() for j in range(self.subpalette_length)] for i in range(self.num_subpalettes)]

        if rgb_list is not None:
            self.from_list(rgb_list)
예제 #10
0
def from_snes_address(address):
    if address < 0:
        raise InvalidArgumentError(
            "Invalid snes address[{:#x}]".format(address))
    elif address >= 0xc00000:
        return address - 0xc00000
    else:
        return address
예제 #11
0
def check_range_validity(range, size):
    begin, end = range
    if end < begin:
        raise InvalidArgumentError("Invalid range[(%#x,%#x)] provided" %
                                   (begin, end))
    elif (begin < 0) or (end >= size):
        raise OutOfBoundsError("Invalid range[(%#x,%#x)] provided" %
                               (begin, end))
예제 #12
0
    def read_from_yml_data(self, yml_data):
        self.text = yml_data[self.key]['text']
        self.mode = yml_data[self.key]['mode']

        if self.mode not in DYNAMIC_CAST_NAME_MODES:
            raise InvalidArgumentError(
                'Invalid dynamic cast name mode \'{}\' for entry with text \'{}\'. Valid modes are {}'
                .format(self.mode, self.name, DYNAMIC_CAST_NAME_MODES))
예제 #13
0
    def fromstring(cls, s):
        value = getattr(cls, s.upper(), None)
        if value is None:
            from coilsnake.exceptions.common.exceptions import InvalidArgumentError

            raise InvalidArgumentError(
                "Could not convert string[%s] to class[%s] because the value was "
                "undefined" % (s, cls.__name__))
        return value
예제 #14
0
    def tostring(cls, val):
        for k, v in vars(cls).items():
            if v == val:
                return k.lower()
        from coilsnake.exceptions.common.exceptions import InvalidArgumentError

        raise InvalidArgumentError(
            "Could not convert value[%s] to string because the value was undefined"
            % val)
예제 #15
0
 def to_block(self, block, offset, is_mode_01):
     if is_mode_01 and self.x3 != 0xff and self.x4 != 0:
         raise InvalidArgumentError(
             "Cannot write row with two lines in only two bytes")
     block[offset] = self.x1
     block[offset + 1] = self.x2
     if not is_mode_01:
         block[offset + 2] = self.x3
         block[offset + 3] = self.x4
예제 #16
0
    def __setitem__(self, key, item):
        subpalette_number, color_number = key
        if subpalette_number < 0 or subpalette_number >= self.num_subpalettes \
                or (isinstance(color_number, int) and (color_number < 0 or color_number >= self.subpalette_length)):
            raise InvalidArgumentError(
                "Could not set color[{},{}] of palette of size[{},{}]".format(
                    subpalette_number, color_number, self.num_subpalettes,
                    self.subpalette_length))

        self.subpalettes[subpalette_number][color_number] = item
예제 #17
0
 def __setitem__(self, key, item):
     if isinstance(key, int) and isinstance(item, (int, int)):
         if item < 0 or item > 0xff:
             raise InvalidArgumentError(
                 "Could not write invalid value[%d] as a single byte" %
                 item)
         if key >= self.size:
             raise OutOfBoundsError(
                 "Attempted to write to offset[%#x] which is out of bounds"
                 % key)
         else:
             self.data[key] = item
     elif isinstance(key, slice) and \
             (isinstance(item, list) or isinstance(item, array.array) or isinstance(item, Block)):
         if key.start > key.stop:
             raise InvalidArgumentError(
                 "Second argument of slice %s must be greater than  the first"
                 % key)
         elif (key.start < 0) or (key.stop - 1 >= self.size):
             raise OutOfBoundsError(
                 "Attempted to write to range (%#x,%#x) which is out of bounds"
                 % (key.start, key.stop - 1))
         elif len(item) != (key.stop - key.start):
             raise InvalidArgumentError(
                 "Attempted to write data of size %d to range of length %d"
                 % (len(item), key.stop - key.start))
         elif (key.stop - key.start) == 0:
             raise InvalidArgumentError("Attempted to write data of size 0")
         else:
             if isinstance(item, list):
                 self.data[key] = array.array('B', item)
             elif isinstance(item, array.array):
                 self.data[key] = item
             elif isinstance(item, Block):
                 self.data[key] = item.data
             else:
                 raise InvalidArgumentError(
                     "Can not write value of type[{}]".format(type(item)))
     else:
         raise TypeError(
             "Arguments \"key\" and \"item\" had invalid types of %s and %s"
             % (type(key).__name__, type(item).__name__))
예제 #18
0
    def recreate(self, num_rows=None, size=None):
        if num_rows is not None:
            self.num_rows = num_rows
        else:
            if size % self.schema.size != 0:
                raise InvalidArgumentError(
                    "Cannot create table[{}] with rows of size[{}] and total size[{}]"
                    .format(self.name, self.schema.size, size))
            self.num_rows = size // self.schema.size

        self.size = self.schema.size * self.num_rows
        self.values = [None for i in range(self.num_rows)]
예제 #19
0
    def allocate(self, data=None, size=None, can_write_to=None):
        if data is None and size is None:
            raise InvalidArgumentError("Insufficient parameters provided")

        if size is None:
            size = len(data)
        elif data is not None and size != len(data):
            raise InvalidArgumentError(
                "Parameter size[%d] and data's size[%d] differ" %
                (size, len(data)))

        if size <= 0:
            raise InvalidArgumentError("Cannot allocate a range of size[%d]" %
                                       size)

        # First find a free range
        allocated_range = None
        for i in range(0, len(self.unallocated_ranges)):
            begin, end = self.unallocated_ranges[i]
            if size <= end - begin + 1:
                if (can_write_to is not None) and (not can_write_to(begin)):
                    continue

                if begin + size - 1 == end:
                    # Used up the entire free range
                    del (self.unallocated_ranges[i])
                else:
                    self.unallocated_ranges[i] = (begin + size, end)

                allocated_range = (begin, begin + size - 1)
                break

        if allocated_range is None:
            raise NotEnoughUnallocatedSpaceError("Not enough free space left")

        if data is not None:
            self[allocated_range[0]:allocated_range[1] + 1] = data

        return allocated_range[0]
예제 #20
0
    def to_table_entry_class(cls, column_specification):
        class_name = "GeneratedTableEntry_{}".format(
            column_specification["name"])
        column_specification["size"] = getitem_with_default(
            column_specification, "size", 1)
        column_specification["type"] = getitem_with_default(
            column_specification, "type", cls.DEFAULT_TABLE_ENTRY_TYPE)
        if (column_specification["type"]
                == "int") and ("values" in column_specification):
            return EnumeratedLittleEndianIntegerTableEntry.create(
                column_specification["name"], column_specification["size"],
                column_specification["values"])
        elif (column_specification["type"]
              == "bitfield") and ("bitvalues" in column_specification):
            enumeration_class = GenericEnum.create(
                name=class_name, values=column_specification["bitvalues"])
            return BitfieldTableEntry.create(
                name=column_specification["name"],
                size=column_specification["size"],
                enumeration_class=enumeration_class)
        else:
            try:
                entry_class, parameter_list = cls.TABLE_ENTRY_CLASS_MAP[
                    column_specification["type"]]
            except KeyError:
                raise InvalidArgumentError(
                    "Unknown table column type[{}]".format(
                        column_specification["type"]))

            try:
                parameters = dict(
                    map(lambda x: (x, column_specification[x]),
                        parameter_list))
            except KeyError:
                raise InvalidArgumentError(
                    "Column[{}] in table schema not provided with all required attributes[{}]"
                    .format(column_specification["name"], parameter_list))

            return type(class_name, (entry_class, ), parameters)
예제 #21
0
 def write_multi(self, key, item, size):
     if size < 0:
         raise InvalidArgumentError(
             "Attempted to write data of negative length[%d]" % size)
     elif (key < 0) or (key >= self.size) or (key + size > self.size):
         raise OutOfBoundsError(
             "Attempted to write size[%d] bytes to offset[%#x], which is out of bounds in this "
             "block of size[%#x]" % (size, key, self.size))
     elif size == 0:
         return
     else:
         for i in range(key, key + size):
             self.data[i] = item & 0xff
             item >>= 8
예제 #22
0
    def __init__(self,
                 schema,
                 name="Anonymous Table",
                 size=None,
                 num_rows=None):
        self.name = name

        if size is None and num_rows is None:
            raise InvalidArgumentError(
                "Cannot create table[{}] with null size and null num_rows".
                format(self.name))

        self.schema = schema

        self.recreate(num_rows=num_rows, size=size)
예제 #23
0
    def read_from_project(self, resource_open):
        formatting_data = {}

        with resource_open(CAST_FORMATTING_FILE_NAME, 'yml', True) as f:
            formatting_data = yml_load(f)

        for fmt_entry in formatting_data:
            entry = EbCastEntry()
            entry.set_values(formatting_data[fmt_entry]['begin'],
                             formatting_data[fmt_entry]['size'],
                             formatting_data[fmt_entry]['misc'])
            self.entries.append(entry)

            if entry.size == 0:
                raise InvalidArgumentError(
                    'Cast graphics entry number {} has size 0 - would crash the cast screen.'
                    .format(fmt_entry))
예제 #24
0
 def read_multi(self, key, size):
     if size < 0:
         raise InvalidArgumentError(
             "Attempted to read data of negative length[%d]" % size)
     elif size == 0:
         return 0
     elif (key < 0) or (key >= self.size) or (key + size > self.size):
         raise OutOfBoundsError(
             "Attempted to read size[%d] bytes from offset[%#x], which is out of bounds in this "
             "block of size[%#x]" % (size, key, self.size))
     else:
         out = 0
         bit_offset = 0
         for byte in self.data[key:key + size]:
             out |= byte << bit_offset
             bit_offset += 8
         return out
예제 #25
0
    def __init__(self,
                 schema,
                 matrix_height,
                 name="Anonymous Table",
                 size=None,
                 num_rows=None):
        super(MatrixTable, self).__init__(schema=schema,
                                          name=name,
                                          size=size,
                                          num_rows=num_rows)

        if self.num_rows % matrix_height != 0:
            raise InvalidArgumentError(
                "Could not create MatrixTable with num_rows[{}] not evenly divisible "
                "by matrix_height[{}]".format(self.num_rows, matrix_height))
        self.matrix_height = matrix_height
        self.matrix_width = self.num_rows // matrix_height
예제 #26
0
    def from_schema(cls,
                    schema,
                    name="CustomRowTableEntry",
                    hidden_columns=set()):
        if type(hidden_columns) == list:
            hidden_columns = set(hidden_columns)
        elif type(hidden_columns) != set:
            raise InvalidArgumentError(
                "Could not create RowTableEntry with invalid hidden_columns[{}]"
                .format(hidden_columns))

        return type(
            name, (cls, ), {
                "name": name,
                "size": sum([x.size for x in schema]),
                "schema": schema,
                "hidden_columns": hidden_columns
            })
예제 #27
0
 def expand(self, desired_size):
     if self.type == 'Earthbound':
         if (desired_size != 0x400000) and (desired_size != 0x600000):
             raise InvalidArgumentError(
                 "Cannot expand an %s ROM to size[%#x]" %
                 (self.type, self.size))
         else:
             if self.size == 0x300000:
                 self.data.fromlist([0] * 0x100000)
                 self.size += 0x100000
             if desired_size == 0x600000 and self.size == 0x400000:
                 self[0x00ffd5] = 0x25
                 self[0x00ffd7] = 0x0d
                 self.data.fromlist([0] * 0x200000)
                 self.size += 0x200000
                 # The data range written below is already marked as used in romtypes.yml
                 for i in range(0x8000, 0x8000 + 0x8000):
                     self[0x400000 + i] = self[i]
     else:
         raise NotImplementedError(
             "Don't know how to expand ROM of type[%s]" % self.type)
예제 #28
0
 def __getitem__(self, key):
     if isinstance(key, slice):
         if key.start > key.stop:
             raise InvalidArgumentError(
                 "Second argument of slice %s must be greater than the first"
                 % key)
         elif (key.start < 0) or (key.stop - 1 >= self.size):
             raise OutOfBoundsError(
                 "Attempted to read from range (%#x,%#x) which is out of bounds"
                 % (key.start, key.stop - 1))
         else:
             out = Block()
             out.from_array(self.data[key])
             return out
     elif isinstance(key, int):
         if key >= self.size:
             raise OutOfBoundsError(
                 "Attempted to read at offset[%#x] which is out of bounds" %
                 key)
         else:
             return self.data[key]
     else:
         raise TypeError("Argument \"key\" had invalid type of %s" %
                         type(key).__name__)
예제 #29
0
def open_image(f):
    try:
        image = Image.open(f)
        return image
    except IOError:
        raise InvalidArgumentError("Could not open file: {}".format(f.name))
예제 #30
0
 def check_validity(self):
     if self.tile < 0 or self.tile > 0x3ff:
         raise InvalidArgumentError("Invalid tile[{}]".format(self.tile))
     if self.subpalette < 0 or self.subpalette > 7:
         raise InvalidArgumentError("Invalid subpalette[{}]".format(
             self.subpalette))