示例#1
0
def get_production_v2_actions(produce):
    """
    Get the action list that implements the given produce-block in nfo.

    @param produce: Produce-block to parse.
    @type produce: L{Produce2}
    """
    action_list = []
    action6.free_parameters.save()

    varact2parser = action2var.Varaction2Parser(0x0A,
                                                action2var.get_scope(0x0A))

    def resolve_cargoitem(item):
        cargolabel = item.name.value
        if cargolabel not in global_constants.cargo_numbers:
            raise generic.ScriptError(
                "Cargo label {0} not found in your cargo table".format(
                    cargolabel), produce.pos)
        cargoindex = global_constants.cargo_numbers[cargolabel]
        valueregister = resolve_prodcb_register(item.value, varact2parser)
        return (cargoindex, valueregister)

    sub_in = [resolve_cargoitem(item) for item in produce.subtract_in]
    add_out = [resolve_cargoitem(item) for item in produce.add_out]
    again = resolve_prodcb_register(produce.again, varact2parser)

    prod_action = Action2Production(produce.name.value, produce.pos, 2, sub_in,
                                    add_out, again)

    return finish_production_actions(produce, prod_action, action_list,
                                     varact2parser)
示例#2
0
文件: item.py 项目: spnda/nml
    def pre_process(self):
        for graphics_def in self.graphics_list:
            graphics_def.reduce_expressions(action2var.get_scope(item_feature))
        if self.default_graphics is not None:
            if self.default_graphics.value is None:
                raise generic.ScriptError(
                    "Returning the computed value is not possible in a graphics-block, as there is no computed value.",
                    self.pos,
                )
            self.default_graphics.value = action2var.reduce_varaction2_expr(
                self.default_graphics.value,
                action2var.get_scope(item_feature))

        # initialize base class and pre_process it as well (in that order)
        self.initialize(None, item_feature)
        graphics_base_class.pre_process(self)
示例#3
0
    def pre_process(self):
        # Check parameter names
        seen_names = set()
        for param in self.param_list:
            if not isinstance(param, expression.Identifier):
                raise generic.ScriptError(
                    "switch parameter names must be identifiers.", param.pos)
            if param.value in seen_names:
                raise generic.ScriptError(
                    "Duplicate parameter name '{}' encountered.".format(
                        param.value), param.pos)
            seen_names.add(param.value)

        feature = next(iter(self.feature_set))
        var_scope = action2var.get_scope(feature, self.var_range)
        if var_scope is None:
            raise generic.ScriptError(
                "Requested scope not available for this feature.", self.pos)

        # Allocate registers
        param_map = {}
        param_registers = []
        for param in self.param_list:
            reg = action2var.VarAction2CallParam(param.value)
            param_registers.append(reg)
            param_map[param.value] = reg
        param_map = (param_map, lambda name, value, pos: action2var.
                     VarAction2LoadCallParam(value, name))
        self.register_map[feature] = param_registers

        self.expr = action2var.reduce_varaction2_expr(self.expr, var_scope,
                                                      [param_map])
        self.body.reduce_expressions(var_scope, [param_map])
        switch_base_class.pre_process(self)
