Esempio n. 1
0
    def parse_global(self, key, chance, xor, all_fields, index):
        """
        Add a global chance for properties.

        This is where multiple properties can be triggered by a chance, like

        10% Chance for one of the following:
            - ...
            - ...
        """
        # Grab the value for this index from the global stores:
        fields = dict((k, v[index]) if index < len(v)
                      # If this value isn't repeated, grab the last value
                      else (k, v[-1]) for k, v in all_fields.items())

        # Check if the XOR was set for any field:
        if xor:
            value = {
                'chance': (texts.get(GLOBAL_XOR_ALL) if chance == 100 else
                           texts.get(GLOBAL_XOR_PCT).format(chance)),
                'properties':
                fields,
            }
        else:
            value = {
                'chance': (texts.get(GLOBAL_ALL).format('') if chance == 100
                           else texts.get(GLOBAL_PCT).format(chance)),
                'properties':
                fields,
            }

        # Insert the value normally
        TQDBParser.insert_value(key, value, self.result)
Esempio n. 2
0
    def parse_field(self, field, dbr, result):
        """
        Parse all values for a given character field that is in the DBR.

        """
        for value in dbr[field]:
            # Skip 0 values
            if not value:
                continue

            formatted = texts.get(field).format(value)
            TQDBParser.insert_value(field, formatted, result)
Esempio n. 3
0
    def parse_field(self, field, dbr, result):
        """
        Parse all values for a given character field that is in the DBR.

        """
        for value in dbr[field]:
            # Skip 0 values
            if not value:
                continue

            formatted = texts.get(field).format(value)
            TQDBParser.insert_value(field, formatted, result)
Esempio n. 4
0
    def parse_modifier(self, field, field_type, dbr):
        """
        Parse a percentage increase in an offensive attribute.

        """
        field_mod = f'{field}Modifier'

        chance = dbr.get(f'{field_mod}Chance', 0)
        mod = dbr.get(field_mod, 0)
        is_xor = dbr.get(f'{field}XOR', False)
        is_global = dbr.get(f'{field}Global', False)

        # Optional pre/suffix for chance and duration damage/effects:
        prefix = ''
        suffix = ''

        if field_type in [self.DOT, self.EOT]:
            # Add the possible duration field:
            duration_mod = dbr.get(f'{field}DurationModifier', 0)

            if duration_mod:
                suffix = texts.get(IMPRV_TIME).format(duration_mod)

        value = texts.get(field_mod).format(mod)
        if chance and not is_xor:
            prefix = texts.get(CHANCE).format(chance)

        if not is_global:
            # Insert the value normally
            TQDBParser.insert_value(
                field_mod,
                f'{prefix}{value}{suffix}',
                self.result)
        elif field.startswith('offensive'):
            # Add this field to the global offensive list
            self.offensive[field_mod] = (
                [f'{prefix}{value}{suffix}']
                if field_mod not in self.offensive
                else self.offensive[field_mod] + [f'{prefix}{value}{suffix}']
            )
        elif field.startswith('retaliation'):
            # Add this field to the global retaliation list
            self.retaliation[field_mod] = (
                [f'{prefix}{value}{suffix}']
                if field_mod not in self.retaliation
                else self.retaliation[field_mod] + [f'{prefix}{value}{suffix}']
            )
