예제 #1
0
    def getMeleeAtks(self, item_name=None):
        items = []
        if item_name is None:
            items = [w for w, _ in self.equipment.getWieldedItems()]
        else:
            itemno = self.equipment.find(item_name)
            if itemno >= 0:
                items = [self.equipment.equipment[itemno]]

        weapons = []
        for weapon in items:
            if not weapon.isWeapon():
                continue
            if not weapon.isWielding():
                continue
            if not weapon.hasTag("melee"):
                continue
            weapons.append(weapon)

        if len(weapons) == 0:
            raise NotWieldingItems

        out = []
        str = self.stats.getMod("str")

        for idx, weapon in enumerate(weapons):
            desc = f"{weapon.description}"

            atk = f"1d20 +{self.getBtH()} [BtH] +{weapon.bth} [w BtH]"
            atk += f" +{str} [str]"

            if len(weapons) > 1:
                dex = self.stats.getMod("dex")
                dw_malus = 3 * (1 + idx)
                atk += f" -{dw_malus} [dual w] +{dex} [dex]"

            dmg = f"{weapon.damage} [w dmg]"
            dmg += f" +{str} [str]"
            if (self.god == "Thor" and self.xclass == "Cleric"
                    and weapon.description.lower().find("hammer") != -1):
                dmg += f" +2 [god]"

            out.append(desc)
            out.append("- atk:")
            out.append(roll(atk).__str__())
            out.append("- dmg:")
            out.append(roll(dmg).__str__())

        return "\n".join(out)
예제 #2
0
 async def rrr(self,
               ctx,
               iterations: int,
               rollStr,
               dc: int = 0,
               *,
               args=""):
     """Rolls dice in xdy format, given a set dc.
     Usage: !rrr <iterations> <xdy> <DC> [args]"""
     if iterations < 1 or iterations > 100:
         return await ctx.send("Too many or too few iterations.")
     adv = 0
     out = []
     successes = 0
     if re.search("(^|\s+)(adv|dis)(\s+|$)", args) is not None:
         adv = 1 if re.search("(^|\s+)adv(\s+|$)", args) is not None else -1
         args = re.sub("(adv|dis)(\s+|$)", "", args)
     for r in range(iterations):
         res = roll(rollStr, adv=adv, rollFor=args, inline=True)
         if res.plain >= dc:
             successes += 1
         out.append(res)
     outStr = "Rolling {} iterations, DC {}...\n".format(iterations, dc)
     outStr += "\n".join([o.skeleton for o in out])
     if len(outStr) < 1500:
         outStr += "\n{} successes.".format(str(successes))
     else:
         outStr = "Rolling {} iterations, DC {}...\n[Output truncated due to length]\n".format(
             iterations, dc) + "{} successes.".format(str(successes))
     await try_delete(ctx.message)
     await ctx.send(ctx.author.mention + "\n" + outStr)
     await Stats.increase_stat(ctx, "dice_rolled_life")
예제 #3
0
 async def rr(self, ctx, iterations: int, rollStr, *, args=""):
     """Rolls dice in xdy format a given number of times.
     Usage: !rr <iterations> <xdy> [args]"""
     if iterations < 1 or iterations > 100:
         return await ctx.send("Too many or too few iterations.")
     adv = 0
     out = []
     if re.search("(^|\s+)(adv|dis)(\s+|$)", args) is not None:
         adv = 1 if re.search("(^|\s+)adv(\s+|$)", args) is not None else -1
         args = re.sub("(adv|dis)(\s+|$)", "", args)
     for _ in range(iterations):
         res = roll(rollStr, adv=adv, rollFor=args, inline=True)
         out.append(res)
     outStr = "Rolling {} iterations...\n".format(iterations)
     outStr += "\n".join([o.skeleton for o in out])
     if len(outStr) < 1500:
         outStr += "\n{} total.".format(sum(o.total for o in out))
     else:
         outStr = (
             "Rolling {} iterations...\n[Output truncated due to length]\n".
             format(iterations) +
             "{} total.".format(sum(o.total for o in out)))
     await try_delete(ctx.message)
     await ctx.send(ctx.author.mention + "\n" + outStr)
     await Stats.increase_stat(ctx, "dice_rolled_life")
예제 #4
0
 def levelUp(self):
     """Level up and roll new hit points."""
     hd: int
     if self.xclass == "Barbarian" or self.xclass == "Monk":
         hd = 12
     elif (self.xclass == "Fighter" or self.xclass == "Ranger"
           or self.xclass == "Knight" or self.xclass == "Paladin"
           or self.xclass == "Bard"):
         hd = 10
     elif self.xclass == "Cleric" or self.xclass == "Druid":
         hd = 8
     elif self.xclass == "Rogue" or self.xclass == "Assassin":
         hd = 6
     elif self.xclass == "Wizard" or self.xclass == "Illusionist":
         hd = 4
     else:
         raise InvalidArgument(f"{self.xclass} is not a valid class.")
     con_mod = self.stats.getMod("con")
     result = [roll(f"1d{hd}{con_mod:+}", inline=True) for _ in range(1)]
     total = result[0].total
     if total < 1:
         total = 1
     self.hp.max += total
     self.hp.current += total
     self.level += 1
     hptxt = "hit points"
     if total == 1:
         hptxt = "hit point"
     return (
         f"{self.name} levels up! :partying_face:\n" +
         f":game_die: {result[0].skeleton}\n" +
         f"{self.name} advances to level {self.level} and gains {total} {hptxt} (total hp: {self.hp.max})."
     )
