Example #1
0
    def _get_saves(self) -> Saves:
        out = {}
        for stat_key, save_key in zip(constants.STAT_ABBREVIATIONS, constants.SAVE_NAMES):
            out[save_key] = Skill(self.character_data['stats'][stat_key]['save'],
                                  prof=1 if self.character_data['stats'][stat_key]['saveProficiency'] else 0)

        return Saves(out)
Example #2
0
    def get_skills_and_saves(self) -> (Skills, Saves):
        if self.character_data is None: raise Exception('You must call get_character() first.')
        character = self.character_data
        stats = self.get_stats()

        NAME_SET = set(SKILL_NAMES + SAVE_NAMES)
        ADV_INT_MAP = {-1: False, 0: None, 1: True}
        profs = {}
        effects = collections.defaultdict(lambda: 0)

        # calculate profs
        for prof in character.get('proficiencies', []):
            if prof.get('enabled', False) and not prof.get('removed', False):
                profs[prof.get('name')] = prof.get('value') \
                    if prof.get('value') > profs.get(prof.get('name', 'None'), 0) \
                    else profs[prof.get('name')]

        # and effects
        for effect in self.character_data.get('effects', []):
            if effect.get('stat') in NAME_SET \
                    and effect.get('enabled', True) \
                    and not effect.get('removed', False):
                statname = effect.get('stat')
                if effect.get('operation') == 'disadvantage':
                    effects[statname] = max(-1, effects[statname] - 1)
                if effect.get('operation') == 'advantage':
                    effects[statname] = min(1, effects[statname] + 1)

        # assign skills
        skills = {}
        for skill in SKILL_NAMES:
            prof_mult = profs.get(skill, 0)
            base_val = floor(stats.get_mod(SKILL_MAP[skill]) + stats.prof_bonus * prof_mult)
            adv = ADV_INT_MAP.get(effects.get(skill))
            if skill not in STAT_NAMES:
                value = int(self.calculate_stat(skill, base=base_val))
            else:
                value = base_val
            skills[skill] = Skill(
                value,
                prof=prof_mult,
                adv=adv
            )

        # and saves
        saves = {}
        for save in SAVE_NAMES:
            prof_mult = profs.get(save, 0)
            base_val = floor(stats.get_mod(SKILL_MAP[save]) + stats.prof_bonus * prof_mult)
            adv = ADV_INT_MAP.get(effects.get(save))
            saves[save] = Skill(
                int(self.calculate_stat(save, base=base_val)),
                prof=prof_mult,
                adv=adv
            )

        return Skills(skills), Saves(saves)
Example #3
0
    def _get_saves(self) -> Saves:
        out = {}
        for stat_key, save_key in zip(constants.STAT_ABBREVIATIONS,
                                      constants.SAVE_NAMES):
            stat_data = self.character_data['stats'][stat_key]
            adv_type = derive_adv(stat_data['saveAdv'], stat_data['saveDis'])
            out[save_key] = Skill(
                stat_data['save'],
                prof=1 if stat_data['saveProficiency'] else 0,
                adv=adv_type)

        return Saves(out)
Example #4
0
    def get_skills_and_saves(self):
        if self.character_data is None:
            raise Exception('You must call get_character() first.')
        character = self.character_data

        skills = {}
        saves = {}
        is_joat = self.version == 2 and bool(character.cell("AR45").value)
        for cell, skill, advcell in SKILL_CELL_MAP:
            if isinstance(cell, int):
                advcell = f"F{cell}"
                profcell = f"H{cell}"
                cell = f"I{cell}"
            else:
                profcell = None
            try:
                value = int(character.cell(cell).value)
            except (TypeError, ValueError):
                raise MissingAttribute(skill)

            adv = None
            if self.version == 2 and advcell:
                advtype = character.cell(advcell).value
                if advtype in {'a', 'adv', 'advantage'}:
                    adv = True
                elif advtype in {'d', 'dis', 'disadvantage'}:
                    adv = False

            prof = 0
            if "Save" not in skill and is_joat:
                prof = 0.5
            if profcell:
                proftype = character.cell(profcell).value_unformatted
                if proftype == 'e':
                    prof = 2
                elif proftype and proftype != '0':
                    prof = 1

            skl_obj = Skill(value, prof, adv=adv)
            if "Save" in skill:
                saves[skill] = skl_obj
            else:
                skills[skill] = skl_obj

        skills = Skills(skills)
        saves = Saves(saves)
        return skills, saves