Esempio n. 5
0
    def parse_modifier(self, field, field_type, dbr):
        """
        Parse a percentage increase in an offensive attribute.

        """
        field_mod = f'{field}Modifier'

        chance = dbr.get(f'{field_mod}Chance', 0)
        mod = dbr.get(field_mod, 0)
        is_xor = dbr.get(f'{field}XOR', False)
        is_global = dbr.get(f'{field}Global', False)

        # Optional pre/suffix for chance and duration damage/effects:
        prefix = ''
        suffix = ''

        if field_type in [self.DOT, self.EOT]:
            # Add the possible duration field:
            duration_mod = dbr.get(f'{field}DurationModifier', 0)

            if duration_mod:
                suffix = texts.get(IMPRV_TIME).format(duration_mod)

        value = texts.get(field_mod).format(mod)
        if chance and not is_xor:
            prefix = texts.get(CHANCE).format(chance)

        if not is_global:
            # Insert the value normally
            TQDBParser.insert_value(field_mod, f'{prefix}{value}{suffix}',
                                    self.result)
        elif field.startswith('offensive'):
            # Add this field to the global offensive list
            self.offensive[field_mod] = ([f'{prefix}{value}{suffix}']
                                         if field_mod not in self.offensive
                                         else self.offensive[field_mod] +
                                         [f'{prefix}{value}{suffix}'])
        elif field.startswith('retaliation'):
            # Add this field to the global retaliation list
            self.retaliation[field_mod] = ([f'{prefix}{value}{suffix}']
                                           if field_mod not in self.retaliation
                                           else self.retaliation[field_mod] +
                                           [f'{prefix}{value}{suffix}'])
Esempio n. 6
0
    def parse_global(self, key, chance, xor, all_fields, index):
        """
        Add a global chance for properties.

        This is where multiple properties can be triggered by a chance, like

        10% Chance for one of the following:
            - ...
            - ...
        """
        # Grab the value for this index from the global stores:
        fields = dict(
            (k, v[index])
            if index < len(v)
            # If this value isn't repeated, grab the last value
            else (k, v[-1])
            for k, v in all_fields.items())

        # Check if the XOR was set for any field:
        if xor:
            value = {
                'chance': (
                    texts.get(GLOBAL_XOR_ALL)
                    if chance == 100
                    else texts.get(GLOBAL_XOR_PCT).format(chance)),
                'properties': fields,
            }
        else:
            value = {
                'chance': (
                    texts.get(GLOBAL_ALL).format('')
                    if chance == 100
                    else texts.get(GLOBAL_PCT).format(chance)),
                'properties': fields,
            }

        # Insert the value normally
        TQDBParser.insert_value(key, value, self.result)
Esempio n. 7
0
    def parse_field(self, field, dbr, result):
        """
        Parse all values for a given racial bonus field that is in the DBR.

        """
        if field not in dbr:
            return

        races = []
        for race in dbr[self.RACE]:
            if race == 'Beastman':
                races.append('Beastmen')
            elif race != 'Undead' and race != 'Magical':
                races.append(race + 's')
            else:
                races.append(race)

        for value in dbr[field]:
            TQDBParser.insert_value(
                field,
                # Create a list of all racial bonuses
                [texts.get(field).format(value, race) for race in races],
                result)
Esempio n. 8
0
    def parse_field(self, field, dbr, result):
        """
        Parse all values for a given racial bonus field that is in the DBR.

        """
        if field not in dbr:
            return

        races = []
        for race in dbr[self.RACE]:
            if race == 'Beastman':
                races.append('Beastmen')
            elif race != 'Undead' and race != 'Magical':
                races.append(race + 's')
            else:
                races.append(race)

        for value in dbr[field]:
            TQDBParser.insert_value(
                field,
                # Create a list of all racial bonuses
                [texts.get(field).format(value, race) for race in races],
                result)
Esempio n. 9
0
    def parse_field(self, field, dbr, result):
        """
        Parse all values for a given defensive field that is in the DBR.

        """
        for i in range(len(dbr[field])):
            iteration = TQDBParser.extract_values(dbr, field, i)

            # It's possible some values aren't set in this iteration:
            if field not in iteration:
                continue

            chance = iteration.get(f'{field}Chance', 0)
            value = iteration[field]

            # Format the value using the texts:
            formatted = texts.get(field).format(value)

            # Prepend a chance if it's set:
            if chance:
                formatted = texts.get(CHANCE).format(chance) + formatted

            TQDBParser.insert_value(field, formatted, result)