예제 #5
0
    def siegeCheck(self, name: str, level: int, stat: str, bonus: int,
                   cl: int):
        cb = 18
        mod = self.getMod(stat)
        prime = self.getPrime(stat)
        all_mods = level + mod + prime + bonus
        result = [roll(f"1d20{all_mods:+}", inline=True) for _ in range(1)]
        total = result[0].total
        if total > cb and cl == 0:
            success = f"Success against CL{total-cb}!"
        elif total >= cb + cl:
            success = f"Success (CL{cl})! :grinning:"
        else:
            success = (f"Failure ({total-cb})"
                       if name == "secret_check" else "Failure! :scream:")

        # Long-form result for normal checks
        known_cl = f"against challenge level {cl}" if cl > 0 else ""
        bonuses = f"{level:+} for level"
        if mod != 0:
            bonuses = bonuses + f", {mod:+} modifier"
        if prime != 0:
            bonuses = bonuses + f", {prime:+} for prime attribute"
        if bonus != 0:
            bonuses = bonuses + f", {bonus:+} bonus"

        if name == "secret_check":
            return f"{success}                                                                                \nBonuses are {bonuses} = {all_mods:+}\n:game_die: {result[0].skeleton}"
        else:
            return f"{name} makes a {stat.upper()} check {known_cl}\nBonuses are {bonuses} = {all_mods:+}\n:game_die: {result[0].skeleton}\n{success}"
예제 #6
0
    def rest(self, name: str, conMod: int, duration: int):
        if self.wound == Wound.DEAD:
            return f"{name} gets rigor mortis."
        result = ""
        if not self.conscious:
            self.conscious = True
            hours = [roll("1d6", inline=True) for _ in range(1)]
            result = f"{name} recovers consciousness after {hours[0].total} hours."
        if self.wound == Wound.MORTAL:
            self.wound = Wound.GRIEVOUS
            result += f"\n{name} is no longer mortally wounded."
            duration -= 1
        if duration > 0 and self.wound == Wound.GRIEVOUS:
            self.wound = Wound.NORMAL
            result += f"\n{name} is no longer greviously wounded."
            duration -= 1

        if duration > 0 and duration < 7:
            result += self.recover(name, duration)
            duration = 0
        elif duration > 0:
            result += self.recover(name, 7)
            duration -= 7

        if duration > 0:
            heal_rate = 1
            if conMod > 0:
                heal_rate += conMod
            result += self.recover(name, duration * heal_rate)

        return result
예제 #7
0
 def first_aid(self):
     all_mods = (self.getLevel() + self.stats.getMod("con") +
                 self.stats.getPrime("con"))
     result = [roll(f"1d20{all_mods:+}", inline=True) for _ in range(1)]
     total = result[0].total
     success = total > 18
     check = f"{self.getName()} makes a Constitution check.\n:game_die: {result[0].skeleton}"
     return self.getHp().first_aid(self.getName(), check, success)
예제 #8
0
 def rollHp(self, already_rolled: int = 0):
     result = [
         roll(f"{self.hd}", inline=True)
         for _ in range(self.count - already_rolled)
     ]
     for hp in result:
         print(f"{hp.skeleton}")
     return [hp.total for hp in result]
예제 #9
0
 async def genStats(self, ctx):
     """Randomly generate the six base stats for a new character."""
     rolls = [roll("4d6kh3", inline=True) for _ in range(6)]
     # self.stats.set(rolls[0].total, rolls[1].total, rolls[2].total, rolls[3].total, rolls[4].total, rolls[5].total)
     stat_summary = "\n:game_die: ".join(r.skeleton for r in rolls)
     total = sum([r.total for r in rolls])
     await ctx.send(
         f"{ctx.message.author.mention}\nGenerated random stats:\n:game_die: {stat_summary}\nTotal = `{total}`"
     )
예제 #10
0
    def getShootAtk(self, ammo_name):
        itemno = self.equipment.find(ammo_name)
        if itemno >= 0:
            ammo = self.equipment.equipment[itemno]
        else:
            raise ItemNotFound

        weapon = self.equipment.getWieldedItems()
        if not weapon:
            raise NotWieldingItems
        weapon = weapon[0][0]

        if not weapon.hasTag("shoot"):
            raise NotWieldingItems
        elif not ammo.isAmmo():
            raise NotWieldingItems(
                f"The item {ammo.description} is not an ammo.")
        elif not ammo.hasAnyTag(list(weapon.tags)):
            raise NotWieldingItems(
                f"The wielded weapon and the ammo are not compatible (they do not share tags)."
            )

        out = []
        str = self.stats.getMod("dex")

        desc = f"{weapon.description}"

        atk = (
            f"1d20 +{self.getBtH()} [BtH] +{weapon.bth} [w BtH] +{ammo.bth} [ammo BtH]"
        )
        atk += f" +{str} [dex]"

        dmg = f"{weapon.damage} [w dmg] +{ammo.damage} [ammo dmg]"
        dmg += f" +{str} [str]"

        out.append(desc)
        out.append("- atk:")
        out.append(roll(atk).__str__())
        out.append("- dmg:")
        out.append(roll(dmg).__str__())

        self.equipment.drop(ammo.description, 1)

        return "\n".join(out)
