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
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