Esempio n. 10
0
    def parse_field(self, field, dbr, result):
        """
        Parse all values for a given defensive field that is in the DBR.

        """
        for i in range(len(dbr[field])):
            iteration = TQDBParser.extract_values(dbr, field, i)

            # It's possible some values aren't set in this iteration:
            if field not in iteration:
                continue

            chance = iteration.get(f'{field}Chance', 0)
            value = iteration[field]

            # Format the value using the texts:
            formatted = texts.get(field).format(value)

            # Prepend a chance if it's set:
            if chance:
                formatted = texts.get(CHANCE).format(chance) + formatted

            TQDBParser.insert_value(field, formatted, result)
Esempio n. 11
0
    def parse(self, dbr, dbr_file, result):
        """
        Parse skill properties.

        """
        for field in self.FIELDS:
            if field not in dbr:
                continue

            # Now iterate as many times as is necessary for this field:
            for index, value in enumerate(dbr[field]):
                # Skip any field that has a negligible value
                if value <= 0.01:
                    continue

                formatted = texts.get(field).format(value)

                # Grab the chance and add a prefix with it:
                if f'{field}Chance' in dbr:
                    chance = dbr[f'{field}Chance'][index]
                    formatted = texts.get(CHANCE).format(chance) + formatted

                # Insert the value:
                TQDBParser.insert_value(field, formatted, result)
Esempio n. 12
0
    def parse(self, dbr, dbr_file, result):
        """
        Parse skill properties.

        """
        for field in self.FIELDS:
            if field not in dbr:
                continue

            # Now iterate as many times as is necessary for this field:
            for index, value in enumerate(dbr[field]):
                # Skip any field that has a negligible value
                if value <= 0.01:
                    continue

                formatted = texts.get(field).format(value)

                # Grab the chance and add a prefix with it:
                if f'{field}Chance' in dbr:
                    chance = dbr[f'{field}Chance'][index]
                    formatted = texts.get(CHANCE).format(chance) + formatted

                # Insert the value:
                TQDBParser.insert_value(field, formatted, result)
Esempio n. 13
0
    def parse(self, dbr, dbr_file, result):
        """
        Parse the skill that spawns a pet.

        """
        # Only set time to live it's set (otherwise it's infinite)
        ttl_list = dbr.get(self.TTL, None)

        # Parse all the summons and set them as a list:
        result['summons'] = []
        for index, spawn_file in enumerate(dbr['spawnObjects']):
            spawn = DBRParser.parse(spawn_file)

            # Keep track of the original properties this summon had:
            original_properties = {}
            if 'properties' in spawn:
                if isinstance(spawn['properties'], list):
                    original_properties = spawn['properties'][0].copy()
                else:
                    original_properties = spawn['properties'].copy()

            # We need the raw values from the spawn DBR for hp/mp
            spawn['properties'] = {}
            spawn_dbr = DBRParser.read(spawn_file)

            if 'characterLife' in spawn_dbr:
                hp_list = spawn_dbr['characterLife']
                hp = (hp_list[index]
                      if index < len(hp_list) else hp_list[len(hp_list) - 1])
                TQDBParser.insert_value('characterLife',
                                        texts.get('LifeText').format(hp),
                                        spawn)
            if 'characterMana' in spawn_dbr:
                mp_list = spawn_dbr['characterMana']
                mp = (mp_list[index]
                      if index < len(mp_list) else mp_list[len(mp_list) - 1])
                TQDBParser.insert_value('characterMana',
                                        texts.get('ManaText').format(mp),
                                        spawn)
            if ttl_list:
                ttl = (ttl_list[index] if index < len(ttl_list) else
                       ttl_list[len(ttl_list) - 1])
                TQDBParser.insert_value(self.TTL,
                                        texts.get(self.TTL).format(ttl), spawn)

            # Iterate over the original properties and add some whitelisted
            # properties to the final result:
            for key, value in original_properties.items():
                if key.startswith('character'):
                    continue
                spawn['properties'][key] = value

            result['summons'].append(spawn)
