def loadLegacy(id): """Load a user from the old file format""" with open(userdb.userdbpath / f"{id}.txt", "r") as f: # Make array of lines from file. lines = f.read().splitlines() lines = [line.strip() for line in lines] userdata = userdb.User() userdata.id = id userdata.nickname = lines[NICK] userdata.display = lines[DISP] if lines[CHEI] != "None": userdata.height = lines[CHEI] userdata.height /= Decimal("1e6") if lines[BHEI] != "None": userdata.baseheight = lines[BHEI] userdata.baseheight /= Decimal("1e6") if lines[BWEI] != "None": userdata.baseweight = lines[BWEI] * lines[DENS] # Drop density, and instead update base weight to match userdata.baseweight /= Decimal("1e3") userdata.unitsystem = lines[UNIT] if lines[SPEC] != "None": userdata.species = lines[SPEC] return userdata
def __init__(self, channelId, messageId, *, startTime, duration, nyan=False): self.channelId = channelId self.messageId = messageId self.startTime = Decimal(startTime) self.duration = TV(duration) self.nyan = nyan self.now = Decimal(startTime)
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, unit, trigger=None, rel_trigger=None): if trigger is not None and rel_trigger is not None: raise ValueError self.unitname = unit self._trigger = trigger and Decimal(trigger) self._rel_trigger = rel_trigger and Decimal(rel_trigger) self.unit = None
def __init__(self, userid, guildid, *, addPerSec=0, mulPerSec=1, stopSV=None, stopTV=None, startTime=None, lastRan=None): self.userid = userid self.guildid = guildid self.addPerSec = addPerSec and SV(addPerSec) self.mulPerSec = mulPerSec and Decimal(mulPerSec) self.stopSV = stopSV and SV(stopSV) self.stopTV = stopTV and TV(stopTV) self.startTime = startTime and Decimal(startTime) self.lastRan = lastRan and Decimal(lastRan)
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")
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 parse(cls, s): match = cls.re_rate.match(s) if match is None: raise errors.InvalidSizeValue(s) prefix = match.group("prefix") multOrSvStr = match.group("multOrSv") tvStr = match.group("tv") stopStr = match.group("stop") isSub = prefix in cls.subPrefixes valueSV = utils.tryOrNone(SV.parse, multOrSvStr, ignore=errors.InvalidSizeValue) valueMult = None if valueSV is None: valueMult = utils.tryOrNone(Mult.parse, multOrSvStr, ignore=errors.InvalidSizeValue) if valueSV is None and valueMult is None: raise errors.InvalidSizeValue(s) if valueSV and isSub: valueSV = -valueSV valueTV = utils.tryOrNone(TV.parse, tvStr, ignore=errors.InvalidSizeValue) if valueTV is None: raise errors.InvalidSizeValue(s) stopSV = None stopTV = None if stopStr is not None: stopSV = utils.tryOrNone(SV.parse, stopStr, ignore=errors.InvalidSizeValue) if stopSV is None: stopTV = utils.tryOrNone(TV.parse, stopStr, ignore=errors.InvalidSizeValue) if stopSV is None and stopTV is None: raise errors.InvalidSizeValue(s) if valueSV is not None: addPerSec = valueSV / valueTV else: addPerSec = 0 if valueMult is not None: mulPerSec = valueMult**(1 / valueTV) else: mulPerSec = 1 return Decimal(addPerSec), Decimal(mulPerSec), stopSV, stopTV
def parse(cls, s): value, unitStr = cls.getQuantityPair(s) if value is None and unitStr is None: raise errors.InvalidSizeValue(s) if value is None: value = Decimal(1) else: value = Decimal(value) unit = cls._units.get(unitStr, None) if unit is None: raise errors.InvalidSizeValue(s) baseUnit = unit.toBaseUnit(value) return cls(baseUnit)
def parse(cls, s): value, unitStr = cls.getQuantityPair(s) kind = "size" if cls == SV else "weight" if cls == WV else "time" if cls == TV else "size" if value is None and unitStr is None: raise errors.InvalidSizeValue(s, kind) if value is None: value = Decimal(1) else: value = Decimal(value) unit = cls._units.get(unitStr, None) if unit is None: raise errors.InvalidSizeValue(s, kind) baseUnit = unit.toBaseUnit(value) return cls(baseUnit)
def format(self, value, spec="", preferName=False): inchval = value / self.inch # convert to inches feetval, inchval = divmod(inchval, 12) # divide by 12 to get feet, and the remainder inches if inchval < Decimal("1e-100"): inchval = Decimal("0") feetSpec = DecimalSpec.parse(spec) feetSpec.precision = "0" inchSpec = DecimalSpec.parse(spec) inchSpec.sign = None formatted = f"{feetval:{feetSpec}}'{inchval:{inchSpec}}\"" return formatted
async def setscale(self, ctx, *, newscale): """Change height by scale.""" userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True) if newscale == "<:116:793260849007296522>": scale = Decimal("1/16") elif newscale == "<:1144:793260894686806026>" or newscale == "<:1122:793262146917105664>": scale = Decimal("1/144") else: re_scale = r"(\d+\.?\d*)[:/]?(\d+\.?\d*)?" if m := re.match(re_scale, newscale): multiplier = m.group(1) factor = m.group(2) if m.group(2) else 1 else:
class WV(Dimension): """Weight Value (mass in grams)""" _units = UnitRegistry() _systems = {} _infinity = Decimal("3.4e84") @classmethod def getQuantityPair(cls, s): s = utils.removeBrackets(s) # TODO: These are temporary patches. # Zero patch if s.lower() in ["0", "zero"]: return 0, "g" # Infinity patch if s.lower() in ["infinity", "inf", "∞", "yes"]: if s.lower() == "yes": logger.log(EGG, "Yes.") return cls._infinity, "g" # . patch if s.startswith("."): s = "0" + s match = re.search(r"(?P<value>[\-+]?\d+\.?\d*)? *(?P<unit>[a-zA-Z\'\"]+)", s) value, unit = None, None if match is not None: value, unit = match.group("value"), match.group("unit") return value, unit def __repr__(self): return f"WV('{self}')"
def isFeetAndInchesAndIfSoFixIt(value): regex = r"^(?P<feet>\d+\.?\d*)(ft|foot|feet|')(?P<inch>\d+\.?\d*)(in|\")?" m = re.match(regex, value, flags = re.I) if not m: return value feetval, inchval = m.group("feet"), m.group("inch") if feetval is None and inchval is None: return value if feetval is None: feetval = "0" if inchval is None: inchval = "0" feetval = Decimal(feetval) inchval = Decimal(inchval) totalinches = (feetval * 12) + inchval return f"{totalinches}in"
def __format__(self, spec): value = Decimal(self) dSpec = DecimalSpec.parse(spec) systems = dSpec.type or "" if systems and all(s.casefold() in self._systems.keys() for s in systems): dSpec.type = None numspec = str(dSpec) formattedUnits = [] for s in systems: preferName = s.upper() == s system = self._systems[s.casefold()] unit = system.getBestUnit(value) formattedUnits.append(unit.format(value, numspec, preferName)) # Remove duplicates uniqUnits = [] for u in formattedUnits: if u not in uniqUnits: uniqUnits.append(u) formatted = " / ".join(uniqUnits) else: formatted = format(value, spec) return formatted
async def step(self, bot): self.now = Decimal(time()) channel = bot.get_channel(self.channelId) message = await channel.fetch_message(self.messageId) await message.edit(content=self.formatRunner()) running = self.running return running
def __init__(self, factor=1, symbol=None, name=None, namePlural=None, symbols=[], names=[], fractional=False): self.fractional = fractional self.factor = Decimal(factor) self.symbol = symbol self.name = name self.namePlural = namePlural self.symbols = {s.strip() for s in symbols} # case sensitive symbols if symbol is not None: self.symbols.add(symbol.strip()) self.names = utils.iset(n.strip() for n in names) # case insensitive names if name is not None: self.names.add(name.strip()) if namePlural is not None: self.names.add(namePlural.strip())
class Diff: def __init__(self, original, changetype: Literal["add", "multiply", "power"], amount: Union[SV, Decimal]): self.changetype = changetype self.amount = amount self.original = original @classmethod 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) 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)
async def on_message(m): # non-guild messages if not isinstance(m.author, discord.Member): return try: guilddata = guilddb.load(m.guild.id) except GuildNotFoundException: return # Guild does not have edges set sm = guilddata.small_edge lg = guilddata.large_edge if not (m.author.id == sm or m.author.id == lg): return # The user is not set to be the smallest or the largest user. try: userdata = userdb.load(m.guild.id, m.author.id) except UserNotFoundException: return usersizes = getUserSizes(m.guild) smallestuser = usersizes["smallest"]["id"] smallestsize = usersizes["smallest"]["size"] largestuser = usersizes["largest"]["id"] largestsize = usersizes["largest"]["size"] if sm == m.author.id: if m.author.id == smallestuser: return elif userdata.height == SV(0): return else: userdata.height = smallestsize * Decimal(0.9) userdb.save(userdata) if lg == m.author.id: if m.author.id == largestuser: return elif userdata.height == SV.infinity: return else: userdata.height = largestsize * Decimal(1.1) userdb.save(userdata) if userdata.display: await proportions.nickUpdate(m.author)
def start(cls, channelId, messageId, *, duration, nyan): startTime = Decimal(time()) runner = cls(channelId, messageId, startTime=startTime, duration=duration, nyan=nyan) runners.append(runner)
def TV_format(): value = Decimal(request.args.get("value")) system = request.args.get("system", "m") try: val = TV(value) except InvalidSizeValue: abort(404) return json.dumps({"formatted": format(val, system)})
def loadLegacy(path): """Load a user from the old file format""" with open(path, "r", encoding = "utf-8") as f: # Make array of lines from file. lines = f.read().splitlines() lines = [line.strip() for line in lines] if len(lines) < 8: raise BadLegacyUser(f"Bad legacy user file: {path}") uid = path.stem userdata = userdb.User() userdata.guildid = 350429009730994199 userdata.id = uid userdata.nickname = lines[NICK] userdata.display = False if lines[DISP].lower() == "n" else True if lines[CHEI] != "None": userdata.height = Decimal(lines[CHEI]) userdata.height /= Decimal("1e6") if lines[BHEI] != "None": userdata.baseheight = Decimal(lines[BHEI]) userdata.baseheight /= Decimal("1e6") if lines[BWEI] != "None": userdata.baseweight = Decimal(lines[BWEI]) * Decimal(lines[DENS]) # Drop density, and instead update base weight to match userdata.baseweight /= Decimal("1e3") userdata.unitsystem = lines[UNIT] if lines[SPEC] != "None": userdata.species = lines[SPEC] return userdata
async def on_message(m): # non-guild messages if not isinstance(m.author, discord.Member): return edgedict = getEdgesFile(m.guild.id) sm = edgedict.get("smallest", None) lg = edgedict.get("largest", None) if m.author.id != sm and m.author.id != lg: return # The user is not set to be the smallest or the largest user. userdata = userdb.load(m.guild.id, m.author.id) usersizes = getUserSizes(m.guild) smallestuser = usersizes["smallest"]["id"] smallestsize = usersizes["smallest"]["size"] largestuser = usersizes["largest"]["id"] largestsize = usersizes["largest"]["size"] if edgedict.get("smallest", None) == m.author.id: if m.author.id == smallestuser: return elif userdata.height == SV(0): return else: userdata.height = smallestsize * Decimal(0.9) userdb.save(userdata) logger.info( f"User {m.author.id} ({m.author.display_name}) is now {userdata.height:m} tall, so that they stay the smallest." ) if edgedict.get("largest", None) == m.author.id: if m.author.id == largestuser: return elif userdata.height == SV(SV.infinity): return else: userdata.height = largestsize * Decimal(1.1) userdb.save(userdata) logger.info( f"User {m.author.id} ({m.author.display_name}) is now {userdata.height:m} tall, so that they stay the largest." ) if userdata.display: await proportions.nickUpdate(m.author)
def fromJSON(cls, jsondata): changetype = jsondata["changetype"] if changetype == "add": amount = SV(jsondata["amount"]) else: amount = Decimal(jsondata["amount"]) original = jsondata["original"] return cls(original, changetype, amount)
def formatShoeSize(footlength, women=False): # Inch in meters inch = Decimal("0.0254") footlengthinches = footlength / inch shoesizeNum = (3 * (footlengthinches + Decimal("2/3"))) - 24 prefix = "" if shoesizeNum < 1: prefix = "Children's " shoesizeNum += 12 + Decimal("1/3") if shoesizeNum < 0: return "No shoes exist this small!" if women: shoesize = format(Decimal(shoesizeNum + 1), ",.2%2") else: shoesize = format(Decimal(shoesizeNum), ",.2%2") if women: return f"Size US Women's {prefix}{shoesize}" return f"Size US {prefix}{shoesize}"
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 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 speedcalc(self, dist: SV, *, speed=False, foot=False, include_relative=False): reldist = SV(dist * self.viewer.viewscale) reldist_print = f"{reldist:,.3mu}" climblength = Decimal(0.3048) / self.viewer.viewscale climbspeed = Decimal(4828) / self.viewer.viewscale SVclimbspeed = SV(climbspeed) _walktime = (dist / self.viewer.walkperhour) * 60 * 60 walksteps = math.ceil(dist / self.viewer.walksteplength) _runtime = (dist / self.viewer.runperhour) * 60 * 60 runsteps = math.ceil(dist / self.viewer.runsteplength) _climbtime = (dist / climbspeed) * 60 * 60 climbsteps = math.ceil(dist / climblength) walktime = prettyTimeDelta(_walktime, roundeventually=True) runtime = prettyTimeDelta(_runtime, roundeventually=True) climbtime = prettyTimeDelta(_climbtime, roundeventually=True) walkspeedstr = f"\n*{emojis.blank}{self.viewer.walkperhour:,.3mu} per hour*" runspeedstr = f"\n*{emojis.blank}{self.viewer.runperhour:,.3mu} per hour*" climbspeedstr = f"\n*{emojis.blank}{SVclimbspeed:,.3mu} per hour*" shoesize = " (" + formatShoeSize(dist) + ")" newline = "\n" return ( f"{emojis.ruler} {dist:,.3mu}{shoesize if foot else ''}\n" f"{emojis.eyes + reldist_print + newline if include_relative else ''}" f"{emojis.walk} {walktime} ({walksteps:,.3} steps){walkspeedstr if speed else ''}\n" f"{emojis.run} {runtime} ({runsteps:,.3} strides){runspeedstr if speed else ''}\n" f"{emojis.climb} {climbtime} ({climbsteps:,.3} pulls){climbspeedstr if speed else ''}" )
def parse(cls, s): match = cls.re_mult.match(s) if match is None: raise errors.InvalidSizeValue(s, "multiplier") prefix = match.group("prefix") or match.group("suffix") multValue = Decimal(match.group("multValue")) isDivide = prefix in cls.divPrefixes if isDivide: multValue = 1 / multValue if prefix == "%": multValue = multValue / 100 return multValue
class SV(Dimension): """Size Value (length in meters)""" _units = UnitRegistry() _systems = {} _infinity = Decimal("8.79848e53") @classmethod def getQuantityPair(cls, s): s = utils.removeBrackets(s) s = cls.isFeetAndInchesAndIfSoFixIt(s) # TODO: These are temporary patches. # Zero patch if s.lower() in ["0", "zero", "no"]: if s.lower() == "no": logger.log(EGG, "No.") return 0, "m" # Infinity patch if s.lower() in ["infinity", "inf", "∞", "yes"]: if s.lower() == "yes": logger.log(EGG, "Yes.") return cls._infinity, "m" # . patch if s.startswith("."): s = "0" + s match = re.match(r"(?P<value>[\-+]?\d+\.?\d*)? *(?P<unit>[a-zA-Z\'\"µ ]+)", s) value, unit = None, None if match is not None: value, unit = match.group("value"), match.group("unit") return value, unit @staticmethod def isFeetAndInchesAndIfSoFixIt(value): regex = r"^(?P<feet>\d+\.?\d*)(ft|foot|feet|')(?P<inch>\d+\.?\d*)(in|\")?" m = re.match(regex, value, flags = re.I) if not m: return value feetval, inchval = m.group("feet"), m.group("inch") if feetval is None and inchval is None: return value if feetval is None: feetval = "0" if inchval is None: inchval = "0" feetval = Decimal(feetval) inchval = Decimal(inchval) totalinches = (feetval * 12) + inchval return f"{totalinches}in" def __repr__(self): return f"SV('{self}')"