示例#4
0
def get_production_actions(produce):
    """
    Get the action list that implements the given produce-block in nfo.

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

    result_list = []
    varact2parser = action2var.Varaction2Parser(0x0A,
                                                action2var.get_scope(0x0A))
    if all(x.supported_by_actionD(False) for x in produce.param_list):
        version = 0
        offset = 4
        for i, param in enumerate(produce.param_list):
            result, offset = actionD.write_action_value(
                param, action_list, act6, offset, 2 if i < 5 else 1)
            result_list.append(result.value)
    else:
        version = 1
        for param in produce.param_list:
            result_list.append(resolve_prodcb_register(param, varact2parser))

    if len(act6.modifications) > 0:
        action_list.append(act6)
    prod_action = Action2Production(produce.name.value, produce.pos, version,
                                    result_list[0:3], result_list[3:5],
                                    result_list[5])

    return finish_production_actions(produce, prod_action, action_list,
                                     varact2parser)
示例#5
0
文件: action3.py 项目: spnda/nml
def create_cb_choice_varaction2(feature, expr, mapping, default, pos):
    """
    Create a varaction2 that maps callback numbers to various sprite groups

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

    @param expr: Expression to evaluate
    @type expr: L{Expression}

    @param mapping: Mapping of various values to sprite groups,
                    with a possible extra function to apply to the return value
    @type mapping: C{dict} that maps C{int} to C{tuple} of (L{SpriteGroupRef}, C{function}, or C{None})

    @param default: Default sprite group if no value matches
    @type default: L{SpriteGroupRef}

    @param pos: Positional context.
    @type  pos: L{Position}

    @return: A tuple containing the action list and a reference to the created action2
    @rtype: C{tuple} of (C{list} of L{BaseAction}, L{SpriteGroupRef})
    """
    varact2parser = action2var.Varaction2Parser(feature,
                                                action2var.get_scope(feature))
    varact2parser.parse_expr(expr)
    return create_intermediate_varaction2(feature, varact2parser, mapping,
                                          default, pos)
示例#6
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 name, val, pos: expression.ConstantNumeric(val, pos))]
            offset = action2var.reduce_varaction2_expr(
                sg_ref.param_list[0], action2var.get_scope(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
示例#7
0
文件: produce.py 项目: spnda/nml
 def pre_process(self):
     var_scope = action2var.get_scope(0x0A)
     for i, param in enumerate(self.subtract_in):
         self.subtract_in[i].value = action2var.reduce_varaction2_expr(
             param.value, var_scope)
     for i, param in enumerate(self.add_out):
         self.add_out[i].value = action2var.reduce_varaction2_expr(
             param.value, var_scope)
     self.again = action2var.reduce_varaction2_expr(self.again, var_scope)
     produce_base_class.pre_process(self)
示例#8
0
文件: produce.py 项目: spnda/nml
 def pre_process(self):
     generic.print_warning(
         generic.Warning.DEPRECATION,
         "Consider using the new produce() syntax for '{}'".format(
             self.name),
         self.name.pos,
     )
     var_scope = action2var.get_scope(0x0A)
     for i, param in enumerate(self.param_list):
         self.param_list[i] = action2var.reduce_varaction2_expr(
             param, var_scope)
     produce_base_class.pre_process(self)
示例#9
0
def resolve_prodcb_register(param, varact2parser):
    if (
        isinstance(param, expression.StorageOp)
        and param.name == "LOAD_TEMP"
        and isinstance(param.register, expression.ConstantNumeric)
    ):
        # We can load a register directly
        res = action2var.VarAction2Var(0x7D, 0, 0xFFFFFFFF, param.register.value)
    else:
        if len(varact2parser.var_list) != 0:
            varact2parser.var_list.append(nmlop.VAL2)
            varact2parser.var_list_size += 1
        varact2parser.parse_expr(action2var.reduce_varaction2_expr(param, action2var.get_scope(0x0A)))
        store_tmp = action2var.VarAction2StoreTempVar()
        res = action2var.VarAction2LoadTempVar(store_tmp)
        varact2parser.var_list.append(nmlop.STO_TMP)
        varact2parser.var_list.append(store_tmp)
        varact2parser.var_list_size += store_tmp.get_size() + 1  # Add 1 for operator
    return res
示例#10
0
    def pre_process(self):
        feature = next(iter(self.feature_set))
        # var_scope is really weird for type=BACKWARD/FORWARD.
        # Expressions in cases will still refer to the origin vehicle.
        var_scope = action2var.get_scope(
            feature, 0x8A if self.type.value == "PARENT" else 0x89)

        for choice in self.choices:
            choice.reduce_expressions(var_scope)

        for dep_list in (self.dependent, self.independent):
            for i, dep in enumerate(dep_list[:]):
                if dep.is_return:
                    raise generic.ScriptError(
                        "Expected a random_switch identifier after (in)dependent, not a return.",
                        dep.pos)
                dep_list[i] = dep.value.reduce(global_constants.const_list)
                # Make sure, all [in]dependencies refer to existing random switch blocks
                if (not isinstance(dep_list[i], expression.SpriteGroupRef)
                    ) or len(dep_list[i].param_list) > 0:
                    raise generic.ScriptError(
                        "Value for (in)dependent should be an identifier",
                        dep_list[i].pos)
                spritegroup = action2.resolve_spritegroup(dep_list[i].name)
                if not isinstance(spritegroup, RandomSwitch):
                    raise generic.ScriptError(
                        "Value of (in)dependent '{}' should refer to a random_switch."
                        .format(dep_list[i].name.value),
                        dep_list[i].pos,
                    )

        self.triggers = self.triggers.reduce_constant(
            global_constants.const_list)
        if not (0 <= self.triggers.value <= 255):
            raise generic.ScriptError(
                "random_switch parameter 4 'triggers' out of range 0..255, encountered "
                + str(self.triggers.value),
                self.triggers.pos,
            )

        switch_base_class.pre_process(self)
示例#11
0
文件: action3.py 项目: spnda/nml
def create_proc_call_varaction2(feature, proc, ret_value_function,
                                parent_action, pos):
    """
    Create a varaction2 that executes a procedure call and applies a function on the result

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

    @param proc: Procedure to execute
    @type proc: L{SpriteGroupRef}

    @param ret_value_function: Function to apply on the result (L{Expression} -> L{Expression})
    @type ret_value_function: C{function}

    @param pos: Positional context.
    @type  pos: L{Position}

    @return: A list of extra actions, reference to the created action2 and a comment to add
    @rtype: C{tuple} of (C{list} of L{BaseAction}, L{SpriteGroupRef}, C{str})
    """
    proc.is_procedure = True
    varact2parser = action2var.Varaction2Parser(feature,
                                                action2var.get_scope(feature))
    varact2parser.parse_proc_call(proc)

    mapping = {
        0xFFFF: (expression.SpriteGroupRef(expression.Identifier("CB_FAILED"),
                                           [], None), None)
    }
    default = ret_value_function(
        expression.Variable(expression.ConstantNumeric(0x1C)))
    action_list, result = create_intermediate_varaction2(
        feature, varact2parser, mapping, default, pos)
    action2.add_ref(result, parent_action)
    comment = result.name.value + ";"
    return (action_list, result, comment)
示例#12
0
def get_layout_action2s(spritelayout, feature, spr_pos):
    """
    @param spr_pos: Position information of the sprite view.
    @type  spr_pos: L{Position}
    """
    ground_sprite = None
    building_sprites = []
    actions = []

    if feature not in action2.features_sprite_layout:
        raise generic.ScriptError(
            "Sprite layouts are not supported for feature '{}'.".format(
                general.feature_name(feature)))

    # Allocate registers
    param_map = {}
    param_registers = []
    for param in spritelayout.param_list:
        reg = action2var.VarAction2CallParam(param.value)
        param_registers.append(reg)
        param_map[param.value] = reg
    param_map = (param_map, lambda name, value, pos: action2var.
                 VarAction2LoadCallParam(value, name))
    spritelayout.register_map[feature] = param_registers

    # Reduce all expressions, can't do that earlier as feature is not known
    all_sprite_sets = []
    layout_sprite_list = []  # Create a new structure
    for layout_sprite in spritelayout.layout_sprite_list:
        param_list = []
        layout_sprite_list.append(
            (layout_sprite.type, layout_sprite.pos, param_list))
        for param in layout_sprite.param_list:
            param_val = action2var.reduce_varaction2_expr(
                param.value, action2var.get_scope(feature), [param_map])
            param_list.append((param.name, param_val))
            if isinstance(param_val, expression.SpriteGroupRef):
                spriteset = action2.resolve_spritegroup(param_val.name)
                if not spriteset.is_spriteset():
                    raise generic.ScriptError(
                        "Expected a reference to a spriteset.", param_val.pos)
                all_sprite_sets.append(spriteset)
    actions.extend(
        action1.add_to_action1(all_sprite_sets, feature, spritelayout.pos))

    temp_registers = []
    for type, pos, param_list in layout_sprite_list:
        if type.value not in layout_sprite_types:
            raise generic.ScriptError(
                "Invalid sprite type '{}' encountered. Expected 'ground', 'building', or 'childsprite'."
                .format(type.value),
                type.pos,
            )
        sprite = Action2LayoutSprite(feature, layout_sprite_types[type.value],
                                     pos, [param_map])
        for name, value in param_list:
            sprite.set_param(name, value)
        temp_registers.extend(sprite.get_all_registers())
        if sprite.type == Action2LayoutSpriteType.GROUND:
            if ground_sprite is not None:
                raise generic.ScriptError(
                    "Sprite layout can have no more than one ground sprite",
                    spritelayout.pos)
            ground_sprite = sprite
        else:
            building_sprites.append(sprite)

    if ground_sprite is None:
        if len(building_sprites) == 0:
            # no sprites defined at all, that's not very much.
            raise generic.ScriptError(
                "Sprite layout requires at least one sprite", spr_pos)
        # set to 0 for no ground sprite
        ground_sprite = Action2LayoutSprite(feature,
                                            Action2LayoutSpriteType.GROUND)
        ground_sprite.set_param(expression.Identifier("sprite"),
                                expression.ConstantNumeric(0))

    action6.free_parameters.save()
    act6 = action6.Action6()

    advanced = any(x.is_advanced_sprite()
                   for x in building_sprites + [ground_sprite])

    offset = 4
    sprite_num = ground_sprite.get_sprite_number()
    sprite_num, offset = actionD.write_action_value(sprite_num, actions, act6,
                                                    offset, 4)
    if advanced:
        offset += ground_sprite.get_registers_size()

    for sprite in building_sprites:
        sprite_num = sprite.get_sprite_number()
        sprite_num, offset = actionD.write_action_value(
            sprite_num, actions, act6, offset, 4)
        if advanced:
            offset += sprite.get_registers_size()
        offset += 3 if sprite.type == Action2LayoutSpriteType.CHILD else 6

    if len(act6.modifications) > 0:
        actions.append(act6)

    layout_action = Action2Layout(
        feature,
        spritelayout.name.value + " - feature {:02X}".format(feature),
        spritelayout.pos,
        ground_sprite,
        building_sprites,
        param_registers,
    )
    actions.append(layout_action)

    if temp_registers:
        varact2parser = action2var.Varaction2Parser(
            feature, action2var.get_scope(feature))
        for register_info in temp_registers:
            reg, expr = register_info[1], register_info[2]
            if reg is None:
                continue
            varact2parser.parse_expr(expr)
            varact2parser.var_list.append(nmlop.STO_TMP)
            varact2parser.var_list.append(reg)
            varact2parser.var_list.append(nmlop.VAL2)
            varact2parser.var_list_size += reg.get_size() + 2

    # Only continue if we actually needed any new registers
    if temp_registers and varact2parser.var_list:  # lgtm[py/uninitialized-local-variable]
        # Remove the last VAL2 operator
        varact2parser.var_list.pop()
        varact2parser.var_list_size -= 1

        actions.extend(varact2parser.extra_actions)
        extra_act6 = action6.Action6()
        for mod in varact2parser.mods:
            extra_act6.modify_bytes(mod.param, mod.size, mod.offset + 4)
        if len(extra_act6.modifications) > 0:
            actions.append(extra_act6)

        varaction2 = action2var.Action2Var(
            feature,
            "{}@registers - feature {:02X}".format(spritelayout.name.value,
                                                   feature), spritelayout.pos,
            0x89)
        varaction2.var_list = varact2parser.var_list
        ref = expression.SpriteGroupRef(spritelayout.name, [], None,
                                        layout_action)
        varaction2.ranges.append(
            action2var.VarAction2Range(expression.ConstantNumeric(0),
                                       expression.ConstantNumeric(0), ref, ""))
        varaction2.default_result = ref
        varaction2.default_comment = ""

        # Add two references (default + range)
        # Make sure that registers allocated here are not used by the spritelayout
        action2.add_ref(ref, varaction2, True)
        action2.add_ref(ref, varaction2, True)
        spritelayout.set_action2(varaction2, feature)
        actions.append(varaction2)
    else:
        spritelayout.set_action2(layout_action, feature)

    action6.free_parameters.restore()
    return actions
示例#13
0
    def __init__(self, param_list, choices, pos):
        base_statement.BaseStatement.__init__(self, "random_switch-block", pos,
                                              False, False)
        if not (3 <= len(param_list) <= 4):
            raise generic.ScriptError(
                "random_switch requires 3 or 4 parameters, encountered {:d}".
                format(len(param_list)), pos)
        # feature
        feature = general.parse_feature(param_list[0]).value

        # type
        self.type = param_list[1]
        # Extract type name and possible argument
        if isinstance(self.type, expression.Identifier):
            self.type_count = None
        elif isinstance(self.type, expression.FunctionCall):
            if len(self.type.params) == 0:
                self.type_count = None
            elif len(self.type.params) == 1:
                # var_scope is really weird for type=BACKWARD/FORWARD.
                var_scope = action2var.get_scope(feature, 0x89)
                self.type_count = action2var.reduce_varaction2_expr(
                    self.type.params[0], var_scope)
            else:
                raise generic.ScriptError(
                    "Value for random_switch parameter 2 'type' can have only one parameter.",
                    self.type.pos)
            self.type = self.type.name
        else:
            raise generic.ScriptError(
                "random_switch parameter 2 'type' should be an identifier, possibly with a parameter.",
                self.type.pos)

        # name
        if not isinstance(param_list[2], expression.Identifier):
            raise generic.ScriptError(
                "random_switch parameter 3 'name' should be an identifier",
                pos)
        name = param_list[2]

        # triggers
        self.triggers = param_list[3] if len(
            param_list) == 4 else expression.ConstantNumeric(0)

        # body
        self.choices = []
        self.dependent = []
        self.independent = []
        for choice in choices:
            if isinstance(choice.probability, expression.Identifier):
                if choice.probability.value == "dependent":
                    self.dependent.append(choice.result)
                    continue
                elif choice.probability.value == "independent":
                    self.independent.append(choice.result)
                    continue
            self.choices.append(choice)
        if len(self.choices) == 0:
            raise generic.ScriptError(
                "random_switch requires at least one possible choice", pos)

        self.initialize(name, feature)
        self.random_act2 = None  # Set during action generation to resolve dependent/independent chains
示例#14
0
def parse_randomswitch(random_switch):
    """
    Parse a randomswitch block into actions

    @param random_switch: RandomSwitch block to parse
    @type random_switch: L{RandomSwitch}

    @return: List of actions
    @rtype: C{list} of L{BaseAction}
    """
    action_list = action2real.create_spriteset_actions(random_switch)
    feature = next(iter(random_switch.feature_set))
    type_byte, count, count_expr, start_bit, bits_available = parse_randomswitch_type(
        random_switch)

    total_prob = sum(choice.probability.value
                     for choice in random_switch.choices)
    assert total_prob > 0
    nrand = 1
    while nrand < total_prob:
        nrand <<= 1

    # Verify that enough random data is available
    if min(1 << bits_available, 0x80) < nrand:
        msg = "The maximum sum of all random_switch probabilities is {:d}, encountered {:d}."
        msg = msg.format(min(1 << bits_available, 0x80), total_prob)
        raise generic.ScriptError(msg, random_switch.pos)

    randbit, nrand = parse_randomswitch_dependencies(random_switch, start_bit,
                                                     bits_available, nrand)

    random_action2 = Action2Random(
        feature,
        random_switch.name.value,
        random_switch.pos,
        type_byte,
        count,
        random_switch.triggers.value,
        randbit,
        nrand,
    )
    random_switch.random_act2 = random_action2

    action6.free_parameters.save()
    act6 = action6.Action6()
    offset = 8 if count is not None else 7

    # divide the 'extra' probabilities in an even manner
    i = 0
    resulting_prob = {c: c.probability.value for c in random_switch.choices}
    while i < (nrand - total_prob):
        best_choice = None
        best_ratio = 0
        for choice in random_switch.choices:
            # float division, so 9 / 10 = 0.9
            ratio = choice.probability.value / float(resulting_prob[choice] +
                                                     1)
            if ratio > best_ratio:
                best_ratio = ratio
                best_choice = choice
        assert best_choice is not None
        resulting_prob[best_choice] += 1
        i += 1

    for choice in random_switch.choices:
        res_prob = resulting_prob[choice]
        result, comment = action2var.parse_result(
            choice.result.value,
            action_list,
            act6,
            offset,
            random_action2,
            None,
            0x8A if type_byte == 0x83 else 0x89,
            res_prob,
        )
        offset += res_prob * 2
        comment = "({:d}/{:d}) -> ({:d}/{:d}): ".format(
            choice.probability.value, total_prob, res_prob, nrand) + comment
        random_action2.choices.append(
            RandomAction2Choice(result, res_prob, comment))

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

    action_list.append(random_action2)
    if count_expr is None:
        random_switch.set_action2(random_action2, feature)
    else:
        # Create intermediate varaction2 to compute parameter for type 0x84
        varaction2 = action2var.Action2Var(
            feature, "{}@registers".format(random_switch.name.value),
            random_switch.pos, 0x89)
        varact2parser = action2var.Varaction2Parser(
            feature, action2var.get_scope(feature, 0x89))
        varact2parser.parse_expr(count_expr)
        varaction2.var_list = varact2parser.var_list
        action_list.extend(varact2parser.extra_actions)
        extra_act6 = action6.Action6()
        for mod in varact2parser.mods:
            extra_act6.modify_bytes(mod.param, mod.size, mod.offset + 4)
        if len(extra_act6.modifications) > 0:
            action_list.append(extra_act6)
        ref = expression.SpriteGroupRef(random_switch.name, [], None,
                                        random_action2)
        varaction2.ranges.append(
            action2var.VarAction2Range(expression.ConstantNumeric(0),
                                       expression.ConstantNumeric(0), ref, ""))
        varaction2.default_result = ref
        varaction2.default_comment = ""

        # Add two references (default + range)
        action2.add_ref(ref, varaction2)
        action2.add_ref(ref, varaction2)
        random_switch.set_action2(varaction2, feature)
        action_list.append(varaction2)

    action6.free_parameters.restore()
    return action_list