|
|
|
|
|
|
|
|
x<number> #only use at the end. roll the rest of the expression <number> times(max 10) |
|
|
x<number> #only use at the end. roll the rest of the expression <number> times(max 10) |
|
|
Credit: TBTerra#5677 |
|
|
Credit: TBTerra#5677 |
|
|
""" |
|
|
""" |
|
|
rollMaxRolls = 10 |
|
|
|
|
|
rollMaxVerbose = 10 |
|
|
|
|
|
rollMaxDice = 1000 |
|
|
|
|
|
|
|
|
max_rolls = 10 |
|
|
|
|
|
max_verbose = 10 |
|
|
|
|
|
max_dice = 1000 |
|
|
response = '' |
|
|
response = '' |
|
|
rollVerbose = True |
|
|
|
|
|
|
|
|
roll_verbose = True |
|
|
# sanitise input by removing all spaces, converting to lower case |
|
|
# sanitise input by removing all spaces, converting to lower case |
|
|
expression = expression.lower().replace(' ','') |
|
|
|
|
|
|
|
|
expression = expression.lower().replace(' ', '') |
|
|
|
|
|
|
|
|
# check end of expression for a 'x<number>' |
|
|
# check end of expression for a 'x<number>' |
|
|
parts = expression.split('x',1) |
|
|
|
|
|
|
|
|
parts = expression.split('x', 1) |
|
|
times = 1 |
|
|
times = 1 |
|
|
if len(parts) == 2:#if theres a x |
|
|
|
|
|
try:#try and work out the number after the x |
|
|
|
|
|
|
|
|
if len(parts) == 2: # if theres a x |
|
|
|
|
|
try: # try and work out the number after the x |
|
|
times = int(parts[1]) |
|
|
times = int(parts[1]) |
|
|
if times < 1:#cant roll less than once |
|
|
|
|
|
|
|
|
if times < 1: # cant roll less than once |
|
|
times = 1 |
|
|
times = 1 |
|
|
if times > rollMaxRolls:#dont want to lag the bot/spam the chat by rolling hundreds of times |
|
|
|
|
|
response += "*Warning:* cannot roll an expression more than {0} times. will roll {0} times rather than {1}.\n".format(rollMaxRolls,times) |
|
|
|
|
|
times = rollMaxRolls |
|
|
|
|
|
except ValueError:#probably an input syntax error. safest to just roll once. |
|
|
|
|
|
|
|
|
elif times > max_rolls: # dont want to lag the bot/spam the chat by rolling hundreds of times |
|
|
|
|
|
response += "*Warning:* cannot roll an expression more than {0} times. will roll {0} times rather than {1}.\n".format(max_rolls, times) |
|
|
|
|
|
times = max_rolls |
|
|
|
|
|
except ValueError: # probably an input syntax error. safest to just roll once. |
|
|
times = 1 |
|
|
times = 1 |
|
|
response += "*Warning:* was unable to resolve how many times this command was meant to run. defaulted to once.\n" |
|
|
response += "*Warning:* was unable to resolve how many times this command was meant to run. defaulted to once.\n" |
|
|
m=re.findall('(-?)((?:(\d*)d(\d+))|\d+)(r\d+)?([h,l]{1}\d+)?',parts[0])#voodoo magic regex (matches A,dB,AdB,AdBrC and AdBh/lD all at once, and splits them up to be processed) |
|
|
|
|
|
if m == []:#either there were no arguments, or the expression contained nothing that could be seen as a number or roll |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# voodoo magic regex (matches A,dB,AdB,AdBrC and AdBh/lD all at once, and splits them up to be processed) |
|
|
|
|
|
|
|
|
|
|
|
m = re.findall('(-?)((?:(\d*)d(\d+))|\d+)(r\d+)?([h,l]{1}\d+)?', parts[0]) |
|
|
|
|
|
|
|
|
|
|
|
if m: # either no arguments, or the expression contained nothing that could be seen as a number or roll |
|
|
return await ctx.send("Expression missing. If you are unsure of what the format should be, please use `{}help roll`".format(ctx.prefix)) |
|
|
return await ctx.send("Expression missing. If you are unsure of what the format should be, please use `{}help roll`".format(ctx.prefix)) |
|
|
dice = []#this is the list of all dice sets to be rolled |
|
|
|
|
|
#each element of the list is a 5 element list, containing the sign of the set, how many dice it has, how many sides on each dice, what numbers to re-roll, and how many to select(in that order) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dice = [] # this is the list of all dice sets to be rolled |
|
|
|
|
|
# each element of the list is a 5 element list, containing |
|
|
|
|
|
# [0] the sign of the set |
|
|
|
|
|
# [1] how many dice it has |
|
|
|
|
|
# [2] how many sides on each dice |
|
|
|
|
|
# [3] what numbers to re-roll |
|
|
|
|
|
# [4] and how many to select |
|
|
for item in m: |
|
|
for item in m: |
|
|
temp = [0]*5 |
|
|
temp = [0]*5 |
|
|
temp[0] = 1 if item[0] == '' else -1#if theres a - at the beginning of the sub expression there needs to be a -1 multiplier applied to the sub expression total |
|
|
|
|
|
if 'd' in item[1]:#if its a dice/set of dice rather than a number |
|
|
|
|
|
|
|
|
temp[0] = 1 if item[0] == '' else -1 # if theres a - at the beginning of the sub expression there needs to be a -1 multiplier applied to the sub expression total |
|
|
|
|
|
if 'd' in item[1]: # if its a dice/set of dice rather than a number |
|
|
temp[2] = int(item[3]) |
|
|
temp[2] = int(item[3]) |
|
|
if temp[2] == 0:#safety check for things like 2d0 + 1 (0 sided dice) |
|
|
|
|
|
|
|
|
if temp[2] == 0: # safety check for things like 2d0 + 1 (0 sided dice) |
|
|
return await ctx.send("cant roll a zero sided dice") |
|
|
return await ctx.send("cant roll a zero sided dice") |
|
|
if item[2] == '':#if its just a dY rather than an XdY |
|
|
|
|
|
|
|
|
if item[2] == '': # if its just a dY rather than an XdY |
|
|
temp[1] = 1 |
|
|
temp[1] = 1 |
|
|
else:#its a XdY type unknown if it has r,h,l modifyers, but they dont matter when sorting out the number and sides of dice |
|
|
|
|
|
|
|
|
else: # its a XdY type unknown if it has r,h,l modifyers, but they dont matter when sorting out the number and sides of dice |
|
|
temp[1] = int(item[2]) |
|
|
temp[1] = int(item[2]) |
|
|
if temp[1] > rollMaxDice:#if there are an unreasonable number of dice, error out. almost no-one needs to roll 9999d20 |
|
|
|
|
|
return await ctx.send("I'm sorry {}, I'm afraid I cant do that. (To many dice to roll, max {})".format(self.bot.user.name,rollMaxDice)) |
|
|
|
|
|
if temp[1] > rollMaxVerbose and rollVerbose:#if there is a sub expression that involves lots of rolls then turn off verbose mode |
|
|
|
|
|
rollVerbose = False |
|
|
|
|
|
|
|
|
if temp[1] > max_dice: # if there are an unreasonable number of dice, error out. almost no-one needs to roll 9999d20 |
|
|
|
|
|
return await ctx.send("I can't do that. (Too many dice to roll, max {})".format(ctx.author, max_dice)) |
|
|
|
|
|
if temp[1] > max_verbose and roll_verbose: # if there is a sub expression that involves lots of rolls then turn off verbose mode |
|
|
|
|
|
roll_verbose = False |
|
|
response += '*Warning:* large number of rolls detected, will not use verbose rolling.\n' |
|
|
response += '*Warning:* large number of rolls detected, will not use verbose rolling.\n' |
|
|
else:#numbers are stored as N, 1 sided dice |
|
|
|
|
|
|
|
|
else: # numbers are stored as N, 1 sided dice |
|
|
temp[1] = int(item[1]) |
|
|
temp[1] = int(item[1]) |
|
|
temp[2] = 1 |
|
|
temp[2] = 1 |
|
|
temp[3] = 0 if item[4] == '' else int(item[4][1:])#if it has a reroll value use that. if not, reroll on 0 |
|
|
|
|
|
if item[5] == '':#it has no select requirment |
|
|
|
|
|
|
|
|
temp[3] = 0 if item[4] == '' else int(item[4][1:]) # if it has a reroll value use that. if not, reroll on 0 |
|
|
|
|
|
if item[5] == '': # it has no select requirement |
|
|
temp[4] = 0 |
|
|
temp[4] = 0 |
|
|
else: |
|
|
else: |
|
|
if item[5][0] == 'h':#select highest use positive select argument |
|
|
|
|
|
|
|
|
if item[5][0] == 'h': # select highest use positive select argument |
|
|
temp[4] = int(item[5][1:]) |
|
|
temp[4] = int(item[5][1:]) |
|
|
else:#select lowest so use negative select argument |
|
|
|
|
|
|
|
|
else: # select lowest so use negative select argument |
|
|
temp[4] = -int(item[5][1:]) |
|
|
temp[4] = -int(item[5][1:]) |
|
|
dice.append(temp) |
|
|
dice.append(temp) |
|
|
#at this point dice contains everything needed to do a roll. if you saved dice then you could roll it again without having to re-parse everything (possible roll saving feature in future?) |
|
|
|
|
|
|
|
|
# at this point dice contains everything needed to do a roll. if you saved dice then you could roll it again without having to re-parse everything (possible roll saving feature in future?) |
|
|
for i in range(times): |
|
|
for i in range(times): |
|
|
total = 0 |
|
|
total = 0 |
|
|
if times > 1: |
|
|
if times > 1: |
|
|
response += 'Roll {}: '.format(i+1) |
|
|
response += 'Roll {}: '.format(i+1) |
|
|
else: |
|
|
else: |
|
|
response += 'Rolled: ' |
|
|
response += 'Rolled: ' |
|
|
for j, die in enumerate(dice):#for each dice set in the expression |
|
|
|
|
|
if j != 0 and rollVerbose:#dont need the + before the first element |
|
|
|
|
|
|
|
|
for j, die in enumerate(dice): # for each dice set in the expression |
|
|
|
|
|
if j != 0 and roll_verbose: # dont need the + before the first element |
|
|
response += ' + ' |
|
|
response += ' + ' |
|
|
if die[0] == -1 and rollVerbose:#all the dice sets will return positive numbers so the sign is set entirely by the sign value (element 0) |
|
|
|
|
|
|
|
|
if die[0] == -1 and roll_verbose: # all the dice sets will return positive numbers so the sign is set entirely by the sign value (element 0) |
|
|
response += '-' |
|
|
response += '-' |
|
|
if die[2] == 1:#its just a number |
|
|
|
|
|
if rollVerbose: |
|
|
|
|
|
|
|
|
if die[2] == 1: # its just a number |
|
|
|
|
|
if roll_verbose: |
|
|
response += '{}'.format(die[1]) |
|
|
response += '{}'.format(die[1]) |
|
|
total += die[0] * die[1] |
|
|
total += die[0] * die[1] |
|
|
else:#its a dice or set of dice |
|
|
|
|
|
if rollVerbose: |
|
|
|
|
|
|
|
|
else: # its a dice or set of dice |
|
|
|
|
|
if roll_verbose: |
|
|
response += '(' |
|
|
response += '(' |
|
|
temp = [] |
|
|
temp = [] |
|
|
for k in range(die[1]):#for each dice in number of dice |
|
|
|
|
|
t = [0,''] |
|
|
|
|
|
t[0] = random.randint(1,die[2])#roll the dice |
|
|
|
|
|
|
|
|
for k in range(die[1]): # for each dice in number of dice |
|
|
|
|
|
t = [0, ''] |
|
|
|
|
|
t[0] = random.randint(1, die[2]) # roll the dice |
|
|
t[1] = '{}'.format(t[0]) |
|
|
t[1] = '{}'.format(t[0]) |
|
|
if t[0] <= die[3]:#if its below or equal to the re-roll value, then re-roll it |
|
|
|
|
|
t[0] = random.randint(1,die[2]) |
|
|
|
|
|
t[1] += '__{}__'.format(t[0])#underline the re-roll so its clear thats the one to pay attention to |
|
|
|
|
|
|
|
|
if t[0] <= die[3]: # if its below or equal to the re-roll value, then re-roll it |
|
|
|
|
|
t[0] = random.randint(1, die[2]) |
|
|
|
|
|
t[1] += '__{}__'.format(t[0]) # underline the re-roll so its clear thats the one to pay attention to |
|
|
temp.append(t) |
|
|
temp.append(t) |
|
|
def takeFirst(ele): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def take_first(ele): |
|
|
return ele[0] |
|
|
return ele[0] |
|
|
if die[4] > 0:#if its selecting highest |
|
|
|
|
|
temp.sort(key=takeFirst, reverse=True)#sort the rolled dice. highest first |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if die[4] > 0: # if its selecting highest |
|
|
|
|
|
temp.sort(key=take_first, reverse=True) # sort the rolled dice. highest first |
|
|
for k, val in enumerate(temp): |
|
|
for k, val in enumerate(temp): |
|
|
if k >= die[4]:#if the position in the sorted list is greater than the number of dice wanted, cross it out, and make it not count towards the total |
|
|
|
|
|
|
|
|
if k >= die[4]: # if the position in the sorted list is greater than the number of dice wanted, cross it out, and make it not count towards the total |
|
|
val[1] = '~~' + val[1] + '~~' |
|
|
val[1] = '~~' + val[1] + '~~' |
|
|
val[0] = 0 |
|
|
val[0] = 0 |
|
|
if die[4] < 0:#if its selecting lowest |
|
|
|
|
|
temp.sort(key=takeFirst) |
|
|
|
|
|
for k, val in enumerate(temp):#sort the rolled dice. lowest first |
|
|
|
|
|
if k >= -die[4]:#if the position in the sorted list is greater than the number of dice wanted, cross it out, and make it not count towards the total |
|
|
|
|
|
|
|
|
if die[4] < 0: # if its selecting lowest |
|
|
|
|
|
temp.sort(key=take_first) |
|
|
|
|
|
for k, val in enumerate(temp): # sort the rolled dice. lowest first |
|
|
|
|
|
if k >= -die[4]: # if the position in the sorted list is greater than the number of dice wanted, cross it out, and make it not count towards the total |
|
|
val[1] = '~~' + val[1] + '~~' |
|
|
val[1] = '~~' + val[1] + '~~' |
|
|
val[0] = 0 |
|
|
val[0] = 0 |
|
|
for k, val in enumerate(temp):##loop through all dice rolled and add them to the total. also print them if in verbose mode |
|
|
|
|
|
if rollVerbose: |
|
|
|
|
|
|
|
|
for k, val in enumerate(temp): # loop through all dice rolled and add them to the total. also print them if in verbose mode |
|
|
|
|
|
if roll_verbose: |
|
|
response += '{},'.format(val[1]) |
|
|
response += '{},'.format(val[1]) |
|
|
total+= die[0] * val[0] |
|
|
|
|
|
if rollVerbose: |
|
|
|
|
|
response = response[:-1] + ')'#clip the trailing ',' and replace it with a ')' |
|
|
|
|
|
if rollVerbose: |
|
|
|
|
|
|
|
|
total += die[0] * val[0] |
|
|
|
|
|
if roll_verbose: |
|
|
|
|
|
response = response[:-1] + ')' # clip the trailing ',' and replace it with a ')' |
|
|
|
|
|
if roll_verbose: |
|
|
response += ' Totaling: {}'.format(total) |
|
|
response += ' Totaling: {}'.format(total) |
|
|
else: |
|
|
else: |
|
|
response += ' Total: {}'.format(total) |
|
|
response += ' Total: {}'.format(total) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logging = roxbot.guild_settings.get(ctx.guild).logging |
|
|
logging = roxbot.guild_settings.get(ctx.guild).logging |
|
|
log_channel = self.bot.get_channel(logging["channel"]) |
|
|
log_channel = self.bot.get_channel(logging["channel"]) |
|
|
await roxbot.log(ctx.guild, log_channel, "aesthetics", User=ctx.author, Argument_Given=convert, Channel=ctx.channel, Channel_Mention=ctx.channel.mention, Time="{:%a %Y/%m/%d %H:%M:%S} UTC".format(ctx.message.created_at)) |
|
|
|
|
|
|
|
|
await roxbot.log( |
|
|
|
|
|
ctx.guild, |
|
|
|
|
|
log_channel, |
|
|
|
|
|
"aesthetics", |
|
|
|
|
|
User=ctx.author, |
|
|
|
|
|
Argument_Given=convert, |
|
|
|
|
|
Channel=ctx.channel, |
|
|
|
|
|
Channel_Mention=ctx.channel.mention, |
|
|
|
|
|
Time="{:%a %Y/%m/%d %H:%M:%S} UTC".format(ctx.message.created_at) |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
@bot.command(aliases=["ft", "frog"]) |
|
|
@bot.command(aliases=["ft", "frog"]) |
|
|
async def frogtips(self, ctx): |
|
|
async def frogtips(self, ctx): |