Esempio n. 14
0
    def parse_flat(self, field, field_type, dbr):
        """
        Parse a flat increase in an offensive attribute.

        """
        # Prepare some keys that will determine the flat or flat range:
        chance = dbr.get(f'{field}Chance', 0)
        min = dbr.get(f'{field}Min', 0)
        max = dbr.get(f'{field}Max', min)
        is_xor = dbr.get(f'{field}XOR', False)
        is_global = dbr.get(f'{field}Global', False)

        # Optional pre/suffix for chance and duration damage/effects:
        prefix = ''
        suffix = ''

        if field_type == self.MANA:
            # The mana burn suffixes are kind of derpy:
            chance = dbr.get('offensiveManaBurnChance', 0)
            min = dbr.get('offensiveManaBurnDrainMin', 0)
            max = dbr.get('offensiveManaBurnDrainMax', 0)
            is_xor = dbr.get(f'{field}XOR', False)
            ratio = dbr.get('offensiveManaBurnDamageRatio', 0)

            if ratio:
                suffix = texts.get('offensiveManaBurnRatio').format(ratio)

            # Reset the field to what's used in texts.
            field = 'offensiveManaDrain'
        elif field_type == self.DOT:
            duration_min = dbr.get(f'{field}DurationMin', 0)
            duration_max = dbr.get(f'{field}DurationMax', 0)

            if duration_min:
                min *= duration_min
                suffix = texts.get(DOT_SINGLE).format(duration_min)

                if duration_max and max == min:
                    max = min * duration_max
                elif max:
                    max *= duration_min
        elif field_type == self.EOT:
            duration_min = dbr.get(f'{field}DurationMin', 0)

            if duration_min:
                suffix = texts.get(DFT_SINGLE).format(duration_min)

        # Pierce ratio is a singular exception for flat properties:
        if field == 'offensivePierceRatio':
            # Pierce ratio already has its formatter in the flat property:
            # "{0:.0f}% Pierce Ratio" instead of "% Pierce Ratio"
            value = texts.get(field).format(min)
        else:
            # Format the value based on its field type and values:
            value = self.format(field_type, field, min, max)

        if chance and not is_xor:
            prefix = texts.get(CHANCE).format(chance)

        if not is_global:
            # Insert the value normally
            TQDBParser.insert_value(
                field,
                f'{prefix}{value}{suffix}',
                self.result)
        elif field.startswith('offensive'):
            # Add this field to the global offensive list
            self.offensive[field] = (
                [f'{prefix}{value}{suffix}']
                if field not in self.offensive
                else self.offensive[field] + [f'{prefix}{value}{suffix}'])
            if is_xor:
                self.offensiveXOR = True
        elif field.startswith('retaliation'):
            # Add this field to the global retaliation list
            self.retaliation[field] = (
                [f'{prefix}{value}{suffix}']
                if field not in self.retaliation
                else self.retaliation[field] + [f'{prefix}{value}{suffix}'])
            if is_xor:
                self.retaliationXOR = True
