Example #1
0
    def preprocess_storageop(self, expr):
        assert isinstance(expr, expression.StorageOp)
        if expr.info["perm"] and not self.var_scope.has_persistent_storage:
            raise generic.ScriptError(
                "Persistent storage is not supported for feature '{}'".format(
                    self.var_scope.name),
                expr.pos,
            )

        if expr.info["store"]:
            op = nmlop.STO_PERM if expr.info["perm"] else nmlop.STO_TMP
            ret = expression.BinOp(op, expr.value, expr.register, expr.pos)
        else:
            var_num = 0x7C if expr.info["perm"] else 0x7D
            ret = expression.Variable(expression.ConstantNumeric(var_num),
                                      param=expr.register,
                                      pos=expr.pos)

        if expr.info[
                "perm"] and self.var_scope is action2var_variables.scope_towns:
            # store grfid in register 0x100 for town persistent storage
            grfid = expression.ConstantNumeric(
                0xFFFFFFFF if expr.grfid is None else expression.
                parse_string_to_dword(expr.grfid))
            store_op = nmlop.STO_TMP(grfid, 0x100, expr.pos)
            ret = nmlop.VAL2(store_op, ret)
        elif expr.grfid is not None:
            raise generic.ScriptError(
                "Specifying a grfid is only possible for town persistent storage.",
                expr.pos)
        return ret
Example #2
0
def finish_production_actions(produce, prod_action, action_list,
                              varact2parser):
    action_list.append(prod_action)

    if len(varact2parser.var_list) == 0:
        produce.set_action2(prod_action, 0x0A)
    else:
        # Create intermediate varaction2
        varaction2 = action2var.Action2Var(
            0x0A, "{}@registers".format(produce.name.value), produce.pos, 0x89)
        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(produce.name, [], None, prod_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)
        action2.add_ref(ref, varaction2)
        action2.add_ref(ref, varaction2)
        produce.set_action2(varaction2, 0x0A)
        action_list.append(varaction2)

    action6.free_parameters.restore()

    return action_list
Example #3
0
def adjust_value(value, org_value, unit, ottd_convert_func):
    """
    Make sure that the property value written to the NewGRF will match exactly
    the value as quoted

    @param value: The value to check, converted to base units
    @type value: L{Expression}

    @param org_value: The original value as written in the input file
    @type org_value: L{Expression}

    @param unit: The unit of the org_value
    @type unit: L{Unit} or C{None}

    @return: The adjusted value
    @rtype: L{Expression}
    """
    while ottd_convert_func(value, unit) > org_value.value:
        value = expression.ConstantNumeric(int(value.value - 1), value.pos)
    lower_value = value
    while ottd_convert_func(value, unit) < org_value.value:
        value = expression.ConstantNumeric(int(value.value + 1), value.pos)
    higher_value = value

    if abs(ottd_convert_func(lower_value, unit) - org_value.value) < abs(
            ottd_convert_func(higher_value, unit) - org_value.value):
        return lower_value
    return higher_value
Example #4
0
 def _validate_bounding_box(self, name, value):
     if self.type == Action2LayoutSpriteType.GROUND:
         raise generic.ScriptError(
             name + " can not be set for ground sprites", value.pos)
     elif self.type == Action2LayoutSpriteType.CHILD:
         if name not in ("xoffset", "yoffset"):
             raise generic.ScriptError(
                 name + " can not be set for child sprites", value.pos)
         if isinstance(value, expression.ConstantNumeric):
             generic.check_range(value.value, 0, 255, name, value.pos)
             return value
     else:
         assert self.type == Action2LayoutSpriteType.BUILDING
         if name in ("xoffset", "yoffset", "zoffset"):
             if isinstance(value, expression.ConstantNumeric):
                 generic.check_range(value.value, -128, 127, name,
                                     value.pos)
                 return value
         else:
             assert name in ("xextent", "yextent", "zextent")
             if not isinstance(value, expression.ConstantNumeric):
                 raise generic.ScriptError(
                     "Value of '{}' must be a compile-time constant number."
                     .format(name), value.pos)
             generic.check_range(value.value, 0, 255, name, value.pos)
             return value
     # Value must be written to a register
     self.create_register(name, value)
     if self.type == Action2LayoutSpriteType.BUILDING:
         # For building sprites, x and y registers are always written together
         if name == "xoffset" and self.get_register("yoffset") is None:
             self.create_register("yoffset", expression.ConstantNumeric(0))
         if name == "yoffset" and self.get_register("xoffset") is None:
             self.create_register("xoffset", expression.ConstantNumeric(0))
     return expression.ConstantNumeric(0)