예제 #11
0
    def getThrowAtk(self, ammo_or_weapon_name):
        itemno = self.equipment.find(ammo_or_weapon_name)
        if itemno >= 0:
            weapon = self.equipment.equipment[itemno]
        else:
            raise ItemNotFound

        if not weapon.hasTag("throw"):
            raise NotWieldingItems
        elif not weapon.isAmmo() and not weapon.isWeapon():
            raise NotWieldingItems

        out = []
        str = self.stats.getMod("str")
        dex = self.stats.getMod("dex")

        desc = f"{weapon.description}"

        atk = f"1d20 +{self.getBtH()} [BtH] +{weapon.bth} [w BtH]"
        atk += f" +{dex} [dex]"
        if (self.god == "Thor" and self.xclass == "Cleric"
                and weapon.description.lower().find("hammer") != -1):
            atk += " +3 [god]"

        dmg = f"{weapon.damage} [w dmg]"
        dmg += f" +{str} [str]"
        if (self.god == "Thor" and self.xclass == "Cleric"
                and weapon.description.lower().find("hammer") != -1):
            dmg += f" +2 [god]"

        out.append(desc)
        out.append("- atk:")
        out.append(roll(atk).__str__())
        out.append("- dmg:")
        out.append(roll(dmg).__str__())

        if weapon.isAmmo():
            self.equipment.drop(weapon.description, 1)
        elif weapon.isWeapon():
            self.equipment.markAsDropped(weapon.description)

        return "\n".join(out)
예제 #12
0
 def heal(self, heal: str):
     heal_roll = ""
     heal_amt: int
     try:
         int(heal)
         heal_amt = int(heal)
     except ValueError:
         result = [roll(f"{heal}", inline=True) for _ in range(1)]
         heal_amt = result[0].total
         heal_roll = f":game_die: {result[0].skeleton}\n"
     return f"{heal_roll}{self.getHp().heal(self.getName(), heal_amt)}"
예제 #13
0
 def damage(self, dmg: str):
     dmg_roll = ""
     dmg_amt: int
     try:
         int(dmg)
         dmg_amt = int(dmg)
     except ValueError:
         result = [roll(f"{dmg}", inline=True) for _ in range(1)]
         dmg_amt = result[0].total
         dmg_roll = f":game_die: {result[0].skeleton}\n"
     return f"{dmg_roll}{self.getHp().lose(self.getName(), dmg_amt)}"
예제 #14
0
    async def rollCmd(self, ctx, *, rollStr: str = "1d20"):
        """Rolls dice in xdy format.
        __Examples__
        !r xdy Attack!
        !r xdy+z adv Attack with Advantage!
        !r xdy-z dis Hide with Heavy Armor!
        !r xdy+xdy*z
        !r XdYkhZ
        !r 4d6mi2[fire] Elemental Adept, Fire
        !r 2d6e6 Explode on 6
        !r 10d6ra6 Spell Bombardment
        !r 4d6ro<3 Great Weapon Master
        __Supported Operators__
        k (keep)
        p (drop)
        ro (reroll once)
        rr (reroll infinitely)
        mi/ma (min/max result)
        e (explode dice of value)
        ra (reroll and add)
        __Supported Selectors__
        lX (lowest X)
        hX (highest X)
        >X/<X (greater than or less than X)"""

        if rollStr == "0/0":  # easter eggs
            return await ctx.send(
                "What do you expect me to do, destroy the universe?")

        adv = 0
        if re.search("(^|\s+)(adv|dis)(\s+|$)", rollStr) is not None:
            adv = 1 if re.search("(^|\s+)adv(\s+|$)",
                                 rollStr) is not None else -1
            rollStr = re.sub("(adv|dis)(\s+|$)", "", rollStr)
        res = roll(rollStr, adv=adv)
        out = res.result
        await try_delete(ctx.message)
        outStr = ctx.author.mention + "  :game_die:\n" + out
        if len(outStr) > 1999:
            await ctx.send(
                ctx.author.mention +
                "  :game_die:\n[Output truncated due to length]\n**Result:** "
                + str(res.plain))
        else:
            await ctx.send(outStr)
        await Stats.increase_stat(ctx, "dice_rolled_life")
예제 #15
0
 def rollForInitiative(self):
     dex_mod = self.stats.getMod("dex")
     result = [roll(f"2d6{dex_mod:+}", inline=True) for _ in range(1)]
     init = result[0].total
     return (init,
             f":game_die: {self.getName()} rolls 2d6{dex_mod:+} = {init}\n")