Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
 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)
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
    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