Example #5
0
    def preprocess_storageop(self, expr):
        assert isinstance(expr, expression.StorageOp)
        if expr.info['perm'] and self.feature not in (0x08, 0x0A, 0x0D):
            raise generic.ScriptError(
                "Persistent storage is not supported for feature '{}'".format(
                    general.feature_name(self.feature)), expr.pos)

        if expr.info['store']:
            op = nmlop.STO_PERM if expr.info['perm'] else nmlop.STO_TMP
            ret = expression.BinOp(op, expr.value, expr.register, expr.pos)
        else:
            var_num = 0x7C if expr.info['perm'] else 0x7D
            ret = expression.Variable(expression.ConstantNumeric(var_num),
                                      param=expr.register,
                                      pos=expr.pos)

        if expr.info['perm'] and self.feature == 0x08:
            # store grfid in register 0x100 for town persistent storage
            grfid = expression.ConstantNumeric(
                0xFFFFFFFF if expr.grfid is None else expression.
                parse_string_to_dword(expr.grfid))
            store_op = expression.BinOp(nmlop.STO_TMP, grfid,
                                        expression.ConstantNumeric(0x100),
                                        expr.pos)
            ret = expression.BinOp(nmlop.VAL2, store_op, ret, expr.pos)
        elif expr.grfid is not None:
            raise generic.ScriptError(
                "Specifying a grfid is only possible for town persistent storage.",
                expr.pos)
        return ret
Example #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 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
Example #7
0
def get_volume_actions(volume_list):
    """
    Get a list of actions to set sound volumes

    @param volume_list: List of (sound id, volume) tuples, sorted in ascending order
    @type volume_list: C{list} of (C{int}, C{int})-tuples

    @return: A list of actions
    @rtype: C{list} of L{BaseAction}
    """
    action_list = []
    first_id = None  # First ID in a series of consecutive IDs
    value_series = []  # Series of values to write in a single action

    for id, volume in volume_list:
        if first_id is None:
            first_id = id
        continue_series = first_id + len(value_series) == id
        if continue_series:
            value_series.append(volume)

        if not continue_series or id == volume_list[-1][0]:
            # Write action for this series
            act0, offset = create_action0(0x0C, expression.ConstantNumeric(first_id), None, None)
            act0.num_ids = len(value_series)
            act0.prop_list.append(Action0Property(0x08, [expression.ConstantNumeric(v) for v in value_series], 1))
            action_list.append(act0)

            # start new series, if needed
            if not continue_series:
                first_id = id
                value_series = [volume]

    return action_list
Example #8
0
def parse_grm(assignment):
    assert isinstance(assignment.value, expression.GRMOp)

    action6.free_parameters.save()
    action_list = []
    act6 = action6.Action6()
    assert isinstance(assignment.param, expression.Parameter)
    target = assignment.param.num
    if isinstance(target, expression.Parameter) and isinstance(target.num, expression.ConstantNumeric):
        act6.modify_bytes(target.num.value, 1, 1)
        target = expression.ConstantNumeric(0)
    elif not isinstance(target, expression.ConstantNumeric):
        tmp_param, tmp_param_actions = get_tmp_parameter(target)
        act6.modify_bytes(tmp_param, 1, 1)
        target = expression.ConstantNumeric(0)
        action_list.extend(tmp_param_actions)

    op = nmlop.ASSIGN
    param1 = assignment.value.op
    param2 = expression.ConstantNumeric(0xFE)
    data = expression.ConstantNumeric(0xFF | (assignment.value.feature << 8) | (assignment.value.count << 16))

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

    action_list.append(ActionD(target, param1, op, param2, data))
    action6.free_parameters.restore()
    return action_list
