def __init__(self, game, name: str, meta: str): self._game = game self._original_metadata = meta self._metadata = MetaParser(type(self)).parse(meta) self.name = name self.team = self._metadata.team self.gender = self._metadata.gender self.height = SV.parse(self._metadata.height) if isinstance( self._metadata.height, str) else SV.parse(str(self._metadata.height) + "m") self.baseheight = copy(self.height) if not isURL(self._metadata.url): raise ValueError(f"{self._metadata.url} is not a URL.") self.url = self._metadata.url self.attributes = [] if self._metadata.attr is None else self._metadata.attr if self._metadata.nsfw is None or self._metadata.nsfw.lower( ) == "true": self.nsfw = True elif self._metadata.nsfw.lower() == "false": self.nsfw = False else: raise ParseError( f"{self._metadata.nsfw!r} is not a valid NSFW flag.") self.inventory = [] self.dead = False self.elims = 0
def parse(cls, s): prefixmatch = valid_prefixes + r"\s*(.*)" suffixmatch = r"(.*)\s*" + valid_suffixes ct = None v = None if m := re.match(prefixmatch, s): prefix = m.group(1) value = m.group(2) if prefix in add_prefixes: ct = "add" v = SV.parse(value) elif prefix in subtract_prefixes: ct = "add" v = SV.parse(value) * -1 elif prefix in multiply_prefixes: ct = "multiply" v = Decimal(value) elif prefix in divide_prefixes: ct = "multiply" v = Decimal(1) / Decimal(value) elif prefix in percent_prefixes: ct = "multiply" v = Decimal(value) / Decimal(100) elif prefix in power_prefixes: ct = "power" v = Decimal(value)
def __init__(self, *, lessthan: str = None, greaterthan: str = None, elimslessthan: str = None, elimsgreaterthan: str = None, elimsequal: str = None, team: str = None, items: list = None, gender: str = None, attributes: list = None, nsfw=None): self.lessthan = None if lessthan is None else SV.parse(lessthan) self.greaterthan = None if greaterthan is None else SV.parse( greaterthan) self.elimslessthan = None if elimslessthan is None else Decimal( elimslessthan) self.elimsgreaterthan = None if elimsgreaterthan is None else Decimal( elimsgreaterthan) self.elimsequal = None if elimsequal is None else Decimal(elimsequal) self.team = team self.items = items self.attributes = attributes self.gender = gender self.nsfw = nsfw self.realteam = None
def __init__(self, userdata): self.nickname = userdata.nickname self.tag = userdata.tag self.gender = userdata.gender self.height = userdata.height self.baseheight = userdata.baseheight self.viewscale = userdata.viewscale self.scale = userdata.scale self.formattedscale = userdata.getFormattedScale(verbose=True) self.baseweight = userdata.baseweight self.weight = userdata.weight self.formattedweightscale = userdata.getFormattedScale( scaletype="weight", verbose=True) self.averageheightmult = self.height / defaultheight self.averageweightmult = self.weight / defaultweight if userdata.hairlength is None: self.hairlength = None else: self.hairlength = SV(userdata.hairlength / self.viewscale) if userdata.taillength is None: self.taillength = None else: self.taillength = SV(userdata.taillength / self.viewscale) if userdata.footlength is None: self.footlength = SV(self.height * self.footfactor) else: self.footlength = SV(userdata.footlength / self.viewscale) self.shoesize = formatShoeSize(self.footlength, self.gender == "f") self.footwidth = SV(self.height * self.footwidthfactor) self.toeheight = SV(self.height * self.toeheightfactor) self.shoeprintdepth = SV(self.height * self.toeheightfactor) self.pointerlength = SV(self.height * self.pointerfactor) self.thumbwidth = SV(self.height * self.thumbfactor) self.fingerprintdepth = SV(self.height * self.fingerprintfactor) defaultthreadthickness = SV.parse("1.016mm") self.threadthickness = SV(defaultthreadthickness * self.averageheightmult) self.hairwidth = SV(self.height * self.hairfactor) self.nailthickness = SV(self.height * self.nailthickfactor) self.eyewidth = SV(self.height * self.eyewidthfactor) self.avgheightcomp = SV(defaultheight * self.viewscale) self.avgweightcomp = WV(defaultweight * self.viewscale**3) viewangle = calcViewAngle(self.height, defaultheight) self.avglookangle = abs(viewangle) self.avglookdirection = "up" if viewangle >= 0 else "down" defaultwalkspeed = SV.parse("2.5mi") defaultrunspeed = SV.parse("7.5mi") self.walkperhour = SV(defaultwalkspeed * self.averageheightmult) self.runperhour = SV(defaultrunspeed * self.averageheightmult)
def SV_parse(): s = request.args.get("s") try: val = SV.parse(s) except InvalidSizeValue: abort(404) return json.dumps({"SV": str(val)})
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, allow_unreg=True) # 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.") newbaseheight = None newbaseweight = None for arg in [arg1, arg2]: if isinstance(arg, SV): newbaseheight = arg if isinstance(arg, WV): newbaseweight = arg completed_registration = False if newbaseheight is not None: if "setheight" in userdata.registration_steps_remaining: userdata.height = newbaseheight if not (SV.parse("4ft") < newbaseheight < SV.parse("8ft")): await ctx.send( f"{emojis.warning} **WARNING:** Your base height should probably be something more human-scale. This makes comparison math work out much nicer. If this was intended, you can ignore this warning, but it is ***highly recommended*** that you have a base height similar to the size of a normal human being." ) userdata.baseheight = newbaseheight completed_registration = userdata.complete_step( "setheight") or completed_registration if newbaseweight is not None: if "setweight" in userdata.registration_steps_remaining: if not (WV.parse("10lb") < newbaseheight < SV.parse("1000lb")): await ctx.send( f"{emojis.warning} **WARNING:** Your base weight should probably be something more human-scale. This makes comparison math work out much nicer. If this was intended, you can ignore this warning, but it is ***highly recommended*** that you have a base weight similar to that of a normal human being." ) userdata.baseweight = newbaseweight completed_registration = userdata.complete_step( "setweight") or completed_registration userdb.save(userdata) await ctx.send( f"{userdata.nickname} changed their base height and weight to {userdata.baseheight:,.3mu} and {userdata.baseweight:,.3mu}" ) await showNextStep(ctx, userdata, completed=completed_registration)
def fromShoeSize(shoesize): shoesizenum = Decimal(re.search(r"(\d*,)*\d+(\.\d*)?", shoesize)[0]) if "w" in shoesize.lower(): shoesizenum -= 1 if "c" in shoesize.lower( ): # Intentional override, children's sizes have no women/men distinction. shoesizenum -= (12 + Decimal("1/3")) footlengthinches = ((shoesizenum + 24) / 3) - Decimal("2/3") return SV.parse(f"{footlengthinches}in")
async def load(self, data: str): self.parser = Parser(self.game, data) async for progress in self.parser.parse(): yield progress self.minsize = SV.parse( "1mm") if self.parser.minsize is None else SV.parse( self.parser.minsize) self.maxsize = SV.parse( "4mi") if self.parser.maxsize is None else SV.parse( self.parser.maxsize) self.autoelim = True if self.parser.autoelim is None else bool( self.parser.autoelim) self.deathrate = Decimal( 10) if self.parser.deathrate is None else Decimal( self.parser.deathrate) self.arenafreq = Decimal( 10) if self.parser.deathrate is None else Decimal( self.parser.deathrate) self.unitsystem = "m" if self.parser.unitsystem is None else self.parser.unitsystem self.teamwin = False if self.parser.teamwin is None else bool( self.parser.teamwin) self.players = self.parser.players self.original_player_count = len(self.players) self.arenas = self.parser.arenas self._bloodbath_events = self.parser.bloodbath_events self._day_events = self.parser.day_events self._night_events = self.parser.night_events self._fatalday_events = self.parser.fatalday_events self._fatalnight_events = self.parser.fatalnight_events self._feast_events = self.parser.feast_events eventsdict = { "bloodbath_events": self._bloodbath_events, "day_events": self._day_events, "night_events": self._night_events, "fatalday_events": self._fatalday_events, "fatalnight_events": self._fatalnight_events, "feast_events": self._feast_events } self.events = AttrDict(eventsdict)
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)
async def setbaseear(self, ctx, *, newear): """Set a custom ear height.""" newearsv = SV.parse(newear) userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) userdata.earheight = newearsv userdb.save(userdata) await ctx.send( f"{userdata.nickname}'s ear is now {userdata.earheight:mu} long.") await showNextStep(ctx, userdata)
async def setrandomheight(self, ctx, minheight, maxheight): """Change height to a random value. Sets your height to a height between `minheight` and `maxheight`. Weighted on a logarithmic curve.""" minheightSV = utils.clamp(0, SV.parse(minheight), SV._infinity) maxheightSV = utils.clamp(0, SV.parse(maxheight), SV._infinity) newheightSV = decimal.randRangeLog(minheightSV, maxheightSV) userdata = userdb.load(ctx.guild.id, ctx.author.id) userdata.height = newheightSV userdb.save(userdata) logger.info( f"User {ctx.author.id} ({ctx.author.display_name}) set a random height, and are now {userdata.height:m} tall." ) await ctx.send(f"<@{ctx.author.id}> is now {userdata.height:mu} tall.") await proportions.nickUpdate(ctx.author)
async def setbaseheight(self, ctx, *, newbaseheight: SV): """Change base height.""" userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) # Convenience for initial registration if "setheight" in userdata.registration_steps_remaining: userdata.height = newbaseheight if not (SV.parse("4ft") < newbaseheight < SV.parse("8ft")): await ctx.send( f"{emojis.warning} **WARNING:** Your base height should probably be something more human-scale. This makes comparison math work out much nicer. If this was intended, you can ignore this warning, but it is ***highly recommended*** that you have a base height similar to the size of a normal human being." ) userdata.baseheight = newbaseheight completed_registration = userdata.complete_step("setheight") userdb.save(userdata) await ctx.send( f"{userdata.nickname}'s base height is now {userdata.baseheight:mu} tall." ) await proportions.nickUpdate(ctx.author) await showNextStep(ctx, userdata, completed=completed_registration)
async def setbasetail(self, ctx, *, newtail): """Set a custom tail length.""" newtailsv = SV.parse(newtail) userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) userdata.taillength = newtailsv userdb.save(userdata) await ctx.send( f"{userdata.nickname}'s tail is now {userdata.taillength:mu} long." ) await showNextStep(ctx, userdata)
async def setear(self, ctx, *, newear): """Set your current ear heightear.""" userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) newearsv = SV(SV.parse(newear) * userdata.viewscale) userdata.earheight = newearsv userdb.save(userdata) await ctx.send( f"{userdata.nickname}'s base ear height is now {userdata.earheight:mu} long, " f"or {SV(userdata.earheight):mu} currently.") await showNextStep(ctx, userdata)
async def setfoot(self, ctx, *, newfoot): """Set your current foot length.""" userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) userdata.footlength = SV(SV.parse(newfoot) * userdata.viewscale) userdb.save(userdata) await ctx.send( f"{userdata.nickname}'s base foot length is now {userdata.footlength:mu} long ({formatShoeSize(userdata.footlength)}), " f"or {(SV(userdata.footlength * userdata.scale)):mu} currently. {formatShoeSize(SV(userdata.footlength * userdata.scale))}" ) await showNextStep(ctx, userdata)
async def settail(self, ctx, *, newtail): """Set your current tail length.""" userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) newtailsv = SV(SV.parse(newtail) * userdata.viewscale) userdata.taillength = newtailsv userdb.save(userdata) await ctx.send( f"{userdata.nickname}'s base tail length is now {userdata.taillength:mu} long, " f"or {SV(userdata.taillength):mu} currently.") await showNextStep(ctx, userdata)
async def setbasetail(self, ctx, *, newtail): """Set a custom tail length.""" newtailsv = SV.parse(newtail) userdata = userdb.load(ctx.guild.id, ctx.author.id) userdata.taillength = newtailsv userdb.save(userdata) logger.info( f"User {ctx.author.id} ({ctx.author.display_name})'s tail is now {userdata.taillength:m} long." ) await ctx.send( f"<@{ctx.author.id}>'s tail is now {userdata.taillength:mu} long.")
async def settail(self, ctx, *, newtail): """Set your current tail length.""" userdata = userdb.load(ctx.guild.id, ctx.author.id) newtailsv = SV(SV.parse(newtail) * userdata.viewscale) userdata.taillength = newtailsv userdb.save(userdata) logger.info( f"User {ctx.author.id} ({ctx.author.display_name})'s tail is now {userdata.taillength:m} long." ) await ctx.send( f"<@{ctx.author.id}>'s tail is now {userdata.taillength:mu} long.")
async def setfoot(self, ctx, *, newfoot): """Set your current foot length.""" userdata = userdb.load(ctx.guild.id, ctx.author.id) userdata.footlength = SV(SV.parse(newfoot) * userdata.viewscale) userdb.save(userdata) logger.info( f"User {ctx.author.id} ({ctx.author.display_name})'s foot is now {userdata.footlength:m} long." ) await ctx.send( f"<@{ctx.author.id}>'s foot is now {userdata.footlength:mu} long. ({formatShoeSize(userdata.footlength)})" )
async def setbaseheight(self, ctx, *, newbaseheight): """Change base height.""" userdata = userdb.load(ctx.guild.id, ctx.author.id) userdata.baseheight = SV.parse(newbaseheight) userdb.save(userdata) logger.info( f"User {ctx.author.id} ({ctx.author.display_name}) changed their base height to {newbaseheight}." ) await ctx.send( f"<@{ctx.author.id}>'s base height is now {userdata.baseheight:mu} tall." ) await proportions.nickUpdate(ctx.author)
async def setheight(self, ctx, *, newheight): """Change height.""" newheightsv = SV.parse(newheight) userdata = userdb.load(ctx.guild.id, ctx.author.id) userdata.height = newheightsv userdb.save(userdata) logger.info( f"User {ctx.author.id} ({ctx.author.display_name}) is now {userdata.height:m} tall." ) await ctx.send(f"<@{ctx.author.id}> is now {userdata.height:mu} tall.") await proportions.nickUpdate(ctx.author)
async def test_macrovision_SV(): assert await macrovision.get_url([ {"name": "Duncan", "model": "male", "height": SV.parse("0.5in")}, {"name": "Natalie", "model": "female", "height": SV.parse("6in")} ], shorten = False) == "https://macrovision.crux.sexy/?scene=eyJlbnRpdGllcyI6IFt7Im5hbWUiOiAiSHVtYW4iLCAiY3VzdG9tTmFtZSI6ICJOYXRhbGllIiwgInNjYWxlIjogMC4wODk1NTIyMzg4MDU5NzAxNCwgInZpZXciOiAid29tYW4xIiwgIngiOiAiMCIsICJ5IjogIjAiLCAicHJpb3JpdHkiOiAwLCAiYnJpZ2h0bmVzcyI6IDF9LCB7Im5hbWUiOiAiSHVtYW4iLCAiY3VzdG9tTmFtZSI6ICJEdW5jYW4iLCAic2NhbGUiOiAwLjAwNzA0MjI1MzUyMTEyNjc2LCAidmlldyI6ICJtYW4xIiwgIngiOiAiMC4wMzgxIiwgInkiOiAiMCIsICJwcmlvcml0eSI6IDAsICJicmlnaHRuZXNzIjogMX1dLCAid29ybGQiOiB7ImhlaWdodCI6IDAuMTUyNCwgInVuaXQiOiAibWV0ZXJzIiwgIngiOiAiMCIsICJ5IjogIjAifSwgInZlcnNpb24iOiAzfQ=="
async def lookat(self, ctx, *, what: typing.Union[DigiObject, discord.Member, SV, str]): """See what an object looks like to you. Used to see how an object would look at your scale. Examples: `&lookat man` `&look book` `&examine building`""" if isinstance(what, SV): telemetry.SizeViewed(what).save() userdata = getUserdata(ctx.author) if isinstance(what, str): what = what.lower() if isinstance(what, DigiObject): telemetry.ObjectUsed(str(what)).save() la = what.relativestatssentence(userdata) # Easter eggs. if what.name == "photograph": la += "\n\n<https://www.youtube.com/watch?v=BB0DU4DoPP4>" logger.log(EGG, f"{ctx.author.display_name} is jamming to Nickleback.") if what.name == "enderman": la += f"\n\n`{ctx.author.display_name} was slain by an Enderman.`" logger.log(EGG, f"{ctx.author.display_name} was slain by an Enderman.") await ctx.send(la) return elif isinstance(what, discord.Member) or isinstance(what, SV): # TODO: Make this not literally just a compare. (make a sentence) compdata = getUserdata(what) elif isinstance(what, str) and what.lower() in ["person", "man", "average", "average person", "average man", "average human", "human"]: compheight = userdb.defaultheight compdata = getUserdata(compheight, nickname = "an average person") elif isinstance(what, str) and what.lower() in ["chocolate", "stuffed animal", "stuffed beaver", "beaver"]: logger.log(EGG, f"{ctx.author.display_name} found Chocolate!") compdata = getUserdata(SV.parse("11in"), nickname = "Chocolate [Stuffed Beaver]") compdata.baseweight = WV.parse("4.8oz") compdata.footlength = SV.parse("2.75in") compdata.taillength = SV.parse("12cm") elif isinstance(what, str) and what.lower() in ["me", "myself"]: compdata = userdb.load(ctx.guild.id, ctx.author.id) else: # Easter eggs. if what.lower() in ["all those chickens", "chickens"]: await ctx.send("https://www.youtube.com/watch?v=NsLKQTh-Bqo") logger.log(EGG, f"{ctx.author.display_name} looked at all those chickens.") return if what.lower() == "that horse": await ctx.send("https://www.youtube.com/watch?v=Uz4bW2yOLXA") logger.log(EGG, f"{ctx.author.display_name} looked at that horse (it may in fact be a moth.)") return if what.lower() == "my horse": await ctx.send("https://www.youtube.com/watch?v=o7cCJqya7wc") logger.log(EGG, f"{ctx.author.display_name} looked at my horse (my horse is amazing.)") return if what.lower() == "cake": await ctx.send("The cake is a lie.") logger.log(EGG, f"{ctx.author.display_name} realized the cake was lie.") return if what.lower() == "snout": await ctx.send("https://www.youtube.com/watch?v=k2mFvwDTTt0") logger.log(EGG, f"{ctx.author.display_name} took a closer look at that snout.") return await ctx.send( f"Sorry, I don't know what `{what}` is.\n" f"If this is an object or alias you'd like added to SizeBot, " f"use `{ctx.prefix}suggestobject` to suggest it " f"(see `{ctx.prefix}help suggestobject` for instructions on doing that.)" ) telemetry.UnknownObject(str(what)).save() return stats = proportions.PersonComparison(userdata, compdata) embedtosend = await stats.toEmbed(requesterID = ctx.message.author.id) await ctx.send(embed = embedtosend)
def test_negative_SV_parse(): result = SV.parse("-12m") assert result == SV("-12")
def test_feetinch_noinchunit(): result = SV.parse("5ft8") assert result == SV("1.7272")
v = Decimal(value) elif m := re.match(suffixmatch, s): value = m.group(1) suffix = m.group(2) if suffix in multiply_suffixes: ct = "multiply" v = Decimal(value) elif suffix in percent_suffixes: ct = "multiply" v = Decimal(value) / Decimal(100) else: ct = "add" v = SV.parse(s) return cls(s, ct, v) def toJSON(self): return { "changetype": self.changetype, "amount": str(self.amount), "original": self.original } @classmethod def fromJSON(cls, jsondata): changetype = jsondata["changetype"] if changetype == "add": amount = SV(jsondata["amount"])
def test_reverse_shoesize_calc(): insize = SV.parse("10in") shoesize = formatShoeSize(insize) outsize = fromShoeSize(shoesize) assert insize == outsize
def __init__(self, game, text: str, meta: str): self._game = game self._original_metadata = meta self._metadata = MetaParser(type(self)).parse(meta) self.text = text self.detect_meta_errors() if re.fullmatch(re_parse_tributes, self._metadata.tributes): self.tributes = None if self._metadata.tributes is None else Decimal( self._metadata.tributes) try: self.sizes = None if self._metadata.size is None else [ (int(k), Diff.parse(v)) for k, v in self._metadata.size ] except errors.InvalidSizeValue as e: raise ParseError(e.formatUserMessage()) try: self.setsizes = None if self._metadata.setsize is None else [ (int(k), SV.parse(v)) for k, v in self._metadata.setsize ] except errors.InvalidSizeValue as e: raise ParseError(e.formatUserMessage()) try: self.sizeranges = None if self._metadata.sizerange is None else [ (int(k), Diff.parse(v1), Diff.parse(v2)) for k, v1, v2 in self._metadata.sizerange ] except errors.InvalidSizeValue as e: raise ParseError(e.formatUserMessage()) try: self.setsizeranges = None if self._metadata.setsizerange is None else [ (int(k), SV.parse(v1), SV.parse(v2)) for k, v1, v2 in self._metadata.setsizerange ] except errors.InvalidSizeValue as e: raise ParseError(e.formatUserMessage()) self.elims = None if self._metadata.elim is None else [ int(i) for i in self._metadata.elim ] self.perps = None if self._metadata.perp is None else [ int(i) for i in self._metadata.perp ] self.gives = None if self._metadata.give is None else [ (int(k), v) for k, v in self._metadata.give ] self.removes = None if self._metadata.remove is None else [ (int(k), v) for k, v in self._metadata.remove ] self.giveattrs = None if self._metadata.giveattr is None else [ (int(k), v) for k, v in self._metadata.giveattr ] self.removeattrs = None if self._metadata.removeattr is None else [ (int(k), v) for k, v in self._metadata.removeattr ] self.clears = None if self._metadata.clear is None else [ int(i) for i in self._metadata.clear ] self.rarity = 1 if self._metadata.rarity is None else float( self._metadata.rarity) if self._metadata.nsfw is None or self._metadata.nsfw.lower( ) == "false": self.nsfw = False elif self._metadata.nsfw.lower() == "true": self.nsfw = True else: raise ParseError( f"{self._metadata.nsfw!r} is not a valid NSFW flag.") self.dummies = {} self.parse(self.text) if self.tributes != len(self.dummies): raise ParseError( f"Tribute amount mismatch. ({self.tributes} != {len(self.dummies)})" )