Beispiel #1
0
    def resolve_spritegroup_ref(self, sg_ref):
        """
        Resolve a reference to a (sprite/palette) sprite group

        @param sg_ref: Reference to a sprite group
        @type sg_ref: L{SpriteGroupRef}

        @return: Sprite number (index of action1 set) to use
        @rtype: L{Expression}
        """
        spriteset = action2.resolve_spritegroup(sg_ref.name)

        if len(sg_ref.param_list) == 0:
            offset = None
        elif len(sg_ref.param_list) == 1:
            id_dicts = [(spriteset.labels, lambda val, pos: expression.ConstantNumeric(val, pos))]
            offset = action2var.reduce_varaction2_expr(sg_ref.param_list[0], self.feature, self.extra_dicts + id_dicts)
            if isinstance(offset, expression.ConstantNumeric):
                generic.check_range(offset.value, 0, len(real_sprite.parse_sprite_data(spriteset)) - 1, "offset within spriteset", sg_ref.pos)
        else:
            raise generic.ScriptError("Expected 0 or 1 parameter, got " + str(len(sg_ref.param_list)), sg_ref.pos)

        num = action1.get_action1_index(spriteset)
        generic.check_range(num, 0, (1 << 14) - 1, "sprite", sg_ref.pos)
        return expression.ConstantNumeric(num), offset
Beispiel #2
0
def add_to_action1(spritesets, feature, pos):
    """
    Add a list of spritesets to a spriteset collection. This will try to reuse
    one collection as long as possible and create a new one when needed.

    @param spritesets: List of spritesets that will be used by the next action2.
    @type spritesets: C{list} of L{SpriteSet}

    @param feature: Feature of the spritesets.
    @type feature: C{int}

    @param pos: Position reference to source.
    @type  pos: L{Position}

    @return: List of collections that needs to be added to the global action list.
    @rtype: C{list} of L{SpritesetCollection}.
    """
    if not spritesets:
        return []

    setsize = len(real_sprite.parse_sprite_data(spritesets[0]))
    for spriteset in spritesets:
        if setsize != len(real_sprite.parse_sprite_data(spriteset)):
            raise generic.ScriptError(
                "Using spritesets with different sizes in a single sprite group / layout is not possible",
                pos)

    global spriteset_stats
    if spriteset_stats[0] < len(spritesets):
        spriteset_stats = (len(spritesets), pos)

    global last_spriteset_collection
    actions = []
    if last_spriteset_collection is None or not last_spriteset_collection.can_add(
            spritesets, feature):
        last_spriteset_collection = SpritesetCollection(
            feature, len(real_sprite.parse_sprite_data(spritesets[0])))
        actions.append(last_spriteset_collection)

    last_spriteset_collection.add(spritesets)

    return actions
Beispiel #3
0
def parse_action5(replaces):
    real_sprite_list = real_sprite.parse_sprite_data(replaces)
    num_sprites = len(real_sprite_list)

    if replaces.type.value not in action5_table:
        raise generic.ScriptError(
            replaces.type.value + " is not a valid sprite replacement type",
            replaces.type.pos)
    type_id, num_required, block_type = action5_table[replaces.type.value]
    offset = None

    if block_type == Action5BlockType.FIXED:
        if num_sprites < num_required:
            msg = "Invalid sprite count for sprite replacement type '{}', expected {:d}, got {:d}"
            msg = msg.format(replaces.type, num_required, num_sprites)
            raise generic.ScriptError(msg, replaces.pos)

        elif num_sprites > num_required:
            msg = (
                "Too many sprites specified for sprite replacement type '{}',"
                " expected {:d}, got {:d}, extra sprites may be ignored"
            ).format(replaces.type, num_required, num_sprites)
            generic.print_warning(msg, replaces.pos)

        if replaces.offset != 0:
            msg = "replacenew parameter 'offset' must be zero for sprite replacement type '{}'".format(
                replaces.type)
            raise generic.ScriptError(msg, replaces.pos)

    elif block_type == Action5BlockType.ANY:
        if replaces.offset != 0:
            msg = "replacenew parameter 'offset' must be zero for sprite replacement type '{}'".format(
                replaces.type)
            raise generic.ScriptError(msg, replaces.pos)

    elif block_type == Action5BlockType.OFFSET:
        if num_sprites + replaces.offset > num_required:
            msg = "Exceeding the limit of {:d} sprites for sprite replacement type '{}', extra sprites may be ignored"
            msg = msg.format(num_required, replaces.type)
            generic.print_warning(msg, replaces.pos)

        if replaces.offset != 0 or num_sprites != num_required:
            offset = replaces.offset
    else:
        assert 0

    return [Action5(type_id, num_sprites, offset)] + real_sprite_list