Example #9
0
    def parse(self, expr):
        #Preprocess the expression
        if isinstance(expr, expression.SpecialParameter):
            #do this first, since it may evaluate to a BinOp
            expr = expr.to_reading()

        if isinstance(expr, expression.BinOp):
            expr = self.preprocess_binop(expr)

        elif isinstance(expr, expression.Boolean):
            expr = expression.BinOp(nmlop.MINU, expr.expr,
                                    expression.ConstantNumeric(1))

        elif isinstance(expr, expression.BinNot):
            expr = expression.BinOp(nmlop.XOR, expr.expr,
                                    expression.ConstantNumeric(0xFFFFFFFF))

        elif isinstance(
                expr,
                expression.TernaryOp) and not expr.supported_by_actionD(False):
            expr = self.preprocess_ternaryop(expr)

        elif isinstance(expr, expression.StorageOp):
            expr = self.preprocess_storageop(expr)

        #Try to parse the expression to a list of variables+operators
        if isinstance(expr, expression.ConstantNumeric):
            self.parse_constant(expr)

        elif isinstance(expr, expression.Parameter) and isinstance(
                expr.num, expression.ConstantNumeric):
            self.parse_param(expr)

        elif isinstance(expr, expression.Variable):
            self.parse_variable(expr)

        elif expr.supported_by_actionD(False):
            self.parse_via_actionD(expr)

        elif isinstance(expr, expression.BinOp):
            self.parse_binop(expr)

        elif isinstance(expr, expression.Not):
            self.parse_not(expr)

        elif isinstance(expr, expression.String):
            self.parse_string(expr)

        elif isinstance(expr,
                        (VarAction2LoadTempVar, VarAction2LoadLayoutParam)):
            self.var_list.append(expr)
            self.var_list_size += expr.get_size()

        elif isinstance(expr, expression.SpriteGroupRef):
            self.parse_proc_call(expr)

        else:
            expr.supported_by_action2(True)
            assert False  #supported_by_action2 should have raised the correct error already
Example #10
0
def parse_boolean(assignment):
    assert isinstance(assignment.value, expression.Boolean)
    actions = parse_actionD(ParameterAssignment(assignment.param, expression.ConstantNumeric(0)))
    expr = nmlop.CMP_NEQ(assignment.value.expr, 0)
    cond_block = conditional.Conditional(
        expr, [ParameterAssignment(assignment.param, expression.ConstantNumeric(1))], None
    )
    actions.extend(conditional.ConditionalList([cond_block]).get_action_list())
    return actions
Example #11
0
def industry_layout_count(name, args, pos, info):
    if len(args) < 2 or len(args) > 3:
        raise generic.ScriptError("'{}'() requires between 2 and 3 argument(s), encountered {:d}".format(name, len(args)), pos)

    grfid = expression.ConstantNumeric(0xFFFFFFFF) if len(args) == 2 else args[2]

    extra_params = []
    extra_params.append( (0x100, grfid) )
    extra_params.append( (0x101, expression.BinOp(nmlop.AND, args[1], expression.ConstantNumeric(0xFF)).reduce()) )
    return (args[0], extra_params)
Example #12
0
def industry_town_count(name, args, pos, info):
    if len(args) < 1 or len(args) > 2:
        raise generic.ScriptError("'{}'() requires between 1 and 2 argument(s), encountered {:d}".format(name, len(args)), pos)

    grfid = expression.ConstantNumeric(0xFFFFFFFF) if len(args) == 1 else args[1]

    extra_params = []
    extra_params.append( (0x100, grfid) )
    extra_params.append( (0x101, expression.ConstantNumeric(0x0100)) )
    return (args[0], extra_params)
Example #13
0
def parse_var(info, pos):
    param = expression.ConstantNumeric(
        info['param']) if 'param' in info else None
    res = expression.Variable(
        expression.ConstantNumeric(info['var']),
        expression.ConstantNumeric(info['start']),
        expression.ConstantNumeric((1 << info['size']) - 1), param, pos)
    if 'value_function' in info:
        return info['value_function'](res, info)
    return res
Example #14
0
def parse_hasbit(assignment):
    assert isinstance(assignment.value, expression.BinOp) and (
        assignment.value.op == nmlop.HASBIT or assignment.value.op == nmlop.NOTHASBIT
    )
    actions = parse_actionD(ParameterAssignment(assignment.param, expression.ConstantNumeric(0)))
    cond_block = conditional.Conditional(
        assignment.value, [ParameterAssignment(assignment.param, expression.ConstantNumeric(1))], None
    )
    actions.extend(conditional.ConditionalList([cond_block]).get_action_list())
    return actions
