コード例 #1
0
ファイル: monster.py プロジェクト: driesceuppens/avrae
 def from_data(cls, d):
     ability_scores = BaseStats.from_dict(d['ability_scores'])
     saves = Saves.from_dict(d['saves'])
     skills = Skills.from_dict(d['skills'])
     display_resists = Resistances.from_dict(d['display_resists'], smart=False)
     traits = [Trait(**t) for t in d['traits']]
     actions = [Trait(**t) for t in d['actions']]
     reactions = [Trait(**t) for t in d['reactions']]
     legactions = [Trait(**t) for t in d['legactions']]
     bonus_actions = [Trait(**t) for t in d.get('bonus_actions', [])]
     mythic_actions = [Trait(**t) for t in d.get('mythic_actions', [])]
     resistances = Resistances.from_dict(d['resistances'])
     attacks = AttackList.from_dict(d['attacks'])
     if d['spellbook'] is not None:
         spellcasting = MonsterSpellbook.from_dict(d['spellbook'])
     else:
         spellcasting = None
     return cls(d['name'], d['size'], d['race'], d['alignment'], d['ac'], d['armortype'], d['hp'], d['hitdice'],
                d['speed'], ability_scores, saves, skills, d['senses'], display_resists, d['condition_immune'],
                d['languages'], d['cr'], d['xp'],
                traits=traits, actions=actions, reactions=reactions, legactions=legactions,
                bonus_actions=bonus_actions, mythic_actions=mythic_actions,
                la_per_round=d['la_per_round'], passiveperc=d['passiveperc'],
                # augmented
                resistances=resistances, attacks=attacks, proper=d['proper'], image_url=d['image_url'],
                spellcasting=spellcasting, token_free_fp=d['token_free'], token_sub_fp=d['token_sub'],
                # sourcing
                source=d['source'], entity_id=d['id'], page=d['page'], url=d['url'], is_free=d['isFree'])
コード例 #2
0
ファイル: sheetManager.py プロジェクト: rtotheichie/avrae
    async def attack_import(self, ctx, *, data):
        """
        Imports an attack from JSON exported from the Avrae Dashboard.
        """
        character: Character = await Character.from_ctx(ctx)

        try:
            attack_json = json.loads(data)
        except json.decoder.JSONDecodeError:
            return await ctx.send("This is not a valid attack.")

        if not isinstance(attack_json, list):
            attack_json = [attack_json]

        try:
            attacks = AttackList.from_dict(attack_json)
        except:
            return await ctx.send("This is not a valid attack.")

        conflicts = [a for a in character.overrides.attacks if a.name.lower() in [new.name.lower() for new in attacks]]
        if conflicts:
            if await confirm(ctx, f"This will overwrite {len(conflicts)} attacks with the same name "
                                  f"({', '.join(c.name for c in conflicts)}). Continue?"):
                for conflict in conflicts:
                    character.overrides.attacks.remove(conflict)
            else:
                return await ctx.send("Okay, aborting.")

        character.overrides.attacks.extend(attacks)
        await character.commit(ctx)

        out = f"Imported {len(attacks)} attacks:\n{attacks.build_str(character)}"
        await ctx.send(out)
コード例 #3
0
 def from_bestiary(cls, data):
     for key in ('traits', 'actions', 'reactions', 'legactions'):
         data[key] = [Trait(**t) for t in data.pop(key)]
     data['spellcasting'] = Spellbook.from_dict(data.pop('spellbook'))
     data['saves'] = Saves.from_dict(data['saves'])
     data['skills'] = Skills.from_dict(data['skills'])
     data['ability_scores'] = BaseStats.from_dict(data['ability_scores'])
     data['attacks'] = AttackList.from_dict(data['attacks'])
     if 'display_resists' in data:
         data['display_resists'] = Resistances.from_dict(
             data['display_resists'])
     return cls(**data)
コード例 #4
0
ファイル: monster.py プロジェクト: driesceuppens/avrae
 def from_bestiary(cls, data, source):
     for key in ('traits', 'actions', 'reactions', 'legactions'):
         data[key] = [Trait(**t) for t in data.pop(key)]
     data['spellcasting'] = MonsterSpellbook.from_dict(data.pop('spellbook'))
     data['saves'] = Saves.from_dict(data['saves'])
     data['skills'] = Skills.from_dict(data['skills'])
     data['ability_scores'] = BaseStats.from_dict(data['ability_scores'])
     data['attacks'] = AttackList.from_dict(data['attacks'])
     if 'resistances' in data:
         data['resistances'] = Resistances.from_dict(data['resistances'])
     if 'display_resists' in data:
         data['display_resists'] = Resistances.from_dict(data['display_resists'], smart=False)
     else:
         data['display_resists'] = Resistances()
     if 'source' in data:
         del data['source']
     return cls(homebrew=True, source=source, **data)