Beispiel #4
0
    def get_action_list(self):
        """
        Create a list of actions needed to write this collection to the output. This
        will generate a single Action1 and as many realsprites as needed.

        @return: A list of actions needed to represet this collection in a GRF.
        @rtype: C{list} of L{BaseAction}
        """
        actions = [
            Action1(self.feature, len(self.spritesets),
                    self.num_sprites_per_spriteset)
        ]
        for idx in range(len(self.spritesets)):
            for spriteset, spriteset_offset in self.spritesets.items():
                if idx == spriteset_offset:
                    actions.extend(real_sprite.parse_sprite_data(spriteset))
                    break
        return actions
Beispiel #5
0
def parse_actionA(replaces):
    """
    Parse replace-block to ActionA.

    @param replaces: Replace-block to parse.
    @type  replaces: L{ReplaceSprite}
    """
    action_list = []
    action6.free_parameters.save()
    act6 = action6.Action6()

    real_sprite_list = real_sprite.parse_sprite_data(replaces)
    block_list = []
    total_sprites = len(real_sprite_list)
    offset = 2  # Skip 0A and <num-sets>
    sprite_offset = 0  # Number of sprites already covered by previous [<num-sprites> <first-sprite>]-pairs

    while total_sprites > 0:
        this_block = min(total_sprites, 255)  # number of sprites in this block
        total_sprites -= this_block
        offset += 1  # Skip <num-sprites>

        first_sprite = replaces.start_id  # number of first sprite
        if sprite_offset != 0:
            first_sprite = expression.BinOp(
                nmlop.ADD, first_sprite,
                expression.ConstantNumeric(sprite_offset, first_sprite.pos),
                first_sprite.pos).reduce()
        first_sprite, offset = actionD.write_action_value(
            first_sprite, action_list, act6, offset, 2)
        block_list.append((this_block, first_sprite.value))

        sprite_offset += this_block  # increase first-sprite for next block

    if len(act6.modifications) > 0:
        action_list.append(act6)
    action6.free_parameters.restore()

    action_list.append(ActionA(block_list))
    action_list.extend(real_sprite_list)

    return action_list
Beispiel #6
0
def parse_action12(font_glyphs):
    try:
        font_size = font_glyphs.font_size.reduce_constant([font_sizes])
        if isinstance(font_glyphs.base_char, expression.StringLiteral) and len(
                font_glyphs.base_char.value) == 1:
            base_char = ord(font_glyphs.base_char.value)
        else:
            base_char = font_glyphs.base_char.reduce_constant()
    except generic.ConstError:
        raise generic.ScriptError(
            "Parameters of font_glyph have to be compile-time constants",
            font_glyphs.pos)
    if font_size.value not in list(font_sizes.values()):
        raise generic.ScriptError(
            "Invalid value for parameter 'font_size' in font_glyph, valid values are 0, 1, 2",
            font_size.pos)
    if not (0 <= base_char.value <= 0xFFFF):
        raise generic.ScriptError(
            "Invalid value for parameter 'base_char' in font_glyph, valid values are 0-0xFFFF",
            base_char.pos)

    real_sprite_list = real_sprite.parse_sprite_data(font_glyphs)
    char = base_char.value
    last_char = char + len(real_sprite_list)
    if last_char > 0xFFFF:
        raise generic.ScriptError(
            "Character numbers in font_glyph block exceed the allowed range (0-0xFFFF)",
            font_glyphs.pos)

    sets = []
    while char < last_char:
        #each set of characters must fit in a single 128-char block, according to specs / TTDP
        if (char // 128) * 128 != (last_char // 128) * 128:
            num_in_set = (char // 128 + 1) * 128 - char
        else:
            num_in_set = last_char - char
        sets.append((font_size, num_in_set, char))
        char += num_in_set

    return [Action12(sets)] + real_sprite_list
Beispiel #7
0
    def can_add(self, spritesets, feature):
        """
        Test whether the given list of spritesets can be added to this collection.

        @param spritesets: The list of spritesets to test for addition.
        @type spritesets: C{list} of L{SpriteSet}

        @param feature: The feature of the given spritesets.
        @type feature: C{int}

        @return: True iff the given spritesets can be added to this collection.
        @rtype: C{bool}
        """
        assert len(spritesets) <= max_sprite_block_size
        if feature != self.feature:
            return False
        for spriteset in spritesets:
            if len(real_sprite.parse_sprite_data(
                    spriteset)) != self.num_sprites_per_spriteset:
                return False
        num_new_sets = sum(1 for x in spritesets if x not in self.spritesets)
        return len(self.spritesets) + num_new_sets <= max_sprite_block_size
Beispiel #8
0
 def get_action_list(self):
     actions = real_sprite.parse_sprite_data(self)
     actions[0].sprite_num = self.sprite_num
     return actions