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
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