def get_levels(self): if self.character_data is None: raise Exception('You must call get_character() first.') try: total_level = int(self.character_data.value("AL6")) self.total_level = total_level except ValueError: raise MissingAttribute("Character level") level_dict = {} if self.additional: for rownum in range(69, 79): # sheet2, C69:C78 namecell = f"C{rownum}" levelcell = f"N{rownum}" classname = self.additional.value(namecell) if classname: classname = re.sub( r'[.$]', '_', classname) # sentry-H7 - invalid class names classlevel = int(self.additional.value(levelcell)) level_dict[classname] = classlevel else: # classes should be top-aligned break levels = Levels(level_dict, total_level) return levels
def _get_levels(self) -> Levels: """Returns a dict with the character's level and class levels.""" out = {} for klass in self.character_data['classes']: cleaned_name = re.sub(r'[.$]', '_', klass['name']) out[cleaned_name] = klass['level'] return Levels(out)
def new(cls, name: str, controller_id: str, init: int, init_skill: Skill, max_hp: int, ac: int, private: bool, resists: Resistances, ctx, combat): skills = Skills.default() skills.update({"initiative": init_skill}) levels = Levels({"Monster": 0}) id = create_combatant_id() return cls(ctx, combat, id, name, controller_id, private, init, levels=levels, resistances=resists, skills=skills, max_hp=max_hp, ac=ac)
def __init__(self, name: str, stats: BaseStats = None, levels: Levels = None, attacks: AttackList = None, skills: Skills = None, saves: Saves = None, resistances: Resistances = None, spellbook: Spellbook = None, ac: int = None, max_hp: int = None, hp: int = None, temp_hp: int = 0, creature_type: str = None): if stats is None: stats = BaseStats.default() if levels is None: levels = Levels() if attacks is None: attacks = AttackList() if skills is None: skills = Skills.default(stats) if saves is None: saves = Saves.default(stats) if resistances is None: resistances = Resistances() if spellbook is None: spellbook = Spellbook() if hp is None: hp = max_hp # ===== static ===== # all actors have a name self._name = name # ability scores self._stats = stats # at least a total level self._levels = levels # attacks - list of automation actions self._attacks = attacks # skill profs/saving throws self._skills = skills self._saves = saves # defensive resistances self._resistances = resistances # assigned by combatant type self._creature_type = creature_type # ===== dynamic ===== # hp/ac self._ac = ac self._max_hp = max_hp self._hp = hp self._temp_hp = temp_hp # spellbook self._spellbook = spellbook
def get_levels(self) -> Levels: """Returns a dict with the character's level and class levels.""" if self.character_data is None: raise Exception('You must call get_character() first.') if self.levels: return self.levels character = self.character_data levels = collections.defaultdict(lambda: 0) for _class in character.get('classes', []): levelName = _class.get('definition', {}).get('name') levels[levelName] += _class.get('level') out = {} for level, v in levels.items(): cleaned_name = re.sub(r'[.$]', '_', level) out[cleaned_name] = v level_obj = Levels(out) self.levels = level_obj return level_obj
def get_levels(self) -> Levels: """Returns a dict with the character's level and class levels.""" if self.character_data is None: raise Exception('You must call get_character() first.') if self.levels: return self.levels character = self.character_data levels = collections.defaultdict(lambda: 0) for level in character.get('classes', []): if level.get('removed', False): continue level_name = level['name'] levels[level_name] += level['level'] out = {} for level, v in levels.items(): cleaned_name = re.sub(r'[.$]', '_', level) out[cleaned_name] = v self.evaluator.names[f"{cleaned_name}Level"] = v level_obj = Levels(out) self.levels = level_obj self.evaluator.names['level'] = level_obj.total_level return level_obj
def __init__( self, name: str, size: str, race: str, alignment: str, ac: int, armortype: str, hp: int, hitdice: str, speed: str, ability_scores: BaseStats, saves: Saves, skills: Skills, senses: str, display_resists: Resistances, condition_immune: list, languages: list, cr: str, xp: int, # optional traits: list = None, actions: list = None, reactions: list = None, legactions: list = None, la_per_round=3, passiveperc: int = None, # augmented resistances: Resistances = None, attacks: AttackList = None, proper: bool = False, image_url: str = None, spellcasting=None, # sourcing homebrew=False, **kwargs): if traits is None: traits = [] if actions is None: actions = [] if reactions is None: reactions = [] if legactions is None: legactions = [] if attacks is None: attacks = AttackList() if spellcasting is None: spellcasting = MonsterSpellbook() if passiveperc is None: passiveperc = 10 + skills.perception.value # old/new resist handling if resistances is None: # fall back to old-style resistances (deprecated) vuln = kwargs.get('vuln', []) resist = kwargs.get('resist', []) immune = kwargs.get('immune', []) resistances = Resistances.from_dict( dict(vuln=vuln, resist=resist, immune=immune)) try: levels = Levels({"Monster": spellcasting.caster_level or int(cr)}) except ValueError: levels = None Sourced.__init__(self, 'monster', homebrew, source=kwargs['source'], entity_id=kwargs.get('entity_id'), page=kwargs.get('page'), url=kwargs.get('url'), is_free=kwargs.get('is_free')) StatBlock.__init__(self, name=name, stats=ability_scores, attacks=attacks, skills=skills, saves=saves, resistances=resistances, spellbook=spellcasting, ac=ac, max_hp=hp, levels=levels) self.size = size self.race = race self.alignment = alignment self.armortype = armortype self.hitdice = hitdice self.speed = speed self.cr = cr self.xp = xp self.passive = passiveperc self.senses = senses self.condition_immune = condition_immune self.languages = languages self.traits = traits self.actions = actions self.reactions = reactions self.legactions = legactions self.la_per_round = la_per_round self.proper = proper self.image_url = image_url # resistances including notes, e.g. "Bludgeoning from nonmagical weapons" self._displayed_resistances = display_resists or resistances
def __init__(self, name: str, size: str, race: str, alignment: str, ac: int, armortype: str, hp: int, hitdice: str, speed: str, ability_scores: BaseStats, cr: str, xp: int, passiveperc: int = None, senses: str = '', vuln: list = None, resist: list = None, immune: list = None, condition_immune: list = None, saves: Saves = None, skills: Skills = None, languages: list = None, traits: list = None, actions: list = None, reactions: list = None, legactions: list = None, la_per_round=3, srd=True, source='homebrew', attacks: AttackList = None, proper: bool = False, image_url: str = None, spellcasting=None, page=None, display_resists: Resistances = None, **_): if vuln is None: vuln = [] if resist is None: resist = [] if immune is None: immune = [] if condition_immune is None: condition_immune = [] if saves is None: saves = Saves.default(ability_scores) if skills is None: skills = Skills.default(ability_scores) if languages is None: languages = [] if traits is None: traits = [] if actions is None: actions = [] if reactions is None: reactions = [] if legactions is None: legactions = [] if attacks is None: attacks = AttackList() if spellcasting is None: spellcasting = Spellbook({}, {}, []) if passiveperc is None: passiveperc = 10 + skills.perception.value try: levels = Levels({"Monster": spellcasting.caster_level or int(cr)}) except ValueError: levels = None resistances = Resistances(vuln=vuln, resist=resist, immune=immune) super(Monster, self).__init__(name=name, stats=ability_scores, attacks=attacks, skills=skills, saves=saves, resistances=resistances, spellbook=spellcasting, ac=ac, max_hp=hp, levels=levels) self.size = size self.race = race self.alignment = alignment self.armortype = armortype self.hitdice = hitdice self.speed = speed self.cr = cr self.xp = xp self.passive = passiveperc self.senses = senses self.condition_immune = condition_immune self.languages = languages self.traits = traits self.actions = actions self.reactions = reactions self.legactions = legactions self.la_per_round = la_per_round self.srd = srd self.source = source self.proper = proper self.image_url = image_url self.page = page # this should really be by source, but oh well # resistances including notes, e.g. "Bludgeoning from nonmagical weapons" self._displayed_resistances = display_resists or resistances