예제 #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)
예제 #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)
예제 #3
0
파일: base.py 프로젝트: fonsleenaars/tqdb
    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)
예제 #4
0
파일: base.py 프로젝트: fonsleenaars/tqdb
    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}']
            )
예제 #5
0
    def parse_creature(self, dbr, dbr_file, result):
        """
        Parse the creature and its properties and skills.

        """
        # Grab the first set of properties:
        classification = dbr.get('monsterClassification', 'Common')
        tag = dbr.get('description', None)

        # Set the known properties for this creature
        if tag:
            race = dbr.get('characterRacialProfile', None)
            result.update({
                'classification':
                classification,
                'name':
                texts.get(tag),
                'race':
                race[0] if race else None,
                'level': [level for level in dbr.get('charLevel', [])],
                'tag':
                tag,
            })

        # Manually parse the defensive properties, since there's no template
        # tied for it for monsters:
        parsers.ParametersDefensiveParser().parse(dbr, dbr_file, result)

        # Iterate over the properties for each difficulty:
        properties = []
        for i in range(3):
            properties.append({})
            itr = TQDBParser.extract_values(dbr, '', i)

            # Set this creature's HP and MP as stats, not as bonuses:
            if self.HP in itr:
                hp = itr[self.HP]
                properties[i][self.HP] = texts.get('LifeText').format(hp)
            if self.MP in itr:
                mp = itr[self.MP]
                properties[i][self.MP] = texts.get('ManaText').format(mp)

            # Add non-character properties:
            for k, v in result['properties'].items():
                if k.startswith('character'):
                    continue

                # Add the property to the correct difficulty index:
                if isinstance(v, list):
                    # The property changes per difficulty:
                    properties[i][k] = v[i] if i < len(v) else v[-1]
                else:
                    # The property is constant:
                    properties[i][k] = v

        # Add the base damage, stats, regens, and resistances:
        result['properties'] = properties
예제 #6
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}'])
예제 #7
0
파일: base.py 프로젝트: fonsleenaars/tqdb
    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)
예제 #8
0
파일: base.py 프로젝트: fonsleenaars/tqdb
    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)
예제 #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)
예제 #10
0
파일: base.py 프로젝트: fonsleenaars/tqdb
    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)
예제 #11
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)
예제 #12
0
    def parse(self, dbr, dbr_file, result):
        """
        Parse all the abilities a monster has.

        """
        # Initialize the abilities (to be indexed per level)
        abilities = []

        # Parse all the normal skills (17 max):
        for i in range(1, 18):
            nameTag = f'skillName{i}'
            levelTag = f'skillLevel{i}'

            # Skip unset skills or skills that are to be ignored:
            if (nameTag not in dbr or levelTag not in dbr
                    or str(dbr[nameTag]).lower() in self.IGNORE_SKILLS):
                continue

            try:
                skill = DBRParser.parse(dbr[nameTag])
            except InvalidItemError as e:
                logging.debug(
                    f"Skipping creature skill {nameTag} in {dbr_file} because it's invalid. {e}"
                )
                continue
            if not skill['properties']:
                continue

            # Store the skill, which will ensure a unique tag:
            skill_tag = storage.store_skill(skill)

            # Iterate over the difficulties:
            for difficulty in range(3):
                itr = TQDBParser.extract_values(dbr, 'skill', difficulty)

                # If a level is set to 0 for a difficulty, it won't be in the
                # extracted result, so use the KeyError safe 'get' method:
                level = itr.get(levelTag, 0)

                if not level:
                    continue

                if len(abilities) - 1 < difficulty:
                    # Create missing tiers:
                    abilities += ([{}] * (difficulty - len(abilities) + 1))

                abilities[difficulty][skill_tag] = level

        result['abilities'] = abilities
예제 #13
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)
예제 #14
0
파일: base.py 프로젝트: fonsleenaars/tqdb
    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)
예제 #15
0
    def parse(self, dbr, dbr_file, result):
        file_name = os.path.basename(dbr_file).split('_')
        difficulty = self.DIFFICULTIES_LIST[int(file_name[0][1:]) - 1]

        result.update({
            # The act it starts dropping in is also listed in the file name
            'act': file_name[1],
            # Bitmap has a different key name than items here.
            'bitmap': dbr.get('relicBitmap', None),
            # Difficulty classification is based on the file name
            'classification': texts.get(difficulty).strip(),
            # Ironically the itemText holds the actual description tag
            'description': texts.get(dbr['itemText']),
            # For relics the tag is in the Actor.tpl variable 'description'
            'name': texts.get(dbr['description']),
            'tag': dbr['description'],
        })

        # The possible completion bonuses are in bonusTableName:
        bonuses = {}
        try:
            bonuses = DBRParser.parse(dbr['bonusTableName'])
        except InvalidItemError as e:
            logging.debug("Could not parse relic completion bonus information "
                          f"for {result['name']} in {dbr_file}. {e}")

        result['bonus'] = bonuses.get('table', [])

        # Find how many pieces this relic has
        max_pieces = TQDBParser.highest_tier(
            result['properties'], result['properties'].keys())

        # Initialize a list of tiers
        properties = [{} for i in range(max_pieces)]

        # Setup properties as list to correspond to adding pieces of a relic:
        for key, values in result['properties'].items():
            if not isinstance(values, list):
                # This property is just repeated for all tiers:
                for i in range(max_pieces):
                    properties[i][key] = values
                continue

            for index, value in enumerate(values):
                properties[index][key] = value

        result['properties'] = properties