コード例 #5
0
ファイル: sheetManager.py プロジェクト: avrae/avrae
    async def attack_import(self, ctx, *, data: str):
        """
        Imports an attack from JSON or YAML exported from the Avrae Dashboard.
        """
        # strip any code blocks
        if data.startswith(('```\n', '```json\n', '```yaml\n', '```yml\n',
                            '```py\n')) and data.endswith('```'):
            data = '\n'.join(data.split('\n')[1:]).rstrip('`\n')

        character: Character = await Character.from_ctx(ctx)

        try:
            attack_json = yaml.safe_load(data)
        except yaml.YAMLError:
            return await ctx.send("This is not a valid attack.")

        if not isinstance(attack_json, list):
            attack_json = [attack_json]

        try:
            attacks = AttackList.from_dict(attack_json)
        except Exception:
            return await ctx.send("This is not a valid attack.")

        conflicts = [
            a for a in character.overrides.attacks
            if a.name.lower() in [new.name.lower() for new in attacks]
        ]
        if conflicts:
            if await confirm(
                    ctx,
                    f"This will overwrite {len(conflicts)} attacks with the same name "
                    f"({', '.join(c.name for c in conflicts)}). Continue? (Reply with yes/no)"
            ):
                for conflict in conflicts:
                    character.overrides.attacks.remove(conflict)
            else:
                return await ctx.send("Okay, aborting.")

        character.overrides.attacks.extend(attacks)
        await character.commit(ctx)

        out = f"Imported {len(attacks)} attacks:\n{attacks.build_str(character)}"
        await ctx.send(out)
コード例 #6
0
 def attacks(self):
     if 'attacks' not in self._cache:
         # attacks granted by effects are cached so that the same object is referenced in initTracker (#950)
         self._cache['attacks'] = self._attacks + AttackList.from_dict(self.active_effects('attack'))
     return self._cache['attacks']
コード例 #7
0
ファイル: bestiary.py プロジェクト: veilheim/avrae
def _monster_factory(data, bestiary_name):
    ability_scores = BaseStats(data['stats']['proficiencyBonus'] or 0,
                               data['stats']['abilityScores']['strength'] or 10,
                               data['stats']['abilityScores']['dexterity'] or 10,
                               data['stats']['abilityScores']['constitution'] or 10,
                               data['stats']['abilityScores']['intelligence'] or 10,
                               data['stats']['abilityScores']['wisdom'] or 10,
                               data['stats']['abilityScores']['charisma'] or 10)
    cr = {0.125: '1/8', 0.25: '1/4', 0.5: '1/2'}.get(data['stats']['challengeRating'],
                                                     str(data['stats']['challengeRating']))
    num_hit_die = data['stats']['numHitDie']
    hit_die_size = data['stats']['hitDieSize']
    con_by_level = num_hit_die * ability_scores.get_mod('con')
    hp = floor(((hit_die_size + 1) / 2) * num_hit_die) + con_by_level
    hitdice = f"{num_hit_die}d{hit_die_size} + {con_by_level}"

    proficiency = data['stats']['proficiencyBonus']
    if proficiency is None:
        raise ExternalImportError(f"Monster's proficiency bonus is nonexistent ({data['name']}).")

    skills = Skills.default(ability_scores)
    skill_updates = {}
    for skill in data['stats']['skills']:
        name = spaced_to_camel(skill['name'])
        if skill['proficient']:
            mod = skills[name].value + proficiency
        else:
            mod = skill.get('value')
        if mod is not None:
            skill_updates[name] = mod
    skills.update(skill_updates)

    saves = Saves.default(ability_scores)
    save_updates = {}
    for save in data['stats']['savingThrows']:
        name = save['ability'].lower() + 'Save'
        if save['proficient']:
            mod = saves.get(name).value + proficiency
        else:
            mod = save.get('value')
        if mod is not None:
            save_updates[name] = mod
    saves.update(save_updates)

    attacks = []
    traits, atks = parse_critterdb_traits(data, 'additionalAbilities')
    attacks.extend(atks)
    actions, atks = parse_critterdb_traits(data, 'actions')
    attacks.extend(atks)
    reactions, atks = parse_critterdb_traits(data, 'reactions')
    attacks.extend(atks)
    legactions, atks = parse_critterdb_traits(data, 'legendaryActions')
    attacks.extend(atks)

    attacks = AttackList.from_dict(attacks)
    spellcasting = parse_critterdb_spellcasting(traits, ability_scores)

    resistances = Resistances.from_dict(dict(vuln=data['stats']['damageVulnerabilities'],
                                             resist=data['stats']['damageResistances'],
                                             immune=data['stats']['damageImmunities']))

    return Monster(name=data['name'], size=data['stats']['size'], race=data['stats']['race'],
                   alignment=data['stats']['alignment'],
                   ac=data['stats']['armorClass'], armortype=data['stats']['armorType'], hp=hp, hitdice=hitdice,
                   speed=data['stats']['speed'], ability_scores=ability_scores, saves=saves, skills=skills,
                   senses=', '.join(data['stats']['senses']), resistances=resistances, display_resists=resistances,
                   condition_immune=data['stats']['conditionImmunities'], languages=data['stats']['languages'], cr=cr,
                   xp=data['stats']['experiencePoints'], traits=traits, actions=actions, reactions=reactions,
                   legactions=legactions, la_per_round=data['stats']['legendaryActionsPerRound'],
                   attacks=attacks, proper=data['flavor']['nameIsProper'], image_url=data['flavor']['imageUrl'],
                   spellcasting=spellcasting, homebrew=True, source=bestiary_name)