Example #5
0
    def get_skills_and_saves(self):
        if self.character_data is None:
            raise Exception('You must call get_character() first.')
        character = self.character_data
        skills = {}
        saves = {}
        is_joat = False
        all_check_bonus = 0

        if self.version == (2, 0):
            is_joat = bool(character.value("AR45"))
            all_check_bonus = int(character.value("AQ26") or 0)
        elif self.version == (2, 1):
            is_joat = bool(character.value("AQ59"))
            all_check_bonus = int(character.value("AR58"))

        joat_bonus = int(is_joat and self.get_stats().prof_bonus // 2)

        # calculate str, dex, con, etc checks
        for cell, skill, advcell in BASE_ABILITY_CHECKS:
            try:
                # add bonuses manually since the cell does not include them
                value = int(
                    character.value(cell)) + all_check_bonus + joat_bonus
            except (TypeError, ValueError):
                raise MissingAttribute(skill)

            prof = 0
            if is_joat:
                prof = 0.5

            skl_obj = Skill(value, prof)
            skills[skill] = skl_obj

        # read the value of the rest of the skills
        for cell, skill, advcell in SKILL_CELL_MAP:
            if isinstance(cell, int):
                advcell = f"F{cell}"
                profcell = f"H{cell}"
                cell = f"I{cell}"
            else:
                profcell = None
            try:
                value = int(character.value(cell))
            except (TypeError, ValueError):
                raise MissingAttribute(skill)

            adv = None
            if self.version >= (2, 0) and advcell:
                advtype = character.unformatted_value(advcell)
                if advtype in {'a', 'adv', 'advantage'}:
                    adv = True
                elif advtype in {'d', 'dis', 'disadvantage'}:
                    adv = False

            prof = 0
            if "Save" not in skill and is_joat:
                prof = 0.5
            if profcell:
                proftype = character.unformatted_value(profcell)
                if proftype == 'e':
                    prof = 2
                elif proftype and proftype != '0':
                    prof = 1

            skl_obj = Skill(value, prof, adv=adv)
            if "Save" in skill:
                saves[skill] = skl_obj
            else:
                skills[skill] = skl_obj

        skills = Skills(skills)
        saves = Saves(saves)
        return skills, saves
Example #6
0
    def get_skills_and_saves(self):
        """Returns a dict of all the character's skills."""
        if self.character_data is None:
            raise Exception('You must call get_character() first.')
        stats = self.get_stats()
        profBonus = stats.prof_bonus

        profs = dict()
        bonuses = dict()
        advantages = collections.defaultdict(lambda: [])

        for mod in self.modifiers():
            mod['subType'] = mod['subType'].replace("-saving-throws", "Save")
            if mod['type'] == 'half-proficiency':
                profs[mod['subType']] = max(profs.get(mod['subType'], 0), 0.5)
            elif mod['type'] == 'proficiency':
                profs[mod['subType']] = max(profs.get(mod['subType'], 0), 1)
            elif mod['type'] == 'expertise':
                profs[mod['subType']] = 2
            elif mod['type'] == 'bonus':
                if not mod['isGranted']:
                    continue
                if mod['statId'] is not None:
                    bonuses[mod['subType']] = bonuses.get(
                        mod['subType'], 0) + self.stat_from_id(mod['statId'])
                else:
                    bonuses[mod['subType']] = bonuses.get(
                        mod['subType'], 0) + (mod['value'] or 0)
            elif mod['type'] == 'advantage' and not mod[
                    'restriction']:  # unconditional adv
                advantages[mod['subType']].append(True)
            elif mod['type'] == 'disadvantage' and not mod[
                    'restriction']:  # unconditional dis
                advantages[mod['subType']].append(False)

        profs['animalHandling'] = profs.get('animal-handling', 0)
        profs['sleightOfHand'] = profs.get('sleight-of-hand', 0)
        advantages['animalHandling'] = advantages['animal-handling']
        advantages['sleightOfHand'] = advantages['sleight-of-hand']

        def _simplify_adv(adv_list):
            adv_set = set(adv_list)
            if len(adv_set) == 1:
                return adv_set.pop()
            return None

        skills = {}
        for skill in SKILL_NAMES:  # add proficiency and bonuses to skills
            relevantprof = profs.get(skill, 0)
            relevantbonus = bonuses.get(skill, 0)
            relevantadv = _simplify_adv(advantages[skill])
            if 'ability-checks' in profs and skill != 'initiative':
                relevantprof = max(relevantprof, profs['ability-checks'])
            if 'ability-checks' in bonuses and skill != 'initiative':
                relevantbonus += bonuses['ability-checks']
            skills[skill] = Skill(floor(
                stats.get_mod(SKILL_MAP[skill]) + (profBonus * relevantprof) +
                relevantbonus),
                                  relevantprof,
                                  relevantbonus,
                                  adv=relevantadv)

        # saves
        saves = {}
        for save in SAVE_NAMES:  # add proficiency and bonuses to skills
            relevantprof = profs.get(save, 0)
            relevantbonus = bonuses.get(save, 0)
            relevantadv = _simplify_adv(advantages[save])
            if 'saving-throws' in profs:
                relevantprof = max(relevantprof, profs['saving-throws'])
            if 'saving-throws' in bonuses:
                relevantbonus += bonuses['saving-throws']
            saves[save] = Skill(floor(
                stats.get_mod(SKILL_MAP[save]) + (profBonus * relevantprof) +
                relevantbonus),
                                relevantprof,
                                relevantbonus,
                                adv=relevantadv)

        # values
        ignored_ids = set()
        for charval in self.character_data['characterValues']:
            if charval['value'] is None:
                continue

            if charval['typeId'] == 39:  # misc saving throw bonus
                save_id = SAVE_NAMES[charval['valueId'] - 1]
                save_bonus = charval['value']
                saves[save_id].value += save_bonus
                saves[save_id].bonus += save_bonus
            elif charval['valueId'] in HOUSERULE_SKILL_MAP and charval[
                    'valueId'] not in ignored_ids:
                skill_name = HOUSERULE_SKILL_MAP[charval['valueId']]
                if charval['typeId'] == 23:  # override
                    skills[skill_name] = Skill(charval['value'])
                    ignored_ids.add(
                        charval['valueId']
                    )  # this must be the final value so we stop looking
                elif charval['typeId'] in {
                        24, 25
                }:  # PROBABLY skill magic/misc bonus
                    skills[skill_name].value += charval['value']
                    skills[skill_name].bonus += charval['value']
                elif charval['typeId'] == 26:  # proficiency stuff
                    relevantprof = profs.get(skill_name, 0)
                    skills[skill_name].value -= relevantprof * profBonus
                    if charval[
                            'value'] == 0:  # no prof, don't need to do anything
                        skills[skill_name].prof = 0
                    elif charval['value'] == 1:  # half prof, round down
                        skills[skill_name].value += profBonus // 2
                        skills[skill_name].prof = 0.5
                    elif charval['value'] == 2:  # half, round up
                        skills[skill_name].value += ceil(profBonus / 2)
                        skills[skill_name].prof = 0.5
                    elif charval['value'] == 3:  # full
                        skills[skill_name].value += profBonus
                        skills[skill_name].prof = 1
                    elif charval['value'] == 4:  # double
                        skills[skill_name].value += profBonus * 2
                        skills[skill_name].prof = 2

        skills = Skills(skills)
        saves = Saves(saves)

        return skills, saves
Example #7
0
    def get_skills_and_saves(self):
        """Returns a dict of all the character's skills."""
        if self.character_data is None:
            raise Exception('You must call get_character() first.')
        character = self.character_data
        stats = self.get_stats()
        profBonus = stats.prof_bonus

        profs = dict()
        bonuses = dict()

        for modtype in character['modifiers'].values(
        ):  # calculate proficiencies in all skills
            for mod in modtype:
                mod['subType'] = mod['subType'].replace(
                    "-saving-throws", "Save")
                if mod['type'] == 'half-proficiency':
                    profs[mod['subType']] = max(profs.get(mod['subType'], 0),
                                                0.5)
                elif mod['type'] == 'proficiency':
                    profs[mod['subType']] = max(profs.get(mod['subType'], 0),
                                                1)
                elif mod['type'] == 'expertise':
                    profs[mod['subType']] = 2
                elif mod['type'] == 'bonus':
                    if not mod['isGranted']:
                        continue
                    if mod['statId'] is not None:
                        bonuses[mod['subType']] = bonuses.get(
                            mod['subType'], 0) + self.stat_from_id(
                                mod['statId'])
                    else:
                        bonuses[mod['subType']] = bonuses.get(
                            mod['subType'], 0) + (mod['value'] or 0)

        profs['animalHandling'] = profs.get('animal-handling', 0)
        profs['sleightOfHand'] = profs.get('sleight-of-hand', 0)

        skills = {}
        for skill in SKILL_NAMES:  # add proficiency and bonuses to skills
            relevantprof = profs.get(skill, 0)
            relevantbonus = bonuses.get(skill, 0)
            if 'ability-checks' in profs:
                relevantprof = max(relevantprof, profs['ability-checks'])
            if 'ability-checks' in bonuses:
                relevantbonus += bonuses['ability-checks']
            skills[skill] = Skill(
                floor(
                    stats.get_mod(SKILL_MAP[skill]) +
                    (profBonus * relevantprof) + relevantbonus), relevantprof,
                relevantbonus)

        saves = {}
        for save in SAVE_NAMES:  # add proficiency and bonuses to skills
            relevantprof = profs.get(save, 0)
            relevantbonus = bonuses.get(save, 0)
            if 'saving-throws' in profs:
                relevantprof = max(relevantprof, profs['saving-throws'])
            if 'saving-throws' in bonuses:
                relevantbonus += bonuses['saving-throws']
            saves[save] = Skill(
                floor(
                    stats.get_mod(SKILL_MAP[save]) +
                    (profBonus * relevantprof) + relevantbonus), relevantprof,
                relevantbonus)

        ignored_ids = set()
        for charval in self.character_data['characterValues']:
            if charval['valueId'] in HOUSERULE_SKILL_MAP and charval[
                    'valueId'] not in ignored_ids:
                skill_name = HOUSERULE_SKILL_MAP[charval['valueId']]
                if charval['typeId'] == 23:  # override
                    skills[skill_name] = Skill(charval['value'])
                    ignored_ids.add(
                        charval['valueId']
                    )  # this must be the final value so we stop looking
                elif charval['typeId'] in {
                        24, 25
                }:  # PROBABLY skill magic/misc bonus
                    skills[skill_name].value += charval['value']
                    skills[skill_name].bonus += charval['value']
                elif charval['typeId'] == 26:  # proficiency stuff
                    relevantprof = profs.get(skill_name, 0)
                    skills[skill_name].value -= relevantprof * profBonus
                    if charval[
                            'value'] == 0:  # no prof, don't need to do anything
                        skills[skill_name].prof = 0
                    elif charval['value'] == 1:  # half prof, round down
                        skills[skill_name].value += profBonus // 2
                        skills[skill_name].prof = 0.5
                    elif charval['value'] == 2:  # half, round up
                        skills[skill_name].value += ceil(profBonus / 2)
                        skills[skill_name].prof = 0.5
                    elif charval['value'] == 3:  # full
                        skills[skill_name].value += profBonus
                        skills[skill_name].prof = 1
                    elif charval['value'] == 4:  # double
                        skills[skill_name].value += profBonus * 2
                        skills[skill_name].prof = 2

        skills = Skills(skills)
        saves = Saves(saves)

        return skills, saves