Discord.py D&D 掷骰子命令有太多问题

Discord.py D&D dice roll command has far too many issues

所以我所有的 D&D 党员都相信当前的骰子机器人是“被诅咒的”,所以我决定自己动手制作自己的机器人。这很酷,但是我的掷骰子命令有多个问题。

我目前的命令是

async def d(ctx, die:int):
    for x in range(1):
        await ctx.send("<:d20:748302353375166614> "+str(random.randint(1,die)))

第一个问题是它使用格式“|d 20”而不是“|d20”,因此第一个请求将摆脱“d”和 int 之间的 space表示骰子的面数(“die”变量,本例中为“20”)。

除此之外,我想添加一项功能,如果输入“|[骰子数]d[面数] ”,它会按照要求的次数掷出要求的骰子。如果未指定骰子数(例如:“|d20”),它应该自动假定骰子数为 1。机器人消息应包括所有掷出的数字及其总和。

例如“|2d20”可能 return“<:d20:748302353375166614>11 + 15 = 26”,而“|10d2”可能 return "<:d20:748302353375166614> 1 + 1 + 2 + 1 + 2 + 2 + 2 + 1 + 1 + 2 = 15"

除此之外,我还希望能够为掷骰添加奖励(“|[骰子数量]d [边数]+[奖金]") 和 return 机器人消息中的骰子掷骰、奖金和最终值。

例如“|d20+4”可能 return“<:d20:748302353375166614>11 + 4 = 15”和“|2d10+2+ 3" 可能 return "<:d20:748302353375166614> 9 + 4 + 2 + 3 = 18"

(可选地,如果痛苦地写下这个问题的答案的人觉得他们还没有因为这个请求的规模而感到足够痛苦,那么像“|1d4+2d6”这样的事情可能成为可能)

!roll 3d20+6d8+1 这样的格式怎么样?如果可以接受,您可以这样做:

async def d(ctx, *args):
    dicestring = "".join(args)
    # Process dicestring here

这里,*args 是一个 variable-length 参数说明符。命令的解析方式,!roll 5d6 + 6d12 会给你参数 ("5d6", "+", "6d12")!roll 5d6+6d12 会给你参数 ("5d6+6d12").

"".join(args) 会将所有这些参数简单地混合在一起,为您留下一个您可以根据需要进行解析的字符串。

如果唯一的前缀是 | 对您来说很重要,那么您尝试做的事情就不能很好地融入命令结构。我会考虑将其设为 on_message 事件,例如 https://discordpy.readthedocs.io/en/latest/api.html#discord-api-events.

使用 commands extension, you can't get rid of the space between your command and the die variable. In order to get rid of it, you'd have to use an on_message 事件解析您的命令内容:

from random import sample

@client.event
async def on_message(message):
    content = message.content
    if content.startswith('|') and (content[1].isdigit() or content[1]=='d'):
        content = content.split('+')
        rolls = [int(content.pop(i)) for i in range(len(content)) if content[i].isdigit()]
        for elem in content:
            n, faces = elem.split('d') if elem.split('d')[0] != '' else (1, elem[1:])
            rolls += [randint(1, int(faces)) for _ in range(int(n))]
        rolls_str = ' + '.join([str(n) for n in rolls]) 
        await message.channel.send(f"{rolls_str} = {sum(rolls)}")
    else:
        pass

    await client.process_commands(message)