Example #15
0
def cargo_profit_value(value):
    # In NFO, calculation is (amount * price_factor * cb_result) / 8192
    # Units of the NML price factor differ by about 41.12, i.e. 1 NML unit = 41 NFO units
    # That'd make the formula (amount * price_factor * cb_result) / (8192 / 41)
    # This is almost (error 0.01%) equivalent to the following, which is what this calculation does
    # (amount * price_factor * (cb_result * 329 / 256)) / 256
    # This allows us to report a factor of 256 in the documentation, which makes a lot more sense than 199.804...
    # Not doing the division here would improve accuracy, but limits the range of the return value too much
    value = expression.BinOp(nmlop.MUL, value, expression.ConstantNumeric(329),
                             value.pos)
    return expression.BinOp(nmlop.DIV, value, expression.ConstantNumeric(256),
                            value.pos)
Example #16
0
def parse_var(name, info, pos):
    if "replaced_by" in info:
        generic.print_warning("'{}' is deprecated, consider using '{}' instead".format(name, info["replaced_by"]), pos)
    param = expression.ConstantNumeric(info["param"]) if "param" in info else None
    res = expression.Variable(
        expression.ConstantNumeric(info["var"]),
        expression.ConstantNumeric(info["start"]),
        expression.ConstantNumeric((1 << info["size"]) - 1),
        param,
        pos,
    )
    if "value_function" in info:
        return info["value_function"](res, info)
    return res
Example #17
0
 def validate_size(self):
     """
     Check if xpos/ypos/xsize/ysize are already set and if not, set them
     to 0,0,image_width,image_height.
     """
     if self.xpos is None:
         with Image.open(generic.find_file(self.file.value)) as im:
             self.xpos = expression.ConstantNumeric(0)
             self.ypos = expression.ConstantNumeric(0)
             self.xsize = expression.ConstantNumeric(im.size[0])
             self.ysize = expression.ConstantNumeric(im.size[1])
             self.check_sprite_size()
     if self.mask_pos is None:
         self.mask_pos = (self.xpos, self.ypos)
Example #18
0
def tile_offset(name, args, pos, info, min, max):
    if len(args) != 2:
        raise generic.ScriptError("'{}'() requires 2 arguments, encountered {:d}".format(name, len(args)), pos)
    for arg in args:
        if isinstance(arg, expression.ConstantNumeric):
            generic.check_range(arg.value, min, max, "Argument of '{}'".format(name), arg.pos)

    x = expression.BinOp(nmlop.AND, args[0], expression.ConstantNumeric(0xF), args[0].pos)
    y = expression.BinOp(nmlop.AND, args[1], expression.ConstantNumeric(0xF), args[1].pos)
    # Shift y left by four
    y = expression.BinOp(nmlop.SHIFT_LEFT, y, expression.ConstantNumeric(4), y.pos)
    param = expression.BinOp(nmlop.ADD, x, y, x.pos)
    #Make sure to reduce the result
    return ( param.reduce(), [] )
Example #19
0
def parse_var(name, info, pos):
    if 'replaced_by' in info:
        generic.print_warning(
            "'{}' is deprecated, consider using '{}' instead".format(
                name, info['replaced_by']), pos)
    param = expression.ConstantNumeric(
        info['param']) if 'param' in info else None
    res = expression.Variable(
        expression.ConstantNumeric(info['var']),
        expression.ConstantNumeric(info['start']),
        expression.ConstantNumeric((1 << info['size']) - 1), param, pos)
    if 'value_function' in info:
        return info['value_function'](res, info)
    return res
Example #20
0
def nearest_house_matching_criterion(name, args, pos, info):
    # nearest_house_matching_criterion(radius, criterion)
    # parameter is radius | (criterion << 6)
    if len(args) != 2:
        raise generic.ScriptError("{}() requires 2 arguments, encountered {:d}".format(name, len(args)), pos)
    if isinstance(args[0], expression.ConstantNumeric):
        generic.check_range(args[0].value, 1, 63, "{}()-parameter 1 'radius'".format(name), pos)
    if isinstance(args[1], expression.ConstantNumeric) and args[1].value not in (0, 1, 2):
        raise generic.ScriptError("Invalid value for {}()-parameter 2 'criterion'".format(name), pos)

    radius = expression.BinOp(nmlop.AND, args[0], expression.ConstantNumeric(0x3F, pos), pos)
    criterion = expression.BinOp(nmlop.AND, args[1], expression.ConstantNumeric(0x03, pos), pos)
    criterion = expression.BinOp(nmlop.MUL, criterion, expression.ConstantNumeric(0x40, pos), pos)
    retval = expression.BinOp(nmlop.OR, criterion, radius, pos).reduce()
    return (retval, [])