Esempio n. 15
0
    def parse_flat(self, field, field_type, dbr):
        """
        Parse a flat increase in an offensive attribute.

        """
        # Prepare some keys that will determine the flat or flat range:
        chance = dbr.get(f'{field}Chance', 0)
        min = dbr.get(f'{field}Min', 0)
        max = dbr.get(f'{field}Max', min)
        is_xor = dbr.get(f'{field}XOR', False)
        is_global = dbr.get(f'{field}Global', False)

        # Optional pre/suffix for chance and duration damage/effects:
        prefix = ''
        suffix = ''

        if field_type == self.MANA:
            # The mana burn suffixes are kind of derpy:
            chance = dbr.get('offensiveManaBurnChance', 0)
            min = dbr.get('offensiveManaBurnDrainMin', 0)
            max = dbr.get('offensiveManaBurnDrainMax', 0)
            is_xor = dbr.get(f'{field}XOR', False)
            ratio = dbr.get('offensiveManaBurnDamageRatio', 0)

            if ratio:
                suffix = texts.get('offensiveManaBurnRatio').format(ratio)

            # Reset the field to what's used in texts.
            field = 'offensiveManaDrain'
        elif field_type == self.DOT:
            duration_min = dbr.get(f'{field}DurationMin', 0)
            duration_max = dbr.get(f'{field}DurationMax', 0)

            if duration_min:
                min *= duration_min
                suffix = texts.get(DOT_SINGLE).format(duration_min)

                if duration_max and max == min:
                    max = min * duration_max
                elif max:
                    max *= duration_min
        elif field_type == self.EOT:
            duration_min = dbr.get(f'{field}DurationMin', 0)

            if duration_min:
                suffix = texts.get(DFT_SINGLE).format(duration_min)

        # Pierce ratio is a singular exception for flat properties:
        if field == 'offensivePierceRatio':
            # Pierce ratio already has its formatter in the flat property:
            # "{0:.0f}% Pierce Ratio" instead of "% Pierce Ratio"
            value = texts.get(field).format(min)
        else:
            # Format the value based on its field type and values:
            value = self.format(field_type, field, min, max)

        if chance and not is_xor:
            prefix = texts.get(CHANCE).format(chance)

        if not is_global:
            # Insert the value normally
            TQDBParser.insert_value(field, f'{prefix}{value}{suffix}',
                                    self.result)
        elif field.startswith('offensive'):
            # Add this field to the global offensive list
            self.offensive[field] = ([
                f'{prefix}{value}{suffix}'
            ] if field not in self.offensive else self.offensive[field] +
                                     [f'{prefix}{value}{suffix}'])
            if is_xor:
                self.offensiveXOR = True
        elif field.startswith('retaliation'):
            # Add this field to the global retaliation list
            self.retaliation[field] = ([
                f'{prefix}{value}{suffix}'
            ] if field not in self.retaliation else self.retaliation[field] +
                                       [f'{prefix}{value}{suffix}'])
            if is_xor:
                self.retaliationXOR = True
Esempio n. 16
0
    def parse(self, dbr, dbr_file, result):
        """
        Parse the skill that spawns a pet.

        """
        # Only set time to live it's set (otherwise it's infinite)
        ttl_list = dbr.get(self.TTL, None)

        # Parse all the summons and set them as a list:
        result['summons'] = []
        for index, spawn_file in enumerate(dbr['spawnObjects']):
            spawn = DBRParser.parse(spawn_file)

            # Keep track of the original properties this summon had:
            original_properties = {}
            if 'properties' in spawn:
                if isinstance(spawn['properties'], list):
                    original_properties = spawn['properties'][0].copy()
                else:
                    original_properties = spawn['properties'].copy()

            # We need the raw values from the spawn DBR for hp/mp
            spawn['properties'] = {}
            spawn_dbr = DBRParser.read(spawn_file)

            if 'characterLife' in spawn_dbr:
                hp_list = spawn_dbr['characterLife']
                hp = (
                    hp_list[index]
                    if index < len(hp_list)
                    else hp_list[len(hp_list) - 1])
                TQDBParser.insert_value(
                    'characterLife',
                    texts.get('LifeText').format(hp),
                    spawn)
            if 'characterMana' in spawn_dbr:
                mp_list = spawn_dbr['characterMana']
                mp = (
                    mp_list[index]
                    if index < len(mp_list)
                    else mp_list[len(mp_list) - 1])
                TQDBParser.insert_value(
                    'characterMana',
                    texts.get('ManaText').format(mp),
                    spawn)
            if ttl_list:
                ttl = (
                    ttl_list[index]
                    if index < len(ttl_list)
                    else ttl_list[len(ttl_list) - 1])
                TQDBParser.insert_value(
                    self.TTL,
                    texts.get(self.TTL).format(ttl),
                    spawn)

            # Iterate over the original properties and add some whitelisted
            # properties to the final result:
            for key, value in original_properties.items():
                if key.startswith('character'):
                    continue
                spawn['properties'][key] = value

            result['summons'].append(spawn)
