Пример #1
0
def get_steps(start_inc: SV, diff: Diff, goal: SV):
    """Return the number of steps it would take to reach `goal` from 0,
    first by increasing by `start_inc`, then by `start_inc` operator(`diff.changetype`) `diff.amount`,
    repeating this process until `goal` is reached.

    Returns (steps, final increment, start inc. / final inc.)"""

    if (diff.changetype == "add"
            and diff.amount == 0) or (diff.changetype == "multiply"
                                      and diff.amount == 1):
        if start_inc <= 0:
            return (Decimal("inf"), SV(0), Decimal("inf"))
        # Calculate number of steps required to reach goal
        steps = math.ceil(goal / start_inc)
        # Calculate how far user got after those steps
        # current_pos = start_inc * steps
        return (Decimal(steps), start_inc, 1)
    elif diff.changetype == "add":
        if diff.amount < 0:
            # Calculate max distance travelled, if each step is getting shorter
            max_dist = ((diff.amount / 2) - start_inc) / diff.amount
            if max_dist < goal:
                return (Decimal("inf"), SV(0), Decimal("inf"))
        # Calculate number of steps required to reach goal
        # https://www.wolframalpha.com/input/?i=g+%3D+%28s+*+t%29+%2B+%28a+*+%28%28t+-+1%29+*+t%29+%2F+2%29+solve+for+t
        steps = math.ceil(
            Decimal(
                Decimal(
                    math.sqrt(
                        Decimal(diff.amount**2) -
                        Decimal(4 * diff.amount * start_inc) +
                        Decimal(8 * diff.amount * goal) +
                        Decimal(4 * Decimal(start_inc**2)))) + diff.amount -
                Decimal(2 * start_inc)) / Decimal(2 * diff.amount))
        # Calculate how far user got after those steps
        # current_pos = (start_inc * steps) + (diff.amount * ((steps - 1) * steps) / 2)
        # Calculate length of last step
        current_inc = start_inc + (diff.amount * (steps - 1))
        return (Decimal(steps), current_inc, start_inc / current_inc)
    elif diff.changetype == "multiply":
        # https://en.wikipedia.org/wiki/Geometric_series
        if diff.amount < 1:
            # Calculate max distance travelled, if each step is getting shorter
            max_dist = start_inc / (1 - diff.amount)
            if max_dist < goal:
                return (Decimal("inf"), SV(0), Decimal("inf"))
        # Calculate number of steps required to reach goal
        steps = math.ceil(
            Decimal(
                math.log(-(goal * (1 - diff.amount) / start_inc) + 1,
                         diff.amount)))
        # Calculate how far user got after those steps
        # current_pos = start_inc * ((1 - diff.amount ** (steps - 1)) / (1 - diff.amount))
        # Calculate length of last step
        current_inc = start_inc * (diff.amount**(steps - 1))
        return (Decimal(steps), current_inc, start_inc / current_inc)
    else:
        raise ChangeMethodInvalidException(
            "This change type is not yet supported for scale-walking.")
Пример #2
0
 def liftstrength(self, value):
     if value is None:
         self._liftstrength = None
         return
     value = SV(value)
     if value < 0:
         value = SV(0)
     self._liftstrength = value
Пример #3
0
    def change_height(self, diff: Diff):
        if diff.changetype == "add":
            self.height = SV(self.height + diff.amount)
        elif diff.changetype == "multiply":
            self.height = SV(self.height * diff.amount)

        else:
            raise GametimeError(f"Unsupported changetype {diff.changetype!r}.")
Пример #4
0
 def hairlength(self, value):
     if value is None:
         self._hairlength = None
         return
     value = SV(value)
     if value < 0:
         value = SV(0)
     self._hairlength = value
Пример #5
0
 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)
Пример #6
0
def get_dist(start_inc: SV, diff: Diff, steps: int):
    if diff.changetype == "add":
        current_pos = (start_inc * steps) + (diff.amount *
                                             ((steps - 1) * steps) / 2)
        return SV(current_pos)
    elif diff.changetype == "multiply":
        current_pos = start_inc * ((1 - diff.amount**(steps - 1)) /
                                   (1 - diff.amount))
        return SV(current_pos)
    else:
        raise ChangeMethodInvalidException(
            "This change type is not yet supported for scale-walking.")
Пример #7
0
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
    }
Пример #8
0
    async def ruler(self, ctx, length: SV, *, who: typing.Union[discord.Member, SV] = None):
        """A distance to a user looks how long to everyone else?

        Examples:
        `&ruler 1mi`
        `&ruler 1ft @DigiDuncan`"""

        if who is None:
            who = ctx.message.author

        userdata = getUserdata(who)
        userstats = proportions.PersonStats(userdata)

        if userdata.height == 0:
            await ctx.send(f"{userdata.tag} doesn't exist...")
            return

        newlength = SV(length / userstats.viewscale)

        e = discord.Embed(
            title = f"{userstats.nickname}'s {length:,.3mu} to the world",
            description = (
                f"To everyone else, {userstats.nickname}'s {length:,.3mu} would look to be **{newlength:,.3mu}.**"
            )
        )

        await ctx.send(embed = e)
