Browse Source

Cleaned up fun command. Should be a tiny bit easier to maintain.

tags/v1.8.0
Roxie Gibson 6 years ago
parent
commit
6e56042d83
1 changed files with 82 additions and 60 deletions
  1. +82
    -60
      roxbot/cogs/fun.py

+ 82
- 60
roxbot/cogs/fun.py View File

@@ -65,109 +65,122 @@ class Fun:
x<number> #only use at the end. roll the rest of the expression <number> times(max 10)
Credit: TBTerra#5677
"""
rollMaxRolls = 10
rollMaxVerbose = 10
rollMaxDice = 1000
max_rolls = 10
max_verbose = 10
max_dice = 1000
response = ''
rollVerbose = True
roll_verbose = True
# 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>'
parts = expression.split('x',1)
parts = expression.split('x', 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])
if times < 1:#cant roll less than once
if times < 1: # cant roll less than once
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
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))
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:
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])
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")
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
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])
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'
else:#numbers are stored as N, 1 sided dice
else: # numbers are stored as N, 1 sided dice
temp[1] = int(item[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
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:])
else:#select lowest so use negative select argument
else: # select lowest so use negative select argument
temp[4] = -int(item[5][1:])
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):
total = 0
if times > 1:
response += 'Roll {}: '.format(i+1)
else:
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 += ' + '
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 += '-'
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])
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 += '('
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])
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)
def takeFirst(ele):

def take_first(ele):
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):
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[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[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])
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)
else:
response += ' Total: {}'.format(total)
@@ -278,7 +291,16 @@ class Fun:

logging = roxbot.guild_settings.get(ctx.guild).logging
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"])
async def frogtips(self, ctx):

Loading…
Cancel
Save