コード例 #8
0
    def from_data(cls, data):
        # print(f"Parsing {data['name']}")
        _type = parse_type(data['type'])
        alignment = parse_alignment(data['alignment'])
        speed = parse_speed(data['speed'])
        ac = data['ac']['ac']
        armortype = data['ac'].get('armortype') or None
        if not 'special' in data['hp']:
            hp = data['hp']['average']
            hitdice = data['hp']['formula']
        else:
            hp = 0
            hitdice = data['hp']['special']
        scores = BaseStats(0, data['str'] or 10, data['dex'] or 10, data['con']
                           or 10, data['int'] or 10, data['wis'] or 10,
                           data['cha'] or 10)
        if isinstance(data['cr'], dict):
            cr = data['cr']['cr']
        else:
            cr = data['cr']

        # resistances
        vuln = parse_resists(data['vulnerable'],
                             notated=False) if 'vulnerable' in data else None
        resist = parse_resists(data['resist'],
                               notated=False) if 'resist' in data else None
        immune = parse_resists(data['immune'],
                               notated=False) if 'immune' in data else None

        display_resists = Resistances(*[
            parse_resists(data.get(r))
            for r in ('resist', 'immune', 'vulnerable')
        ])

        condition_immune = data.get('conditionImmune',
                                    []) if 'conditionImmune' in data else None

        languages = data.get('languages',
                             '').split(', ') if 'languages' in data else None

        traits = [Trait(t['name'], t['text']) for t in data.get('trait', [])]
        actions = [Trait(t['name'], t['text']) for t in data.get('action', [])]
        legactions = [
            Trait(t['name'], t['text']) for t in data.get('legendary', [])
        ]
        reactions = [
            Trait(t['name'], t['text']) for t in data.get('reaction', [])
        ]

        skills = Skills.default(scores)
        skills.update(data['skill'])

        saves = Saves.default(scores)
        saves.update(data['save'])

        scores.prof_bonus = _calc_prof(scores, saves, skills)

        source = data['source']
        proper = bool(data.get('isNamedCreature') or data.get('isNPC'))

        attacks = AttackList.from_dict(data.get('attacks', []))
        spellcasting = data.get('spellcasting', {})
        spells = [SpellbookSpell(s) for s in spellcasting.get('spells', [])]
        spellbook = Spellbook({}, {}, spells, spellcasting.get('dc'),
                              spellcasting.get('attackBonus'),
                              spellcasting.get('casterLevel', 1))

        return cls(data['name'],
                   parsesize(data['size']),
                   _type,
                   alignment,
                   ac,
                   armortype,
                   hp,
                   hitdice,
                   speed,
                   scores,
                   cr,
                   xp_by_cr(cr),
                   data['passive'],
                   data.get('senses', ''),
                   vuln,
                   resist,
                   immune,
                   condition_immune,
                   saves,
                   skills,
                   languages,
                   traits,
                   actions,
                   reactions,
                   legactions,
                   3,
                   data.get('srd', False),
                   source,
                   attacks,
                   spellcasting=spellbook,
                   page=data.get('page'),
                   proper=proper,
                   display_resists=display_resists)