Пример #9
0
def SV_format():
    value = Decimal(request.args.get("value"))
    system = request.args.get("system")
    try:
        val = SV(value)
    except InvalidSizeValue:
        abort(404)
    return json.dumps({"formatted": format(val, system)})
Пример #10
0
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)
Пример #11
0
    def runperhour(self, value):
        if value is None:
            self._runperhour = None
            return

        if isinstance(value, ParseableRate):
            if value.diff.changetype != "add":
                raise ValueError("Invalid rate for speed parsing.")
            if value.diff.amount < 0:
                raise ValueError("Speed can not go backwards!")
            value = value.diff.amount / value.time * Decimal("3600")

        value = SV(value)

        if value < 0:
            value = SV(0)

        self._runperhour = value
Пример #12
0
    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)
Пример #13
0
    async def setinf(self, ctx):
        """Change height to infinity."""
        userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True)

        userdata.height = SV("infinity")
        completed_registration = userdata.complete_step("setheight")
        userdb.save(userdata)

        await ctx.send(f"{userdata.nickname} is now infinitely tall.")

        await proportions.nickUpdate(ctx.author)
        await showNextStep(ctx, userdata, completed=completed_registration)
Пример #14
0
    def fromJSON(cls, jsondata):
        rate = Rate.fromJSON(jsondata["rate"])
        original = jsondata["original"]
        stoptype = jsondata["stoptype"]
        if stoptype == "SV":
            stop = SV(jsondata["stop"])
        elif stoptype == "TV":
            stop = TV(jsondata["stop"])
        else:
            raise ThisShouldNeverHappenException

        return cls(original, rate, stop)
Пример #15
0
    async def scalewalk(self, ctx, change: Diff, dist: SV, flag=None):
        """Walk a certain distance, scaling by an amount each step you take.
        Accepts addition or subtraction of a certain height, or multiplication/division of a factor.

        Examples:
        `&scalewalk 2x 50m
        `&scalewalk -1mm 20ft"""

        guildid = ctx.guild.id
        userid = ctx.author.id

        userdata = userdb.load(guildid, userid)
        stats = proportions.PersonStats(userdata)

        stepcount, final_inc, final_ratio = get_steps(stats.walksteplength,
                                                      change, dist)

        finalheight = SV(userdata.height / final_ratio)

        symbol = ""
        if change.changetype == "add":
            symbol = "+"
        if change.changetype == "multiply":
            symbol = "x"

        amountstring = ""
        if change.changetype == "add":
            amountstring = f"{symbol}{change.amount:,.3mu}"
        if change.changetype == "multiply":
            amountstring = f"{symbol}{change.amount:,.3}"

        if flag is None:
            e = discord.Embed(
                title=
                f"If {userdata.nickname} walked {dist:,.3mu}, scaling {amountstring} each step...",
                description=
                f"They would now be **{finalheight:,.3mu}** tall after **{stepcount}** steps."
            )
            await ctx.send(embed=e)
        elif flag == "apply":
            userdata.height = finalheight
            userdb.save(userdata)

            e = discord.Embed(
                title=
                f"{userdata.nickname} walked {dist:,.3mu}, scaling {amountstring} each step...",
                description=
                f"They are now **{finalheight:,.3mu}** tall after **{stepcount}** steps."
            )
            await ctx.send(embed=e)
        else:
            raise DigiContextException(f"Invalid flag {flag}.")
Пример #16
0
    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)
Пример #17
0
    async def setrandomheight(self, ctx, minheight: SV, maxheight: SV):
        """Change height to a random value.

        Sets your height to a height between `minheight` and `maxheight`.
        Weighted on a logarithmic curve."""
        if minheight < 0:
            minheight = SV(0)
        if maxheight < 0:
            maxheight = SV(0)

        newheightSV = decimal.randRangeLog(minheight, maxheight)

        userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True)

        userdata.height = newheightSV
        userdb.save(userdata)

        await ctx.send(f"{userdata.nickname} is now {userdata.height:mu} tall."
                       )

        await proportions.nickUpdate(ctx.author)
        await showNextStep(ctx, userdata)
Пример #18
0
    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)
Пример #19
0
    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)
Пример #20
0
    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 ''}"
        )
Пример #21
0
    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)})"
        )
Пример #22
0
    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.")
Пример #23
0
def getUserSizes(g):
    # Find the largest and smallest current users.
    # TODO: Check to see if these users are recently active, which would determine if they count towards the check.
    smallestuser = 000000000000000000
    smallestsize = SV(SV.infinity)
    largestuser = 000000000000000000
    largestsize = SV(0)
    allusers = {}
    for _, testid in userdb.listUsers(g.id):
        if testid in list(
            [m.id for m in g.members if str(m.status) != "offline"]):
            testdata = userdb.load(g.id, testid)
            allusers[testid] = testdata.height
            if testdata.height <= 0 or testdata.height >= SV.infinity:
                break
            if testdata.height > largestsize:
                largestuser = testid
                largestsize = testdata.height
            if testdata.height < smallestsize:
                smallestuser = testid
                smallestsize = testdata.height

    smallestuser = int(smallestuser)
    largestuser = int(largestuser)

    return {
        "smallest": {
            "id": smallestuser,
            "size": smallestsize
        },
        "largest": {
            "id": largestuser,
            "size": largestsize
        },
        "users": allusers
    }
