Exemple #1
0
    async def game_spellslot(self, ctx, level: int = None, value: str = None, *args):
        """
        Views or sets your remaining spell slots.
        __Valid Arguments__
        nopact - Modifies normal spell slots first instead of a Pact Magic slots, if applicable.
        """
        if level is not None:
            try:
                assert 0 < level < 10
            except AssertionError:
                return await ctx.send("Invalid spell level.")
        character: Character = await Character.from_ctx(ctx)
        embed = EmbedWithCharacter(character)

        if level is None and value is None:  # show remaining
            embed.description = f"__**Remaining Spell Slots**__\n{character.spellbook.slots_str()}"
        elif value is None:
            embed.description = f"__**Remaining Level {level} Spell Slots**__\n" \
                                f"{character.spellbook.slots_str(level)}"
        else:
            old_slots = character.spellbook.get_slots(level)
            value = maybe_mod(value, old_slots)
            character.spellbook.set_slots(level, value, pact='nopact' not in args)
            await character.commit(ctx)
            embed.description = f"__**Remaining Level {level} Spell Slots**__\n" \
                                f"{character.spellbook.slots_str(level)} ({(value - old_slots):+})"

        # footer - pact vs non pact
        if character.spellbook.max_pact_slots is not None:
            embed.set_footer(text=f"{constants.FILLED_BUBBLE} = Available / {constants.EMPTY_BUBBLE} = Used\n"
                                  f"{constants.FILLED_BUBBLE_ALT} / {constants.EMPTY_BUBBLE_ALT} = Pact Slot")
        else:
            embed.set_footer(text=f"{constants.FILLED_BUBBLE} = Available / {constants.EMPTY_BUBBLE} = Used")

        await ctx.send(embed=embed)
Exemple #2
0
    def run(self, autoctx):
        super(Save, self).run(autoctx)
        save = autoctx.args.last('save') or self.stat
        auto_pass = autoctx.args.last('pass', type_=bool, ephem=True)
        auto_fail = autoctx.args.last('fail', type_=bool, ephem=True)
        hide = autoctx.args.last('h', type_=bool)

        dc_override = None
        if self.dc:
            try:
                dc_override = autoctx.parse_annostr(self.dc)
                dc_override = int(dc_override)
            except (TypeError, ValueError):
                raise AutomationException(
                    f"{dc_override} cannot be interpreted as a DC.")

        # dc hierarchy: arg > self.dc > spell cast override > spellbook dc
        dc = dc_override or autoctx.dc_override or autoctx.caster.spellbook.dc
        if 'dc' in autoctx.args:
            dc = maybe_mod(autoctx.args.last('dc'), dc)

        if dc is None:
            raise NoSpellDC(
                "No spell save DC found. Use the `-dc` argument to specify one!"
            )
        try:
            save_skill = next(s
                              for s in ('strengthSave', 'dexteritySave',
                                        'constitutionSave', 'intelligenceSave',
                                        'wisdomSave', 'charismaSave')
                              if save.lower() in s.lower())
        except StopIteration:
            raise InvalidSaveType()

        autoctx.meta_queue(f"**DC**: {dc}")
        if not autoctx.target.is_simple:
            save_blurb = f'{save_skill[:3].upper()} Save'
            if auto_pass:
                is_success = True
                autoctx.queue(f"**{save_blurb}:** Automatic success!")
            elif auto_fail:
                is_success = False
                autoctx.queue(f"**{save_blurb}:** Automatic failure!")
            else:
                saveroll = autoctx.target.get_save_dice(
                    save_skill, adv=autoctx.args.adv(boolwise=True))
                save_roll = roll(saveroll)
                is_success = save_roll.total >= dc
                success_str = ("; Success!" if is_success else "; Failure!")
                out = f"**{save_blurb}**: {save_roll.result}{success_str}"
                if not hide:
                    autoctx.queue(out)
                else:
                    autoctx.add_pm(str(autoctx.ctx.author.id), out)
                    autoctx.queue(f"**{save_blurb}**: 1d20...{success_str}")
        else:
            autoctx.meta_queue('{} Save'.format(save_skill[:3].upper()))
            is_success = False

        if is_success:
            damage = self.on_success(autoctx)
        else:
            damage = self.on_fail(autoctx)
        return {"total": damage}