예제 #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)
예제 #17
0
    def parse(self, dbr, dbr_file, result):
        file_name = os.path.basename(dbr_file).split('_')
        difficulty = self.DIFFICULTIES_LIST[int(file_name[0][1:]) - 1]

        result.update({
            # The act it starts dropping in is also listed in the file name
            'act': file_name[1],
            # Bitmap has a different key name than items here.
            'bitmap': dbr.get('relicBitmap', None),
            # Difficulty classification is based on the file name
            'classification': texts.get(difficulty).strip(),
            # Ironically the itemText holds the actual description tag
            'description': texts.get(dbr['itemText']),
            # For relics the tag is in the Actor.tpl variable 'description'
            'name': texts.get(dbr['description']),
            'tag': dbr['description'],
        })

        # The possible completion bonuses are in bonusTableName:
        bonuses = DBRParser.parse(dbr['bonusTableName'])
        result['bonus'] = bonuses.get('table', [])

        # Find how many pieces this relic has
        max_pieces = TQDBParser.highest_tier(
            result['properties'], result['properties'].keys())

        # Initialize a list of tiers
        properties = [{} for i in range(max_pieces)]

        # Setup properties as list to correspond to adding pieces of a relic:
        for key, values in result['properties'].items():
            if not isinstance(values, list):
                # This property is just repeated for all tiers:
                for i in range(max_pieces):
                    properties[i][key] = values
                continue

            for index, value in enumerate(values):
                properties[index][key] = value

        result['properties'] = properties
예제 #18
0
파일: base.py 프로젝트: fonsleenaars/tqdb
    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
예제 #19
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
예제 #20
0
파일: skills.py 프로젝트: fonsleenaars/tqdb
    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)
예제 #21
0
파일: base.py 프로젝트: fonsleenaars/tqdb
    def parse(self, dbr, dbr_file, result):
        """
        Parse an offensive/retaliation field.

        For each field, depending on the group it's in, this function will need
        to check both the absolute (flat increase) and modifier (% increase)
        versions as well as possible effects or damage durations.

        Args:
            field (str): Field name, as listed in the FIELDS list

        """
        # Set the result and prepare the global stores:
        self.result = result
        self.offensive = {}
        self.offensiveXOR = False
        self.retaliation = {}
        self.retaliationXOR = False

        for field, field_type in self.FIELDS.items():
            # Find whether the flat, modifier, or both fields are present:
            min = (f'{field}Min'
                   if field != 'offensiveManaBurn'
                   # Mana burn is the only field that differs from the rest
                   else 'offensiveManaBurnDrainMin')
            mod = f'{field}Modifier'

            iterations = max(
                len(dbr[min]) if min in dbr else 0,
                len(dbr[mod]) if mod in dbr else 0,
                0)

            # Now iterate as many times as is necessary for this field:
            for index in range(iterations):
                # Create a new copy of the DBR with the values for this index:
                iteration = TQDBParser.extract_values(dbr, field, index)

                if min in iteration:
                    # Parse the flat (+...) version:
                    self.parse_flat(field, field_type, iteration)
                if mod in iteration:
                    # Parse the modifier (+...%) version
                    self.parse_modifier(field, field_type, iteration)

        # Now add the global chance tags if they're set:
        offensive_key = 'offensiveGlobalChance'
        if offensive_key in dbr and self.offensive:
            # Skip 0 chance globals altogether
            chances = [chance for chance in dbr[offensive_key] if chance]

            for index, chance in enumerate(chances):
                self.parse_global(
                    offensive_key,
                    # The global chance for the offensive properties
                    chance,
                    # If any global offensive properties are XOR-ed:
                    self.offensiveXOR,
                    # The dictionary of global offensive properties
                    self.offensive,
                    # Index of this global chance
                    index)

        retaliation_key = 'retaliationGlobalChance'
        if retaliation_key in dbr and self.retaliation:
            # Skip 0 chance globals altogether
            chances = [chance for chance in dbr[retaliation_key] if chance]

            for index, chance in enumerate(chances):
                self.parse_global(
                    retaliation_key,
                    # The global chance for the offensive properties
                    chance,
                    # If any global offensive properties are XOR-ed:
                    self.retaliationXOR,
                    # The dictionary of global offensive properties
                    self.retaliation,
                    # Index of this global chance
                    index)
