async def change(self, ctx, *, string: Union[LimitedRate, ParseableRate, Diff]): """Either change or slow-change your height. Can be used in essentially the three following ways: `&change <amount>` `&change <amount>/<time>` `&change <amount>/<time> until <size/time>` Examples: `&change +1ft` `&change *2` `&change 50ft/day` `&change -1in/min until 1ft` `&change -1mm/sec for 1hr` """ guildid = ctx.guild.id userid = ctx.author.id if isinstance(string, Diff): style = string.changetype amount = string.amount userdata = userdb.load(guildid, userid) if style == "add": userdata.height += amount elif style == "multiply": userdata.height *= amount elif style == "power": userdata = userdata**amount else: raise ChangeMethodInvalidException await proportions.nickUpdate(ctx.author) userdb.save(userdata) await ctx.send( f"User <@{userid}> is now {userdata.height:m} ({userdata.height:u}) tall." ) elif isinstance(string, ParseableRate) or isinstance( string, LimitedRate): addPerSec, mulPerSec, stopSV, stopTV = Rate.parse(string.original) userdata = userdb.load( guildid, userid ) # Load this data but don't use it as an ad-hoc user test. changes.start(userid, guildid, addPerSec=addPerSec, mulPerSec=mulPerSec, stopSV=stopSV, stopTV=stopTV) await ctx.send( f"{ctx.author.display_name} has begun slow-changing at a rate of `{string.original}`." )
def getUserSizes(g): # Find the largest and smallest current users. smallestuser = None smallestsize = SV.infinity largestuser = None largestsize = SV(0) allusers = {} for _, userid in userdb.listUsers(guildid=g.id): member = g.get_member(userid) if not (member and str(member.status) != "offline"): continue userdata = userdb.load(g.id, userid) if userdata.height == 0 or userdata.height == SV.infinity: continue if not userdata.is_active: continue if userdata.height > largestsize: largestuser = userid largestsize = userdata.height if userdata.height < smallestsize: smallestuser = userid smallestsize = userdata.height allusers[userid] = userdata.height return { "smallest": { "id": smallestuser, "size": smallestsize }, "largest": { "id": largestuser, "size": largestsize }, "users": allusers }
async def on_message(m): # non-guild messages if not isinstance(m.author, discord.Member): return try: userdata = userdb.load(m.guild.id, m.author.id) except UserNotFoundException: return try: guilddata = guilddb.load(m.guild.id) except GuildNotFoundException: return if guilddata.low_limit: if userdata.height < guilddata.low_limit: userdata.height = guilddata.low_limit userdb.save(userdata) if guilddata.high_limit: if userdata.height > guilddata.high_limit: userdata.height = guilddata.high_limit userdb.save(userdata) if userdata.display: await proportions.nickUpdate(m.author)
async def setgender(self, ctx, gender): """Set gender.""" guild = ctx.guild user = ctx.author gendermap = AliasMap({ "m": ("male", "man", "boy"), "f": ("female", "woman", "girl"), None: ("none", "x", "nb") }) try: gender = gendermap[gender.lower()] except KeyError: raise errors.ArgumentException userdata = userdb.load(guild.id, user.id, allow_unreg=True) userdata.gender = gender userdb.save(userdata) if userdata.display: await proportions.nickUpdate(user) await ctx.send( f"{userdata.nickname}'s gender is now set to {userdata.gender}.") await showNextStep(ctx, userdata)
async def setgender(self, ctx, gender): """Set gender.""" guild = ctx.guild user = ctx.author gendermap = { "m": "m", "male": "m", "man": "m", "boy": "m", "f": "f", "female": "f", "woman": "f", "girl": "f", "none": None, None: None } try: gender = gendermap[gender] except KeyError: raise errors.ArgumentException userdata = userdb.load(guild.id, user.id) userdata.gender = gender userdb.save(userdata) if userdata.display: await proportions.nickUpdate(user) logger.info( f"User {user.id} ({user.display_name}) set their gender to {userdata.gender}." ) await ctx.send( f"<@{user.id}>'s gender is now set to {userdata.gender}.")
async def lineup(self, ctx): """Lineup a bunch of people for comparison.""" failedusers = [] userdatas = [] for member in ctx.message.mentions: try: userdatas.append(userdb.load(member.guild.id, member.id, member=member)) except errors.UserNotFoundException: failedusers.append(member) # TODO: Raise exception instead if failedusers: nicks = sentence_join((u.display_name for u in failedusers), oxford=True) if len(failedusers) == 1: failmessage = f"{nicks} is not a SizeBot user." else: failmessage = f"{nicks} are not SizeBot users." await ctx.send(failmessage) return users = [{"name": u.nickname, "model": u.macrovision_model, "view": u.macrovision_view, "height": u.height} for u in userdatas] nicks = sentence_join((u.nickname for u in userdatas), oxford=True) e = discord.Embed( title="Click here for lineup image!", description=f"Lineup of {nicks}", color=colors.cyan, url = await macrovision.get_url(users) ) await ctx.send(embed = e)
def user(guildid, userid): try: u = userdb.load(guildid, userid) except UserNotFoundException: abort(404) return json.dumps({"nickname": u.nickname})
async def setsystem(self, ctx, newsys): """Set measurement system.""" newsys = newsys.lower() systemmap = AliasMap({ "m": ("b", "e", "metric", "british", "europe", "european"), "u": ("i", "c", "a", "us", "imperial", "customary", "american") }) if newsys not in systemmap: await ctx.send( f"Please enter `{ctx.prefix}{ctx.invoked_with} {ctx.command.usage}`." ) return newsys = systemmap[newsys] userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) userdata.unitsystem = newsys completed_registration = userdata.complete_step("setsystem") userdb.save(userdata) await ctx.send( f"{userdata.nickname}'s system is now set to {userdata.unitsystem}." ) await proportions.nickUpdate(ctx.author) await showNextStep(ctx, userdata, completed=completed_registration)
async def setbase(self, ctx, arg1: typing.Union[SV, WV], arg2: typing.Union[SV, WV] = None): """Set your base height and weight.""" userdata = userdb.load(ctx.guild.id, ctx.author.id) # Don't allow a user to enter setbase(SV, SV) or setbase(WV, WV) if (isinstance(arg1, SV) and isinstance(arg2, SV)) or (isinstance(arg1, WV) and isinstance(arg2, WV)): raise errors.UserMessedUpException( "Please do not enter two heights or two weights.") for arg in [arg1, arg2]: if isinstance(arg, SV): userdata.baseheight = arg if isinstance(arg, WV): userdata.baseweight = arg userdb.save(userdata) logger.info( f"User {ctx.author.id} ({ctx.author.display_name}) changed their base height and weight to {userdata.baseheight:,.3mu} and {userdata.baseweight:,.3mu}." ) await ctx.send( f"{ctx.author.display_name} changed their base height and weight to {userdata.baseheight:,.3mu} and {userdata.baseweight:,.3mu}" )
async def nickReset(user): """Remove sizetag from user's nickname""" # webhooks if user.discriminator == "0000": return # non-guild messages if not isinstance(user, discord.Member): return # bots if user.bot: return # guild owner if user.id == user.guild.owner_id: return userdata = userdb.load(user.guild.id, user.id, allow_unreg=True) # User's display setting is N. No sizetag. if not userdata.display: return try: # PERMISSION: requires manage_nicknames await user.edit(nick=userdata.nickname) except discord.Forbidden: raise errors.NoPermissionsException
async def setdescription(self, ctx, *, desc): """Set your profile description. Accepts slightly more markdown than usual, see https://leovoel.github.io/embed-visualizer/""" userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) userdata.description = desc userdb.save(userdata) await ctx.send("Profile description set.")
async def nickUpdate(user): # webhooks if user.discriminator == "0000": return # non-guild messages if not isinstance(user, discord.Member): return # bots if user.bot: return # guild owner if user.id == user.guild.owner.id: return try: userdata = userdb.load(user.guild.id, user.id) except errors.UserNotFoundException: return # User's display setting is N. No sizetag. if not userdata.display: return height = userdata.height if height is None: height = userdata.baseheight nick = userdata.nickname species = userdata.species if userdata.unitsystem in ["m", "u"]: sizetag = format(height, f",{userdata.unitsystem}%") else: sizetag = "" if species is not None: sizetag = f"{sizetag}, {species}" max_nick_len = 32 if len(nick) > max_nick_len: # Truncate nick is too long nick = nick[:max_nick_len] if len(nick) + len(sizetag) + 3 <= max_nick_len: # Fit full nick and sizetag newnick = f"{nick} [{sizetag}]" elif len(sizetag) + 7 <= max_nick_len: # Fit short nick and sizetag chars_left = max_nick_len - len(sizetag) - 4 short_nick = nick[:chars_left] newnick = f"{short_nick}… [{sizetag}]" else: # Cannot fit the new sizetag newnick = nick try: await user.edit(nick=newnick) except discord.Forbidden: raise errors.NoPermissionsException
async def resetrun(self, ctx): """Remove custom run speed.""" userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) userdata.runperhour = None userdb.save(userdata) await ctx.send(f"{userdata.nickname}'s run speed is now cleared.") await showNextStep(ctx, userdata)
async def resetear(self, ctx): """Remove custom ear height.""" userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) userdata.earheight = None userdb.save(userdata) await ctx.send(f"{userdata.nickname}'s ear height is now cleared.") await showNextStep(ctx, userdata)
async def resettail(self, ctx): """Remove custom tail length.""" userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) userdata.taillength = None userdb.save(userdata) await ctx.send(f"{userdata.nickname}'s tail length is now cleared.") await showNextStep(ctx, userdata)
async def resetfoot(self, ctx): """Remove custom foot length.""" userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) userdata.footlength = None userdb.save(userdata) await ctx.send(f"{userdata.nickname}'s foot length is now default.") await showNextStep(ctx, userdata)
def changeUser(guildid, userid, changestyle, amount): changestyle = changestyle.lower() if changestyle in ["add", "+", "a", "plus"]: changestyle = "add" if changestyle in ["subtract", "sub", "-", "minus"]: changestyle = "subtract" if changestyle in ["power", "exp", "pow", "exponent", "^", "**"]: changestyle = "power" if changestyle in ["multiply", "mult", "m", "x", "times", "*"]: changestyle = "multiply" if changestyle in ["divide", "d", "/", "div"]: changestyle = "divide" if changestyle in ["percent", "per", "perc", "%"]: changestyle = "percent" if changestyle not in [ "add", "subtract", "multiply", "divide", "power", "percent" ]: raise errors.ChangeMethodInvalidException(changestyle) amountSV = None amountVal = None newamount = None if changestyle in ["add", "subtract"]: amountSV = SV.parse(amount) elif changestyle in ["multiply", "divide", "power"]: amountVal = Decimal(amount) if amountVal == 1: raise errors.ValueIsOneException if amountVal == 0: raise errors.ValueIsZeroException elif changestyle in ["percent"]: amountVal = Decimal(amount) if amountVal == 0: raise errors.ValueIsZeroException userdata = userdb.load(guildid, userid) if changestyle == "add": newamount = userdata.height + amountSV elif changestyle == "subtract": newamount = userdata.height - amountSV elif changestyle == "multiply": newamount = userdata.height * amountVal elif changestyle == "divide": newamount = userdata.height / amountVal elif changestyle == "power": userdata = userdata**amountVal elif changestyle == "percent": newamount = userdata.height * (amountVal / 100) if changestyle != "power": userdata.height = newamount userdb.save(userdata)
def getUserdata(memberOrSV, nickname = None, *, allow_unreg=False): if isinstance(memberOrSV, discord.Member): userdata = userdb.load(memberOrSV.guild.id, memberOrSV.id, member=memberOrSV, allow_unreg=allow_unreg) else: userdata = userdb.User() userdata.height = memberOrSV if nickname is None: nickname = f"a {userdata.height:,.3mu} person" userdata.nickname = nickname return userdata
async def on_message(m): """Is this user active?""" if m.author.bot: return try: userdata = userdb.load(m.guild.id, m.author.id) except errors.UserNotFoundException: return userdata.lastactive = arrow.now() userdb.save(userdata)
def getUserdata(memberOrSV, nickname="Raw"): if nickname is None: nickname = "Raw" if isinstance(memberOrSV, discord.Member): userdata = userdb.load(memberOrSV.guild.id, memberOrSV.id) else: userdata = userdb.User() userdata.nickname = nickname userdata.height = memberOrSV return userdata
async def resetstepscale(self, ctx): """Clear your step-scale amount, for use with `&step`.""" guildid = ctx.guild.id userid = ctx.author.id userdata = userdb.load(guildid, userid) userdata.currentscalestep = None userdb.save(userdata) await ctx.send(f"{userdata.nickname}'s scale per step is now cleared.")
async def togglefur(self, ctx): """Switch between the word "hair" and "fur" for your stats.""" userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) userdata.furtoggle = not userdata.furtoggle userdb.save(userdata) await ctx.send( f"The hair of {userdata.nickname} is now called {userdata.hairname.lower()}." ) await showNextStep(ctx, userdata)
async def resetfoot(self, ctx): """Remove custom foot length.""" userdata = userdb.load(ctx.guild.id, ctx.author.id) userdata.footlength = None userdb.save(userdata) logger.info( f"User {ctx.author.id} ({ctx.author.display_name}) removed their custom foot length." ) await ctx.send(f"<@{ctx.author.id}>'s foot length is now default.")
async def resetheight(self, ctx): """Reset height/size.""" userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) userdata.height = userdata.baseheight userdb.save(userdata) await ctx.send(f"{ctx.author.display_name} reset their size.") await proportions.nickUpdate(ctx.author) await showNextStep(ctx, userdata)
async def eatme(self, ctx): """Eat me! Increases your height by a random amount between 2x and 20x.""" guildid = ctx.guild.id userid = ctx.author.id userdata = userdb.load(guildid, userid) randmult = round(random.randint(2, 20), 1) proportions.changeUser(guildid, userid, "multiply", randmult) await proportions.nickUpdate(ctx.author) userdata = userdb.load(guildid, userid) lines = pkg_resources.read_text(sizebot.data, "eatme.txt").splitlines() line = random.choice(lines) await ctx.send( f"<@{userid}> ate a :cake:! *{line}*\n" f"They multiplied {randmult}x and are now {userdata.height:m} tall. ({userdata.height:u})" )
async def resettail(self, ctx): """Remove custom tail length.""" userdata = userdb.load(ctx.guild.id, ctx.author.id) userdata.taillength = None userdb.save(userdata) logger.info( f"User {ctx.author.id} ({ctx.author.display_name}) removed their custom tail length." ) await ctx.send(f"<@{ctx.author.id}>'s tail length is now cleared.")
async def resetspecies(self, ctx): """Remove species.""" userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) userdata.species = None userdb.save(userdata) await ctx.send(f"{userdata.nickname}'s species is now cleared.") await proportions.nickUpdate(ctx.author) await showNextStep(ctx, userdata)
async def togglepaw(self, ctx): """Switch between the word "foot" and "paw" for your stats.""" userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) userdata.pawtoggle = not userdata.pawtoggle userdb.save(userdata) await ctx.send( f"The end of {userdata.nickname}'s legs are now called a {userdata.footname.lower()}." ) await showNextStep(ctx, userdata)
async def setbaserun(self, ctx, *, newrun: ParseableRate): """Set a custom run speed.""" userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) userdata.runperhour = newrun userdb.save(userdata) await ctx.send( f"{userdata.nickname}'s run is now {userdata.runperhour:mu}.") await showNextStep(ctx, userdata)
async def setspecies(self, ctx, *, newtag): """Change species.""" userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) userdata.species = newtag userdb.save(userdata) await ctx.send( f"{userdata.nickname}'s species is now a {userdata.species}.") await proportions.nickUpdate(ctx.author) await showNextStep(ctx, userdata)