Exemple #3
0
    def run(self, autoctx):
        super().run(autoctx)
        if autoctx.target is None:
            raise TargetException("Tried to make a save without a target! Make sure all Save effects are inside "
                                  "of a Target effect.")

        # ==== args ====
        save = autoctx.args.last('save') or self.stat
        sb = autoctx.args.get('sb', ephem=True)
        auto_pass = autoctx.args.last('pass', type_=bool, ephem=True)
        auto_fail = autoctx.args.last('fail', type_=bool, ephem=True)
        hide = autoctx.args.last('h', type_=bool)

        # ==== dc ====
        dc_override = None
        if self.dc:
            try:
                dc_override = autoctx.parse_intexpression(self.dc)
            except Exception:
                raise AutomationException(f"{self.dc!r} cannot be interpreted as a DC.")

        # dc hierarchy: arg > self.dc > spell cast override > spellbook dc
        dc = dc_override or autoctx.dc_override or autoctx.caster.spellbook.dc
        if 'dc' in autoctx.args:
            dc = maybe_mod(autoctx.args.last('dc'), dc)

        if dc is None:
            raise NoSpellDC("No spell save DC found. Use the `-dc` argument to specify one!")
        try:
            save_skill = next(s for s in ('strengthSave', 'dexteritySave', 'constitutionSave',
                                          'intelligenceSave', 'wisdomSave', 'charismaSave') if
                              save.lower() in s.lower())
            stat = save_skill[:3]
        except StopIteration:
            raise InvalidSaveType()

        # ==== ieffects ====
        if autoctx.target.combatant:
            # Combine args/ieffect advantages - adv/dis (#1552)
            sadv_effects = autoctx.target.combatant.active_effects('sadv')
            sdis_effects = autoctx.target.combatant.active_effects('sdis')
            sadv = 'all' in sadv_effects or stat in sadv_effects
            sdis = 'all' in sdis_effects or stat in sdis_effects
            adv = reconcile_adv(
                adv=autoctx.args.last('sadv', type_=bool, ephem=True) or sadv,
                dis=autoctx.args.last('sdis', type_=bool, ephem=True) or sdis
            )
        else:
            adv = autoctx.args.adv(custom={'adv': 'sadv', 'dis': 'sdis'})

        # ==== execution ====
        save_roll = None
        autoctx.metavars['lastSaveRollTotal'] = 0
        autoctx.metavars['lastSaveNaturalRoll'] = 0  # 1495
        autoctx.metavars['lastSaveDC'] = dc
        autoctx.metavars['lastSaveAbility'] = verbose_stat(stat)
        autoctx.meta_queue(f"**DC**: {dc}")

        if not autoctx.target.is_simple:
            save_blurb = f'{stat.upper()} Save'
            if auto_pass:
                is_success = True
                autoctx.queue(f"**{save_blurb}:** Automatic success!")
            elif auto_fail:
                is_success = False
                autoctx.queue(f"**{save_blurb}:** Automatic failure!")
            else:
                save_dice = autoctx.target.get_save_dice(save_skill, adv=adv, sb=sb)
                save_roll = d20.roll(save_dice)
                is_success = save_roll.total >= dc

                # get natural roll
                d20_value = d20.utils.leftmost(save_roll.expr).total

                autoctx.metavars['lastSaveRollTotal'] = save_roll.total  # 1362
                autoctx.metavars['lastSaveNaturalRoll'] = d20_value  # 1495

                success_str = ("; Success!" if is_success else "; Failure!")
                out = f"**{save_blurb}**: {save_roll.result}{success_str}"
                if not hide:
                    autoctx.queue(out)
                else:
                    autoctx.add_pm(str(autoctx.ctx.author.id), out)
                    autoctx.queue(f"**{save_blurb}**: 1d20...{success_str}")
        else:
            autoctx.meta_queue(f'{stat.upper()} Save')
            is_success = False

        # Disable critical damage state for children (#1556)
        original = autoctx.in_save
        autoctx.in_save = True

        if is_success:
            children = self.on_success(autoctx)
        else:
            children = self.on_fail(autoctx)

        autoctx.in_save = original  # Restore proper crit state (#1556)

        return SaveResult(dc=dc, ability=save_skill, save_roll=save_roll, adv=adv, did_save=is_success,
                          children=children)
Exemple #4
0
 def ac(self):
     _ac = self._ac or self.character.ac
     for e in self.active_effects('ac'):
         _ac = maybe_mod(e, base=_ac)
     return _ac