Esempio n. 17
0
    def parse(self, dbr, dbr_file, result):
        """
        Parse the base properties of a skill.

        These properties include the skillDisplayName, its friendly display
        name (the property returns a tag), and the maximum level of a skill.

        """
        # Store the path to this skill, it is used in tqdb.storage to ensure
        # all tags are unique.
        result['path'] = dbr_file

        if self.NAME in dbr:
            # The tag is the skillDisplayName property
            result['tag'] = self.FORMATTER.sub('', dbr[self.NAME])

            # Now try to find a friendly name for the tag:
            result['name'] = texts.get(result['tag'])

            if result['name'] == result['tag']:
                # If the tag wasn't returned, a friendly name weas found:
                logging.debug(f'No skill name found for {result["tag"]}')
        else:
            logging.debug(f'No skillDisplayName found in {dbr_file}')

        if self.DESC in dbr and texts.has(dbr[self.DESC]):
            # Also load the description, if it's known:
            result['description'] = texts.get(dbr[self.DESC])
        elif self.FILE in dbr:
            # Use the FileDescription instead:
            result['description'] = dbr['FileDescription']

        # Check the skill base fields:
        base_tiers = TQDBParser.highest_tier(dbr, self.FIELDS)

        for field in self.FIELDS:
            for index in range(base_tiers):
                itr_dbr = TQDBParser.extract_values(dbr, field, index)

                if field not in itr_dbr or itr_dbr[field] <= 0.01:
                    continue

                # Insert this skill property
                value = texts.get(field).format(itr_dbr[field])
                TQDBParser.insert_value(field, value, result)

        # Check the damage absorption skill properties:
        abs_tiers = TQDBParser.highest_tier(dbr, self.ABSORPTIONS)

        for field in self.ABSORPTIONS:
            for index in range(abs_tiers):
                itr_dbr = TQDBParser.extract_values(dbr, field, index)

                if field not in itr_dbr:
                    continue

                # Add 'skill' prefix and capitalize first letter:
                field_prefixed = 'skill' + field[:1].upper() + field[1:]
                value = itr_dbr[field]

                # Find qualifier damage type(s):
                damage_types = ', '.join([
                    texts.get(text_key)
                    for dmg_type, text_key in self.QUALIFIERS.items()
                    if dmg_type in dbr
                ])

                if damage_types:
                    TQDBParser.insert_value(
                        field_prefixed,
                        f'{texts.get(field_prefixed).format(value)} '
                        f'({damage_types})', result)
                else:
                    # If there is no qualifier, it's all damage:
                    TQDBParser.insert_value(
                        field_prefixed,
                        texts.get(field_prefixed).format(value), result)

        # Prepare two variables to determine the max number of tiers:
        skill_cap = dbr.get('skillUltimateLevel',
                            dbr.get('skillMaxLevel')) or 99
        props = result['properties']

        # The maximum number of properties is now the minimum between the skill
        # cap and the highest number of tiers available in the properties:
        max_tiers = min(TQDBParser.highest_tier(props, props.keys()),
                        skill_cap)

        # After all skill properties have been set, index them by level:
        properties = [{} for i in range(max_tiers)]

        # Insert the existing properties by adding them to the correct tier:
        for field, values in result['properties'].items():
            for index in range(max_tiers):
                # Each value is either a list or a flat value to repeat:
                if isinstance(values, list):
                    # Properties that are capped before this tier repeat their
                    # last value:
                    if index >= len(values):
                        properties[index][field] = values[len(values) - 1]
                    else:
                        properties[index][field] = values[index]
                else:
                    properties[index][field] = values

        # For summoned skills it's very likely a lot of extraneous empty
        # property tiers were added, filter those out:
        properties = [tier for tier in properties if tier]

        # Now set the reindexed properties:
        result['properties'] = properties
