Example #1
0
File: action0.py Project: spnda/nml
def get_tracktypelist_action(table_prop_id, cond_tracktype_not_defined,
                             tracktype_list):
    action6.free_parameters.save()
    act6 = action6.Action6()

    action_list = []
    action0, offset = create_action0(0x08, expression.ConstantNumeric(0), act6,
                                     action_list)
    id_table = []
    offset += 1  # Skip property number
    for tracktype in tracktype_list:
        if isinstance(tracktype, expression.StringLiteral):
            id_table.append(tracktype)
            offset += 4
            continue
        param, extra_actions = actionD.get_tmp_parameter(
            expression.ConstantNumeric(
                expression.parse_string_to_dword(tracktype[-1])))
        action_list.extend(extra_actions)
        for idx in range(len(tracktype) - 2, -1, -1):
            val = expression.ConstantNumeric(
                expression.parse_string_to_dword(tracktype[idx]))
            action_list.append(
                action7.SkipAction(0x09, 0x00, 4,
                                   (cond_tracktype_not_defined, None),
                                   val.value, 1))
            action_list.append(
                actionD.ActionD(
                    expression.ConstantNumeric(param),
                    expression.ConstantNumeric(0xFF),
                    nmlop.ASSIGN,
                    expression.ConstantNumeric(0xFF),
                    val,
                ))
        act6.modify_bytes(param, 4, offset)
        id_table.append(expression.StringLiteral(r"\00\00\00\00", None))
        offset += 4
    action0.prop_list.append(IDListProp(table_prop_id, id_table))
    action0.num_ids = len(tracktype_list)

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

    action_list.append(action0)
    action6.free_parameters.restore()
    return action_list
Example #2
0
def parse_conditional_block(cond_list):
    global recursive_cond_blocks
    recursive_cond_blocks += 1
    if recursive_cond_blocks == 1:
        # We only save a single state (at toplevel nml-blocks) because
        # we don't know at the start of the block how many labels we need.
        # Getting the same label for a block that was already used in a
        # sub-block would be very bad, since the action7/9 would skip
        # to the action10 of the sub-block.
        free_labels.save()

    blocks = []
    for cond in cond_list.statements:
        if isinstance(cond.expr, expression.ConstantNumeric):
            if cond.expr.value == 0:
                continue
            else:
                blocks.append({"expr": None, "statements": cond.statements})
                break
        blocks.append({"expr": cond.expr, "statements": cond.statements})
    if blocks:
        blocks[-1]["last_block"] = True

    if len(blocks) == 1 and blocks[0]["expr"] is None:
        action_list = []
        for stmt in blocks[0]["statements"]:
            action_list.extend(stmt.get_action_list())
        return action_list

    action6.free_parameters.save()

    if len(blocks) > 1:
        # the skip all parameter is used to skip all blocks after one
        # of the conditionals was true. We can't always skip directly
        # to the end of the blocks since action7/action9 can't always
        # be mixed
        param_skip_all, action_list = actionD.get_tmp_parameter(
            expression.ConstantNumeric(0xFFFFFFFF))
    else:
        action_list = []

    # use parse_conditional here, we also need to know if all generated
    # actions (like action6) can be skipped safely
    for block in blocks:
        (
            block["param_dst"],
            block["cond_actions"],
            block["cond_type"],
            block["cond_value"],
            block["cond_value_size"],
        ) = parse_conditional(block["expr"])
        if "last_block" not in block:
            block["action_list"] = [
                actionD.ActionD(
                    # If this isn't the last block, len(blocks) > 1 so param_skip_all is initialized.
                    expression.ConstantNumeric(
                        param_skip_all
                    ),  # lgtm [py/uninitialized-local-variable]
                    expression.ConstantNumeric(0xFF),
                    nmlop.ASSIGN,
                    expression.ConstantNumeric(0),
                    expression.ConstantNumeric(0),
                )
            ]
        else:
            block["action_list"] = []
        for stmt in block["statements"]:
            block["action_list"].extend(stmt.get_action_list())

    # Main problem: action10 can't be skipped by action9, so we're
    # nearly forced to use action7, but action7 can't safely skip action6
    # Solution: use temporary parameter, set to 0 for not skip, !=0 for skip.
    # then skip every block of actions (as large as possible) with either
    # action7 or action9, depending on which of the two works.

    for i, block in enumerate(blocks):
        param = block["param_dst"]
        if i == 0:
            action_list.extend(block["cond_actions"])
        else:
            action_list.extend(
                cond_skip_actions(block["cond_actions"], param_skip_all,
                                  (2, r"\7="), 0, 4, cond_list.pos))
            if param is None:
                param = param_skip_all
            else:
                action_list.append(
                    actionD.ActionD(
                        expression.ConstantNumeric(block["param_dst"]),
                        expression.ConstantNumeric(block["param_dst"]),
                        nmlop.AND,
                        expression.ConstantNumeric(param_skip_all),
                    ))
        action_list.extend(
            cond_skip_actions(
                block["action_list"],
                param,
                block["cond_type"],
                block["cond_value"],
                block["cond_value_size"],
                cond_list.pos,
            ))

    if recursive_cond_blocks == 1:
        free_labels.restore()
    recursive_cond_blocks -= 1
    action6.free_parameters.restore()
    return action_list