예제 #22
0
    def parse(self, dbr, dbr_file, result):
        """
        Parse an offensive/retaliation field.

        For each field, depending on the group it's in, this function will need
        to check both the absolute (flat increase) and modifier (% increase)
        versions as well as possible effects or damage durations.

        Args:
            field (str): Field name, as listed in the FIELDS list

        """
        # Set the result and prepare the global stores:
        self.result = result
        self.offensive = {}
        self.offensiveXOR = False
        self.retaliation = {}
        self.retaliationXOR = False

        for field, field_type in self.FIELDS.items():
            # Find whether the flat, modifier, or both fields are present:
            min = (
                f'{field}Min' if field != 'offensiveManaBurn'
                # Mana burn is the only field that differs from the rest
                else 'offensiveManaBurnDrainMin')
            mod = f'{field}Modifier'

            iterations = max(
                len(dbr[min]) if min in dbr else 0,
                len(dbr[mod]) if mod in dbr else 0, 0)

            # Now iterate as many times as is necessary for this field:
            for index in range(iterations):
                # Create a new copy of the DBR with the values for this index:
                iteration = TQDBParser.extract_values(dbr, field, index)

                if min in iteration:
                    # Parse the flat (+...) version:
                    self.parse_flat(field, field_type, iteration)
                if mod in iteration:
                    # Parse the modifier (+...%) version
                    self.parse_modifier(field, field_type, iteration)

        # Now add the global chance tags if they're set:
        offensive_key = 'offensiveGlobalChance'
        if offensive_key in dbr and self.offensive:
            # Skip 0 chance globals altogether
            chances = [chance for chance in dbr[offensive_key] if chance]

            for index, chance in enumerate(chances):
                self.parse_global(
                    offensive_key,
                    # The global chance for the offensive properties
                    chance,
                    # If any global offensive properties are XOR-ed:
                    self.offensiveXOR,
                    # The dictionary of global offensive properties
                    self.offensive,
                    # Index of this global chance
                    index)

        retaliation_key = 'retaliationGlobalChance'
        if retaliation_key in dbr and self.retaliation:
            # Skip 0 chance globals altogether
            chances = [chance for chance in dbr[retaliation_key] if chance]

            for index, chance in enumerate(chances):
                self.parse_global(
                    retaliation_key,
                    # The global chance for the offensive properties
                    chance,
                    # If any global offensive properties are XOR-ed:
                    self.retaliationXOR,
                    # The dictionary of global offensive properties
                    self.retaliation,
                    # Index of this global chance
                    index)
예제 #23
0
파일: skills.py 프로젝트: fonsleenaars/tqdb
    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
예제 #24
0
파일: creatures.py 프로젝트: rehevkor5/tqdb
    def parse(self, dbr, dbr_file, result):
        """
        Parse the monster.

        """
        self.parse_creature(dbr, dbr_file, result)

        # Don't parse any further for tagless or level-less creatures:
        if 'tag' not in result or not result['level']:
            return

        # Iterate over normal, epic & legendary version of the boss:
        loot = []
        for index in range(3):
            # Initialize an empty result:
            loot.append({})

            # Create a DBR that only has the equipment for this difficulty:
            difficulty_dbr = TQDBParser.extract_values(dbr, '', index)

            # Parse all the equipment in this difficulty
            difficulty_dbr = self.parse_difficulty(difficulty_dbr, dbr_file)

            # Only store the equipment if there was any:
            if difficulty_dbr:
                loot[index] = difficulty_dbr

        # If there is any tiered data to store, store it:
        if any(tier for tier in loot if tier):
            result['loot'] = loot

        chests = []
        tag = result['tag']

        # Find the chest for each difficulty:
        for index in range(3):
            # Initialize an empty result:
            chests.append({})

            # Grab the chest to parse:
            if tag in CHESTS and CHESTS[tag][index]:
                # Grab the level for this index, or the last one:
                level = (
                    result['level'][index]
                    if len(result['level']) > index
                    else result['level'][-1])

                # Parse the chest and pass the monsters level as a reference:
                loot = DBRParser.parse(
                    DB / CHESTS[tag][index],
                    {'level': level},
                )

                # Convert all item chances to 4 point precision:
                chests[index] = dict(
                    (k, float('{0:.4f}'.format(v))) for k, v
                    in loot['loot_table'].items())

        # If there is any tiered data to store, store it:
        if any(tier for tier in chests if tier):
            result['chest'] = chests

        # Check if this monster is limited to a difficulty:
        if len(result['level']) != len(set(result['level'])):
            # If a level is repeated, it means a creature doesn't spawn in
            # some difficulties. The 'normal' difficulty level is either
            # repeated in Epic and Legendary, so find the index and subtract
            # 1 from that to get all difficulties that should be removed:
            for i in range(result['level'].count(result['level'][0]) - 1):
                result['properties'][i] = {}
                result['abilities'][i] = {}
                result['level'][i] = None
예제 #25
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