Пример #24
0
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)
Пример #25
0
    async def setshoe(self, ctx, *, newshoe):
        """Set your current shoe size.

        Accepts a US Shoe Size.
        If a W is in the shoe size anywhere, it is parsed as a Women's size.
        If a C is in the show size anywhere, it is parsed as a Children's size."""

        userdata = userdb.load(ctx.guild.id, ctx.author.id, allow_unreg=True)

        newfoot = fromShoeSize(newshoe)

        userdata.footlength = SV(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)
Пример #26
0
    async def setshoe(self, ctx, *, newshoe):
        """Set your current shoe size.

        Accepts a US Shoe Size.
        If a W is in the shoe size anywhere, it is parsed as a Women's size.
        If a C is in the show size anywhere, it is parsed as a Children's size."""

        userdata = userdb.load(ctx.guild.id, ctx.author.id)

        newfoot = fromShoeSize(newshoe)

        userdata.footlength = SV(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)})"
        )
Пример #27
0
    def __init__(self,
                 name,
                 dimension,
                 aliases=[],
                 symbol=None,
                 height=None,
                 length=None,
                 width=None,
                 diameter=None,
                 depth=None,
                 thickness=None,
                 weight=None):

        self.name = name
        self.namePlural = getPlural(name)
        self.singularNames = aliases + [self.name]
        self.aliases = aliases + [getPlural(a) for a in aliases]
        self.article = getIndefiniteArticle(self.name).split(" ")[0]
        self.symbol = symbol or None

        self.height = height and SV(height)
        self.length = length and SV(length)
        self.width = width and SV(width)
        self.diameter = diameter and SV(diameter)
        self.depth = depth and SV(depth)
        self.thickness = thickness and SV(thickness)
        self.weight = weight and WV(weight)

        dimensionmap = {
            "h": "height",
            "l": "length",
            "w": "width",
            "d": "diameter",
            "p": "depth",
            "t": "thickness"
        }

        self.unitlength = getattr(self, dimensionmap[dimension])
Пример #28
0
 def viewscale(self, viewscale):
     """Scale the user height to match the view scale"""
     self.height = SV(self.baseheight / viewscale)
Пример #29
0
 def scale(self, scale):
     """Scale the user height to match the scale"""
     self.height = SV(self.baseheight * scale)
Пример #30
0
    async def _run_event(self, event: Event, playerpool: Dict[str,
                                                              Player]) -> dict:
        """Runs an event, returning the string describing what happened and an image."""
        if event.tributes > len(playerpool):
            raise GametimeError("Not enough players to run this event!")
        players = event.get_players(playerpool)

        eventtext = event.fillin(players)
        deaths = []

        logger.log(ROYALE, "[EVENT] " + eventtext)

        def player_by_id(pid):
            return self.players[players.getByIndex(pid - 1).name]

        if event.elims is not None:
            for i in event.elims:
                player_by_id(i).dead = True
                deaths.append(player_by_id(i))

        if event.perps is not None:
            for i in event.perps:
                player_by_id(i).elims += 1

        if event.gives is not None:
            for i, s in event.gives:
                player_by_id(i).give_item(s)

        if event.removes is not None:
            for i, s in event.removes:
                player_by_id(i).remove_item(s)

        if event.clears is not None:
            for i in event.clears:
                player_by_id(i).clear_inventory()

        if event.giveattrs is not None:
            for i, s in event.giveattrs:
                player_by_id(i).give_attribute(s)

        if event.removeattrs is not None:
            for i, s in event.removeattrs:
                player_by_id(i).remove_attribute(s)

        if event.setsizes is not None:
            for i, d in event.setsizes:
                player_by_id(i).height = SV(d)

        if event.sizes is not None:
            for i, d in event.sizes:
                player_by_id(i).change_height(d)

        if event.setsizeranges is not None:
            for i, d1, d2 in event.setsizeranges:
                small, large = minmax(d1, d2)
                d = randRangeLog(small, large)
                player_by_id(i).height = SV(d)

        if event.sizeranges is not None:
            for i, d1, d2 in event.sizeranges:
                da = randRangeLog(d1.amount, d2.amount)
                if d1.changetype == "add":
                    ds = "+"
                elif d1.changetype == "multiply":
                    ds = "x"
                else:
                    raise ThisShouldNeverHappenException
                do = ds + da
                d = Diff(do, changetype=d1.changetype, amount=da)
                player_by_id(i).change_height(d)

        if len(players) == 0:
            eventimage = None
        else:
            eventimage = merge_images(
                [await self.players[p].get_image() for p in players])

        return RunnableEvent(text=eventtext,
                             image=eventimage,
                             players=players,
                             deaths=deaths)