Esempio n. 18
0
    def parse(self, dbr, dbr_file, result):
        """
        Parse the base properties of a skill.

        These properties include the skillDisplayName, its friendly display
        name (the property returns a tag), and the maximum level of a skill.

        """
        # Store the path to this skill, it is used in tqdb.storage to ensure
        # all tags are unique.
        result['path'] = dbr_file

        if self.NAME in dbr:
            # The tag is the skillDisplayName property
            result['tag'] = self.FORMATTER.sub('', dbr[self.NAME])

            # Now try to find a friendly name for the tag:
            result['name'] = texts.get(result['tag'])

            if result['name'] == result['tag']:
                # If the tag wasn't returned, a friendly name weas found:
                logging.debug(f'No skill name found for {result["tag"]}')
        else:
            logging.debug(f'No skillDisplayName found in {dbr_file}')

        if self.DESC in dbr and texts.has(dbr[self.DESC]):
            # Also load the description, if it's known:
            result['description'] = texts.get(dbr[self.DESC])
        elif self.FILE in dbr:
            # Use the FileDescription instead:
            result['description'] = dbr['FileDescription']

        # Check the skill base fields:
        base_tiers = TQDBParser.highest_tier(dbr, self.FIELDS)

        for field in self.FIELDS:
            for index in range(base_tiers):
                itr_dbr = TQDBParser.extract_values(dbr, field, index)

                if field not in itr_dbr or itr_dbr[field] <= 0.01:
                    continue

                # Insert this skill property
                value = texts.get(field).format(itr_dbr[field])
                TQDBParser.insert_value(field, value, result)

        # Check the damage absorption skill properties:
        abs_tiers = TQDBParser.highest_tier(dbr, self.ABSORPTIONS)

        for field in self.ABSORPTIONS:
            for index in range(abs_tiers):
                itr_dbr = TQDBParser.extract_values(dbr, field, index)

                if field not in itr_dbr:
                    continue

                # Add 'skill' prefix and capitalize first letter:
                field_prefixed = 'skill' + field[:1].upper() + field[1:]
                value = itr_dbr[field]

                # Find qualifier damage type(s):
                damage_types = ', '.join([
                    texts.get(text_key)
                    for dmg_type, text_key in self.QUALIFIERS.items()
                    if dmg_type in dbr])

                if damage_types:
                    TQDBParser.insert_value(
                        field_prefixed,
                        f'{texts.get(field_prefixed).format(value)} '
                        f'({damage_types})',
                        result)
                else:
                    # If there is no qualifier, it's all damage:
                    TQDBParser.insert_value(
                        field_prefixed,
                        texts.get(field_prefixed).format(value),
                        result)

        # Prepare two variables to determine the max number of tiers:
        skill_cap = dbr.get('skillUltimateLevel', dbr.get('skillMaxLevel'))
        props = result['properties']

        # The maximum number of properties is now the minimum between the skill
        # cap and the highest number of tiers available in the properties:
        max_tiers = min(
            TQDBParser.highest_tier(props, props.keys()),
            skill_cap)

        # After all skill properties have been set, index them by level:
        properties = [{} for i in range(max_tiers)]

        # Insert the existing properties by adding them to the correct tier:
        for field, values in result['properties'].items():
            for index in range(max_tiers):
                # Each value is either a list or a flat value to repeat:
                if isinstance(values, list):
                    # Properties that are capped before this tier repeat their
                    # last value:
                    if index >= len(values):
                        properties[index][field] = values[len(values) - 1]
                    else:
                        properties[index][field] = values[index]
                else:
                    properties[index][field] = values

        # For summoned skills it's very likely a lot of extraneous empty
        # property tiers were added, filter those out:
        properties = [tier for tier in properties if tier]

        # Now set the reindexed properties:
        result['properties'] = properties