Ejemplo n.º 1
0
Archivo: actionB.py Proyecto: 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
Ejemplo n.º 2
0
    def prepare_output(self, sprite_num):
        # Resolve references to earlier townname actions
        blocks = set()
        for part in self.parts:
            blocks.update(part.resolve_townname_id())

        # Allocate a number for this action F.
        if self.name is None or isinstance(self.name, expression.Identifier):
            self.id_number = get_free_id()
            if isinstance(self.name, expression.Identifier):
                if self.name.value in named_numbers:
                    raise generic.ScriptError(
                        'Cannot define town name "{}", it is already in use'.
                        format(self.name), self.pos)
                named_numbers[
                    self.name.
                    value] = self.id_number  # Add name to the set 'safe' names.
        else:
            numbered_numbers.add(
                self.id_number)  # Add number to the set of 'safe' numbers.

        # Ask existing action F for the lowest available bit.
        if len(town_names_blocks) == 0: startbit = 0
        else:
            startbit = max(block.free_bit
                           for block in town_names_blocks.values())

        town_names_blocks[
            self.id_number] = self  # Add self to the available blocks.

        # Allocate random bits to all parts.
        for part in self.parts:
            num_bits = part.assign_bits(startbit)
            # Prevent overlap if really needed
            if len(part.pieces) > 1: startbit += num_bits
        self.free_bit = startbit

        if startbit > 32:
            raise generic.ScriptError(
                "Not enough random bits for the town name generation ({:d} needed, 32 available)"
                .format(startbit), self.pos)

        # Pull style names if needed.
        if self.style_name is not None:
            grfstrings.validate_string(self.style_name)
            self.style_names = [
                (lang_id, grfstrings.get_translation(self.style_name, lang_id))
                for lang_id in grfstrings.get_translations(self.style_name)
            ]
            self.style_names.append(
                (0x7F, grfstrings.get_translation(self.style_name)))
            self.style_names.sort()
            if len(self.style_names) == 0:
                raise generic.ScriptError(
                    'Style "{}" defined, but no translations found for it'.
                    format(self.style_name.name.value), self.pos)
        else:
            self.style_names = []
Ejemplo n.º 3
0
Archivo: grf.py Proyecto: 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
Ejemplo n.º 4
0
def get_string_action4s(feature, string_range, string, id = None):
    """
    Let a string from the lang files be used in the rest of NML.
    This may involve adding actions directly, but otherwise an ID is allocated and the string will be written later

    @param feature: Feature that uses the string
    @type feature: C{int}

    @param string_range: String range to use, either a value from L{string_ranges} or C{None} if N/A (item names)
    @type string_range: C{int} or C{None}

    @param string: String to parse
    @type string: L{expression.String}

    @param id: ID to use for this string, or C{None} if it will be allocated dynamically (random_id is true for the string range)
    @type id: L{Expression} or C{None}

    @return: A tuple of two values:
                - ID of the string (useful if allocated dynamically)
                - Resulting action list to be appended
    @rtype: C{tuple} of (C{int}, C{list} of L{BaseAction})
    """
    grfstrings.validate_string(string)
    write_action4s = True
    action6.free_parameters.save()
    actions = []

    mod = None
    if string_range is not None:
        size = 2
        if string_ranges[string_range]['random_id']:
            # ID is allocated randomly, we will output the actions later
            write_action4s = False
            if (feature, string) in used_strings[string_range]:
                id_val = used_strings[string_range][(feature, string)]
            else:
                id_val = string_ranges[string_range]['ids'].pop()
                used_strings[string_range][(feature, string)] = id_val
        else:
            # ID must be supplied
            assert id is not None
            assert isinstance(id, expression.ConstantNumeric)
            id_val = id.value | (string_range << 8)
    else:
        # Not a string range, so we must have an id
        assert id is not None
        size = 3 if feature <= 3 else 1
        if isinstance(id, expression.ConstantNumeric):
            id_val = id.value
        else:
            id_val = 0
            tmp_param, tmp_param_actions = actionD.get_tmp_parameter(id)
            actions.extend(tmp_param_actions)
            # Apply ID via action4 later
            mod = (tmp_param, 2 if feature <= 3 else 1, 5 if feature <= 3 else 4)

    if write_action4s:
        strings = [(lang_id, grfstrings.get_translation(string, lang_id)) for lang_id in grfstrings.get_translations(string)]
        # Sort the strings for deterministic ordering and prepend the default language
        strings = [(0x7F, grfstrings.get_translation(string))] + sorted(strings, key=lambda lang_text: lang_text[0])

        for lang_id, text in strings:
            if mod is not None:
                act6 = action6.Action6()
                act6.modify_bytes(*mod)
                actions.append(act6)
            actions.append(Action4(feature, lang_id, size, id_val, [text]))

    action6.free_parameters.restore()

    return (id_val, actions)