Example #21
0
    def parse_binop(self, expr):
        if expr.op.act2_num is None:
            expr.supported_by_action2(True)

        if (isinstance(expr.expr2,
                       (expression.ConstantNumeric, expression.Variable))
                or isinstance(expr.expr2,
                              (VarAction2LoadTempVar, VarAction2LoadCallParam))
                or (isinstance(expr.expr2, expression.Parameter)
                    and isinstance(expr.expr2.num, expression.ConstantNumeric))
                or expr.op == nmlop.VAL2):
            expr2 = expr.expr2
        elif expr.expr2.supported_by_actionD(False):
            tmp_param, tmp_param_actions = actionD.get_tmp_parameter(
                expr.expr2)
            self.extra_actions.extend(tmp_param_actions)
            expr2 = expression.Parameter(expression.ConstantNumeric(tmp_param))
        else:
            # The expression is so complex we need to compute it first, store the
            # result and load it back later.
            self.parse(expr.expr2)
            tmp_var = VarAction2StoreTempVar()
            self.var_list.append(nmlop.STO_TMP)
            self.var_list.append(tmp_var)
            self.var_list.append(nmlop.VAL2)
            # the +2 is for both operators
            self.var_list_size += tmp_var.get_size() + 2
            expr2 = VarAction2LoadTempVar(tmp_var)

        # parse expr1
        self.parse(expr.expr1)
        self.var_list.append(expr.op)
        self.var_list_size += 1

        self.parse(expr2)
Example #22
0
def get_callback_flags_actions(feature, id, flags):
    """
    Get a list of actions to set the callback flags of a certain item

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

    @param id: ID of the item
    @type id: L{Expression}

    @param flags: Value of the 'callback_flags' property
    @type flags: C{int}

    @return: A list of actions
    @rtype: C{list} of L{BaseAction}
    """
    assert isinstance(id, expression.ConstantNumeric)
    act0, offset = create_action0(feature, id, None, None)
    act0.num_ids = 1
    assert feature in callback_flag_properties

    prop_info_list = callback_flag_properties[feature]
    if not isinstance(prop_info_list, list): prop_info_list = [prop_info_list]
    for prop_info in prop_info_list:
        act0.prop_list.append(
            Action0Property(
                prop_info['num'],
                parse_property_value(prop_info,
                                     expression.ConstantNumeric(flags)),
                prop_info['size']))

    return [act0]
