hotdog/hotdog/command/roll.py

59 lines
1.7 KiB
Python

import re
from collections import defaultdict
from random import randint
from ..functions import reply
from ..models import Message
HELP = """Würfelt eine Summe aus.
!roll [how many]d<sides> [ ... ]
"""
parse_die = re.compile("(?P<num>\d*)[dwDW](?P<sides>\d+)").fullmatch
def init(bot):
bot.on_command("roll", handle)
async def handle(message: Message):
if len(message.args) == 1 and message.args[0].isdecimal():
dice = [(1, int(message.args[0]))]
else:
dice = []
num = None
for arg in message.args:
if (match := parse_die(arg)) :
if num and match["num"]:
return
num, sides = int(match["num"] or num or 1), int(match["sides"])
if not 1 <= num < 1000 or not 2 <= sides <= 100:
return
dice.append((num, sides))
num = None
elif arg.isdecimal():
if num is not None:
return
num = int(arg)
else:
return
if not 0 < len(dice) < 20:
return
rolls = defaultdict(list)
for num, sides in dice:
for _ in range(num):
rolls[sides].append(randint(1, sides))
total = sum(sum(vs) for sides, vs in rolls.items())
if len(rolls) == 1:
sides = list(rolls.keys())[0]
text = f"{total} ({len(rolls[sides])}d{sides})"
else:
dicestr = " + ".join(
f"{len(vs)}d{sides} ({sum(vs)})"
for sides, vs in sorted(rolls.items(), key=lambda i: i[0], reverse=1)
)
text = f"{total} = {dicestr}"
await reply(message, plain=text, in_thread=True)