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
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
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
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
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
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
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
def get_action_list(self): actions = real_sprite.parse_sprite_data(self) actions[0].sprite_num = self.sprite_num return actions