Example #23
0
def create_proc_call_varaction2(feature, proc, ret_value_function, 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})
    """
    varact2parser = action2var.Varaction2Parser(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)
    comment = result.name.value + ';'
    return (action_list, result, comment)
Example #24
0
def parse_graphics_block(graphics_block, feature, id, size, is_livery_override = False):
    """
    Parse a graphics block (or livery override) into a list of actions, mainly action3

    @param graphics_block: Graphics-block to parse
    @type graphics_block: L{GraphicsBlock}

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

    @param id: ID of the associated item
    @type id: L{Expression}

    @param size: Size of the associated item (relevant for houses only)
    @type size: L{ConstantNumeric} or C{None}

    @param is_livery_override: Whether this is a livery override instead of a normal graphics block
    @type is_livery_override: C{bool}

    @return: The resulting list of actions
    @rtype: L{BaseAction}
    """
    action_list = action2real.create_spriteset_actions(graphics_block)
    if feature == 0x07:
        # Multi-tile houses need more work
        size_bit = size.value if size is not None else 0
        for i, tile in enumerate(house_tiles[size_bit]):
            tile_id = id if i == 0 else expression.BinOp(nmlop.ADD, id, expression.ConstantNumeric(i, id.pos), id.pos).reduce()
            action_list.extend(parse_graphics_block_single_id(graphics_block, feature, tile_id, is_livery_override, tile, id))
    else:
        action_list.extend(parse_graphics_block_single_id(graphics_block, feature, id, is_livery_override))
    return action_list
Example #25
0
def get_disable_actions(disable):
    """
    Get the action list for a disable_item block

    @param disable: Disable block
    @type disable: L{DisableItem}

    @return: A list of resulting actions
    @rtype: C{list} of L{BaseAction}
    """
    feature = disable.feature.value
    if feature not in disable_info:
        raise generic.ScriptError("disable_item() is not available for feature {:d}.".format(feature), disable.pos)
    if disable.first_id is None:
        # No ids set -> disable all
        assert disable.last_id is None
        first = 0
        num = disable_info[feature]["num"]
    else:
        first = disable.first_id.value
        if disable.last_id is None:
            num = 1
        else:
            num = disable.last_id.value - first + 1

    act0 = Action0(feature, first)
    act0.num_ids = num
    for prop in disable_info[feature]["props"]:
        act0.prop_list.append(
            Action0Property(prop["num"], num * [expression.ConstantNumeric(prop["value"])], prop["size"])
        )

    return [act0]
Example #26
0
File: grf.py Project: stormcone/nml
    def pre_process(self):
        if None in (self.name, self.desc, self.grfid, self.version, self.min_compatible_version):
            raise generic.ScriptError("A GRF-block requires the 'name', 'desc', 'grfid', 'version' and 'min_compatible_version' properties to be set.", self.pos)

        self.grfid = self.grfid.reduce()
        global_constants.constant_numbers['GRFID'] = expression.parse_string_to_dword(self.grfid)
        self.name = self.name.reduce()
        if not isinstance(self.name, expression.String):
            raise generic.ScriptError("GRF-name must be a string", self.name.pos)
        grfstrings.validate_string(self.name)
        self.desc = self.desc.reduce()
        if not isinstance(self.desc, expression.String):
            raise generic.ScriptError("GRF-description must be a string", self.desc.pos)
        grfstrings.validate_string(self.desc)
        if self.url is not None:
            self.url = self.url.reduce()
            if not isinstance(self.url, expression.String):
                raise generic.ScriptError("URL must be a string", self.url.pos)
            grfstrings.validate_string(self.url)
        self.version = self.version.reduce_constant()
        self.min_compatible_version = self.min_compatible_version.reduce_constant()

        global param_stats

        param_num = 0
        for param in self.params:
            param.pre_process(expression.ConstantNumeric(param_num))
            param_num = param.num.value + 1
            if param_num > param_stats[1]:
                raise generic.ScriptError("No free parameters available. Consider assigning <num> manually and combine multiple bool parameters into a single bitmask parameter using <bit>.", self.pos)
            if param_num > param_stats[0]:
                param_stats[0] = param_num
Example #27
0
File: item.py Project: spnda/nml
    def register_names(self):
        if self.name:
            if not isinstance(self.name, expression.Identifier):
                raise generic.ScriptError(
                    "Item parameter 2 'name' should be an identifier",
                    self.pos)
            if self.name.value in global_constants.item_names:
                existing_id = global_constants.item_names[self.name.value].id
                if self.id is not None and existing_id.value != self.id.value:
                    raise generic.ScriptError(
                        ("Duplicate item with name '{}'."
                         " This item has already been assigned to id {:d}, cannot reassign to id {:d}"
                         ).format(self.name.value, existing_id.value,
                                  self.id.value),
                        self.pos,
                    )
                self.id = existing_id

        # We may have to reserve multiple item IDs for houses
        num_ids = action0.house_sizes[
            self.size.value] if self.size is not None else 1
        if self.id is None:
            self.id = expression.ConstantNumeric(
                action0.get_free_id(self.feature.value, num_ids, self.pos))
        elif not action0.check_id_range(self.feature.value, self.id.value,
                                        num_ids, self.id.pos):
            action0.mark_id_used(self.feature.value, self.id.value, num_ids)
        if self.name is not None:
            global_constants.item_names[self.name.value] = self
        base_statement.BaseStatementList.register_names(self)
Example #28
0
def parse_special_check(assignment):
    check = assignment.value
    assert isinstance(check, expression.SpecialCheck)
    actions = parse_actionD(ParameterAssignment(assignment.param, expression.ConstantNumeric(check.results[0])))

    value = check.value
    if check.mask is not None:
        value &= check.mask
        value += check.mask << 32
        assert check.varsize == 8
    else:
        assert check.varsize <= 4
    actions.append(action7.SkipAction(9, check.varnum, check.varsize, check.op, value, 1))

    actions.extend(parse_actionD(ParameterAssignment(assignment.param, expression.ConstantNumeric(check.results[1]))))
    return actions
Example #29
0
File: actionB.py Project: spnda/nml
def parse_error_block(error):
    action6.free_parameters.save()
    action_list = []
    act6 = action6.Action6()

    severity = actionD.write_action_value(error.severity, action_list, act6, 1,
                                          1)[0]

    langs = [0x7F]
    if isinstance(error.msg, expression.String):
        custom_msg = True
        msg_string = error.msg
        grfstrings.validate_string(msg_string)
        langs.extend(grfstrings.get_translations(msg_string))
        for lang in langs:
            assert lang is not None
    else:
        custom_msg = False
        msg = error.msg.reduce_constant().value

    if error.data is not None:
        error.data = error.data.reduce()
        if isinstance(error.data, expression.String):
            grfstrings.validate_string(error.data)
            langs.extend(grfstrings.get_translations(error.data))
            for lang in langs:
                assert lang is not None
        elif not isinstance(error.data, expression.StringLiteral):
            raise generic.ScriptError(
                "Error parameter 3 'data' should be the identifier of a custom sting",
                error.data.pos)

    params = []
    for expr in error.params:
        if isinstance(expr, expression.Parameter) and isinstance(
                expr.num, expression.ConstantNumeric):
            params.append(expr.num)
        else:
            tmp_param, tmp_param_actions = actionD.get_tmp_parameter(expr)
            action_list.extend(tmp_param_actions)
            params.append(expression.ConstantNumeric(tmp_param))

    langs = list(set(langs))
    langs.sort()
    for lang in langs:
        if custom_msg:
            msg = grfstrings.get_translation(msg_string, lang)
        if error.data is None:
            data = None
        elif isinstance(error.data, expression.StringLiteral):
            data = error.data.value
        else:
            data = grfstrings.get_translation(error.data, lang)
        if len(act6.modifications) > 0:
            action_list.append(act6)
        action_list.append(ActionB(severity, lang, msg, data, params))

    action6.free_parameters.restore()
    return action_list
Example #30
0
File: action0.py Project: spnda/nml
def get_snowlinetable_action(snowline_table):
    assert len(snowline_table) == 12 * 32

    action6.free_parameters.save()
    action_list = []
    tmp_param_map = {}  # Cache for tmp parameters
    act6 = action6.Action6()

    act0, offset = create_action0(0x08, expression.ConstantNumeric(0), act6,
                                  action_list)
    act0.num_ids = 1
    offset += 1  # Skip property number

    data_table = []
    idx = 0
    while idx < len(snowline_table):
        val = snowline_table[idx]
        if isinstance(val, expression.ConstantNumeric):
            data_table.append(val.value)
            idx += 1
            continue

        if idx + 3 >= len(snowline_table):
            tmp_param, tmp_param_actions = actionD.get_tmp_parameter(val)
            tmp_param_map[val] = tmp_param
            act6.modify_bytes(tmp_param, 1, offset + idx)
            action_list.extend(tmp_param_actions)
            data_table.append(0)
            idx += 1
            continue

        # Merge the next 4 values together in a single parameter.
        val2 = nmlop.SHIFT_LEFT(snowline_table[idx + 1], 8)
        val3 = nmlop.SHIFT_LEFT(snowline_table[idx + 2], 16)
        val4 = nmlop.SHIFT_LEFT(snowline_table[idx + 3], 24)
        expr = nmlop.OR(val, val2)
        expr = nmlop.OR(expr, val3)
        expr = nmlop.OR(expr, val4)
        expr = expr.reduce()

        # Cache lookup, saves some ActionDs
        if expr in tmp_param_map:
            tmp_param, tmp_param_actions = tmp_param_map[expr], []
        else:
            tmp_param, tmp_param_actions = actionD.get_tmp_parameter(expr)
            tmp_param_map[expr] = tmp_param

        act6.modify_bytes(tmp_param, 4, offset + idx)
        action_list.extend(tmp_param_actions)
        data_table.extend([0, 0, 0, 0])
        idx += 4

    act0.prop_list.append(
        ByteListProp(0x10, "".join([chr(x) for x in data_table])))
    if len(act6.modifications) > 0:
        action_list.append(act6)
    action_list.append(act0)
    action6.free_parameters.restore()
    return action_list