Ejemplo n.º 5
0
 def __init__(self, id, string, skip_default_langid=False):
     Action14Node.__init__(self, "T", id)
     self.string = string
     grfstrings.validate_string(self.string)
     self.skip_default_langid = skip_default_langid
Ejemplo n.º 6
0
    def prepare_output(self, sprite_num):
        # Resolve references to earlier townname actions
        referenced_blocks = []
        for part in self.parts:
            part_blocks = part.resolve_townname_id()
            if part_blocks:
                referenced_blocks.append(part_blocks)

        # Allocate a number for this action F.
        if self.name is None or isinstance(self.name, expression.Identifier):
            self.id_number = get_free_id()
            if isinstance(self.name, expression.Identifier):
                if self.name.value in named_numbers:
                    raise generic.ScriptError(
                        'Cannot define town name "{}", it is already in use'.format(self.name), self.pos
                    )
                named_numbers[self.name.value] = self.id_number  # Add name to the set 'safe' names.
        else:
            numbered_numbers.add(self.id_number)  # Add number to the set of 'safe' numbers.

        town_names_blocks[self.id_number] = self  # Add self to the available blocks.

        def assign_bits(part, startbit):
            num_bits = part.assign_bits(startbit)
            # Prevent overlap if really needed
            if len(part.pieces) > 1:
                startbit += num_bits
            return startbit

        def update_block(block, startbit):
            for part in block.parts:
                startbit = assign_bits(part, startbit)
                # Update dependant Action F
                for dep in block.deps:
                    update_block(town_names_blocks[dep], startbit)
            return startbit

        # Determine lowest available bit, and prevent overlap when needed.
        # referenced_blocks is a list of sets, each set contains references that can share the same bits,
        # but different sets can't share bits.
        startbit = 0
        for part_blocks in referenced_blocks:
            freebit = startbit
            for part_block in part_blocks:
                block = town_names_blocks[part_block]
                startbit = max(startbit, update_block(block, freebit))
                if self.id_number not in block.deps:
                    block.deps.append(self.id_number)

        # Allocate random bits to all parts.
        for part in self.parts:
            startbit = assign_bits(part, startbit)

        if startbit > 32:
            raise generic.ScriptError(
                "Not enough random bits for the town name generation ({:d} needed, 32 available)".format(startbit),
                self.pos,
            )

        # Pull style names if needed.
        if self.style_name is not None:
            grfstrings.validate_string(self.style_name)
            self.style_names = [
                (lang_id, grfstrings.get_translation(self.style_name, lang_id))
                for lang_id in grfstrings.get_translations(self.style_name)
            ]
            self.style_names.append((0x7F, grfstrings.get_translation(self.style_name)))
            self.style_names.sort()
            if len(self.style_names) == 0:
                raise generic.ScriptError(
                    'Style "{}" defined, but no translations found for it'.format(self.style_name.name.value), self.pos
                )
        else:
            self.style_names = []