示例#1
0
def cd(client, tokens, message, server, profile, msg, help=None):
    """
    Display when your cooldowns are expected to be done.
    Usage:
        • `rcd cd [<cooldown_types> [...<cooldown_types>]]`
    Example:
        • `rcd cd`
        • `rcd`
        • `rcd daily weekly`
    """
    implicit_invocation = False
    if tokens[0] in CoolDown.COOLDOWN_MAP or re.match(r"<@!?(?P<user_id>\d+)>", tokens[0]):
        # allow implicit invocation of cd
        tokens, implicit_invocation = ["cd", *tokens], True
    nickname = message.author.name
    cooldown_filter = lambda x: True  # show all filters by default
    if tokens[0] != "cd":
        return None
    if help and len(tokens) == 1:
        return {"msg": HelpMessage(cd.__doc__)}
    elif len(tokens) > 1:
        mentioned_profile = Profile.from_tag(tokens[1], client, server, message)
        if mentioned_profile:
            profile = mentioned_profile
            cd_args = set(tokens[2:])
            nickname = profile.last_known_nickname
        else:
            cd_args = set(tokens[1:])
        # means there are cooldown type arguments to filter on
        if cd_args:
            cooldown_filter = lambda x: x in cd_args

    profile_tz = pytz.timezone(profile.timezone)
    now = datetime.datetime.now(tz=datetime.timezone.utc)
    default = datetime.datetime(1790, 1, 1, tzinfo=datetime.timezone.utc)
    msg = ""
    cooldowns = {
        _cd[0]: _cd[1]
        for _cd in CoolDown.objects.filter(profile_id=profile.pk).order_by("after").values_list("type", "after")
    }
    all_cooldown_types = set([c[0] for c in CoolDown.COOLDOWN_TYPE_CHOICES])
    if not profile.player_guild:
        all_cooldown_types = all_cooldown_types - {"guild"}
    else:
        cooldowns["guild"] = profile.player_guild.after if profile.player_guild.after else default
    selected_cooldown_types = sorted(
        filter(cooldown_filter, all_cooldown_types),
        key=lambda x: cooldowns[x] if x in cooldowns else default,
    )
    for cooldown_type in selected_cooldown_types:
        after = cooldowns.get(cooldown_type, None)
        if after:
            if after > now:
                cooldown_after = cooldowns[cooldown_type].astimezone(profile_tz)
                msg += f":clock2: `{cooldown_type:12} {cooldown_after.strftime(profile.time_format):>20}`\n"
        else:
            msg += f":white_check_mark: `{cooldown_type:12} {'Ready!':>20}` \n"
    if not msg:
        msg = "Please use `rpg cd` or an EPIC RPG command to populate your cooldowns.\n"
    return {"msg": NormalMessage(msg, title=f"**{nickname}'s** Cooldowns ({profile.timezone})")}
示例#2
0
def marry(client, tokens, message, server, profile, msg, help=None):
    """
    # Marriage Help
    «Indicate that you are married to another player. Used to track `hunt together`
    results.»

    ## Usage
        • `rcd marry @<player>`
    ## Examples
    ```
    rcd marry @your_friend
    ```
    """
    partner = Profile.from_tag(tokens[-1], client, server, message)
    if not partner:
        return HelpMessage(marry.__doc__, title="Marriage Help")
    if partner.pk == profile.pk:
        return NormalMessage(
            "I'm afraid I can't let you marry yourself... you'll ruin my statistics!",
            title=":(",
            footer="and marriage is only about statistics...",
        )
    message = f"<@!{profile.pk}> and <@!{partner.pk}> got married!!?!? "
    message += random.choice(
        ["I give it like, 3 months, tops.", "What a time to be alive!", "It's a match made in heaven :heart_eyes:"]
    )
    profile.update(partner=partner)
    partner.update(parner=profile)
    return NormalMessage(message, title="Witness the Newlyweds :wedding:!")
示例#3
0
def stats(client, tokens, message, server, profile, msg, help=None):
    """
    This command shows the output of {long} stats that the helper bot has managed to collect.
    Usage:
        • `rcd {long}|{short} [num_minutes] [@player]`
    Examples:
        • `rcd {long}` show your own {long} stats
        • `rcd {long} 3` for the last 3 minutes
        • `rcd {short} @player` show a player's {long} stats
    """
    minutes, _all = None, False
    token_map = {
        "gambling": ("gambling", "g"),
        "g": ("gambling", "g"),
        "drops": ("drops", "dr"),
        "dr": ("drops", "dr"),
        "hunts": ("hunts", "hu"),
        "hu": ("hunts", "hu"),
    }
    if tokens[0] not in token_map:
        return None
    long, short = token_map[tokens[0]]
    if help:
        return {"msg": HelpMessage(stats.__doc__.format(long=long, short=short))}
    if len(tokens) > 1:
        mentioned_profile = Profile.from_tag(tokens[-1], client, server, message)
        if mentioned_profile:
            tokens = tokens[:-1]
            profile = mentioned_profile
        elif tokens[-1] == "all":
            _all = True
            tokens = tokens[:-1]
        if re.match(r"^([0-9\* ]+)$", tokens[-1]):
            min_tokens, prod = tokens[-1].replace(" ", "").split("*"), 1
            minutes = functools.reduce(operator.mul, [int(t) for t in min_tokens], 1)
        if not mentioned_profile and not minutes and not _all:
            return {
                "msg": ErrorMessage(
                    f"`rcd {' '.join(tokens)}` is not valid invocation of `rcd {long}`. "
                    "Example usage: `rcd {short} 5 @player`",
                    title="Stats Usage Error",
                )
            }
    uid = None if _all else profile.uid
    name = server.name if _all else client.get_user(int(profile.uid)).name
    if long == "gambling":
        return {
            "msg": NormalMessage(
                "", fields=Gamble.objects.stats(uid, minutes, server.id), title=f"{name}'s Gambling Addiction"
            )
        }
    elif long == "hunts":
        return {
            "msg": NormalMessage("", fields=Hunt.objects.hunt_stats(uid, minutes, server.id), title=f"{name}'s Carnage")
        }
    elif long == "drops":
        return {
            "msg": NormalMessage("", fields=Hunt.objects.drop_stats(uid, minutes, server.id), title=f"{name}'s Drops")
        }
示例#4
0
 def __init__(self, client, incoming, server=None):
     super().__init__(client, incoming, server)
     if not self.should_trigger:
         return
     if self.incoming.embeds:
         self.content = self.incoming.content
         self.embed = self.incoming.embeds[0]
         self.profile = Profile.from_embed_icon(self.client, self.server, self.incoming, self.embed)
示例#5
0
def logs(client, tokens, message, server, profile, msg, help=None):
    """
    # Logs Help
    Ask for the future log value of your current inventory!

    «You may need to know how many logs you will have in A10 before you can decide whether
    you should progress to the next area. This command will tell you how many logs you
    will have in area 10 based on your current inventory.»

    The command assumes you are in A5 if no area is provided.

    ## Usage
        • `rcd logs [a{n}=a5] [@player=@you]`

    ## Examples
        • `rcd logs` assuming that I am in A5, how many logs am I gonna have in A10?
        • `rcd logs a7` now that I am in A7, how many logs am I gonna have in A10?
        • `rcd logs @kevin` how many logs is Kevin gonna have in area A10?

    """
    if help or not tokens:
        return {"msg": HelpMessage(logs.__doc__)}

    full_message, metadata = " ".join(tokens), {"area": 5}
    area_indicator = re.search(r" ([aA])?(\d{1,2})", full_message)
    if area_indicator:
        area = int(area_indicator.groups()[1])
        start, end = area_indicator.span()
        tokens, metadata["area"] = tokenize(f"{full_message[0:start]}{full_message[end:]}"), area
    if not 1 <= metadata["area"] <= 15:
        return {"msg": ErrorMessage("Only areas 1-15 are valid!", title="Logs Error")}

    mentioned_profile = Profile.from_tag(tokens[-1], client, server, message)
    if mentioned_profile:
        profile, metadata["snoop"] = mentioned_profile, profile.uid

    open_sentinels = list(Sentinel.objects.filter(trigger=0, profile=profile, action="logs"))
    len(open_sentinels) == 0 and Sentinel.objects.create(trigger=0, profile=profile, action="logs", metadata=metadata)
    for sentinel in open_sentinels:
        sentinel.metadata.get("snoop", -1) == metadata.get("snoop", -1) and sentinel.update(metadata=metadata)

    _area = f'Area {metadata["area"]}'
    if metadata.get("snoop", None):
        return {
            "msg": NormalMessage(
                "Busybody, eh? Okay, I'll check next time they open their inventory.", title=f"Snoop Lawgs ({_area})"
            )
        }
    return {
        "msg": NormalMessage(
            "Okay, the next time I see your inventory, I'll say how many logs you should have in Area 10.",
            title=f"Logs ({_area})",
        )
    }
示例#6
0
def _profile(client, tokens, message, server, profile, msg, help=None):
    """
    #Profile Help
    «When called without any arguments, e.g. `rcd profile` this will display profile-related information.
    Otherwise, it will treat your input as a profile related sub-command.»


    ## Sub Commands
        • `timezone`, `tz`: Set the timezone information for your profile
        • `timeformat`, `tf`: Set the date and time formatting for your profile
        • `multiplier`, `mp`: Reduce or increase your cooldown durations
        • `notify`, `n`: Set which cooldowns the bot will notify you for
        • `marry`: Indicate that you are married to another player

    ## Examples
        • `rcd profile` Displays your profile information
        • `rcd p tz <timezone>` Sets your timezone to the provided timezone.
        • `rcd p on` Enables notifications for your profile.
        • `rcd p notify hunt on` Turns on hunt notifications for your profile.
        • `rcd p hunt on` Turns on hunt notifications for your profile.
    """
    if help and len(tokens) == 1:
        return {"msg": HelpMessage(_profile.__doc__)}
    elif len(tokens) > 1:
        # allow other commands to be namespaced by profile if that's how the user calls it
        if tokens[1] in {
            *timezone.entry_tokens,
            *timeformat.entry_tokens,
            *multiplier.entry_tokens,
            *notify.entry_tokens,
            *marry.entry_tokens,
        }:
            return {"tokens": tokens[1:]}
        maybe_profile = Profile.from_tag(tokens[1], client, server, message)
        if not maybe_profile:
            return {"error": 1}
        profile = maybe_profile
    notifications = ""
    for k, v in model_to_dict(profile).items():
        if isinstance(v, bool):
            notifications += f"{':ballot_box_with_check:' if v else ':x:'} `{k:25}`\n"
    return {
        "msg": NormalMessage(
            "",
            fields=(
                ("Timezone", f"`{profile.timezone}`"),
                ("Time Format", f"`{profile.time_format}`"),
                ("Cooldown Multiplier", f"`{profile.cooldown_multiplier}`"),
                ("Married", f"To <@!{profile.partner_id}>" if profile.partner_id else "Nope."),
                ("Notifications Enabled", notifications),
            ),
        )
    }
示例#7
0
def ban(client, tokens, message, server, profile, msg, help=None):
    """
    # Ban Help

    Someone has been naughty...

    ## Usage
        • `rcd admin ban @player`
        • `rcd ban @player`
        • `rcd unban @player`
        • `rcd ban unban @player`
    """
    naughty = Profile.from_tag(tokens[-1], client, server, message)
    if not naughty:
        return HelpMessage(ban.__doc__)
    banned = "unban" not in tokens
    naughty.update(banned="unban" not in tokens)
    if banned:
        return NormalMessage(f"Okay, <@!{naughty.pk}> can no longer use `rcd` commands.", title=f"Player Banned :(")
    return NormalMessage(f"Okay, <@!{naughty.pk}> can use `rcd` commands!", title=f"Player Un-Banned :)")
示例#8
0
def wed(client, tokens, message, server, profile, msg, help=None):
    """
    # Wedding Help
    «Ensure the blissful union of two players.»

    ## Usage
    • `rcd wed @player_one @player_two`
    • `rcd admin wed @player_one @player_two`
    """
    if len(tokens) < 3:
        return HelpMessage(wed.__doc__)
    groom = Profile.from_tag(tokens[-2], client, server, message)
    if not groom:
        return HelpMessage(wed.__doc__)
    return marry(
        dict(
            client=client,
            message=message,
            tokens=["marry", tokens[-1]],
            server=server,
            profile=groom,
            msg=msg,
        )
    )
示例#9
0
def cd(client, tokens, message, server, profile, msg, help=None):
    """
    # EPIC Helper Cooldowns
    Display when your cooldowns are expected to be done.
    ## Usage
        • `rcd cd [<cooldown_types>]` shows all cooldowns
        • `rcd rd [<cooldown_types>]` shows ready cooldowns
    ## Examples
    ```
    rcd
    rcd cd
    rrd
    rcd rd
    rcd daily weekly
    ```
    """
    if help:
        return {"msg": HelpMessage(cd.__doc__)}

    if tokens[0] not in {"cd", "rd"}:
        # allow for implicit or default invocation of rcd
        tokens = ["cd", *tokens[1:]] if tokens[0] == "" else ["cd", *tokens]
    nickname = message.author.name
    cooldown_filter = lambda x: True  # show all filters by default

    if len(tokens) > 1:
        mentioned_profile = Profile.from_tag(tokens[-1], client, server, message)
        if mentioned_profile:
            profile = mentioned_profile
            cd_args = set(tokens[2:])
            nickname = profile.last_known_nickname
        else:
            cd_args = set(tokens[1:])
        # means there are cooldown type arguments to filter on
        if cd_args:
            cooldown_filter = lambda x: x in cd_args

    profile_tz = pytz.timezone(profile.timezone)
    now = datetime.datetime.now(tz=datetime.timezone.utc)
    default = datetime.datetime(1790, 1, 1, tzinfo=datetime.timezone.utc)
    msg, warn = "", False
    cooldowns = {
        _cd[0]: _cd[1]
        for _cd in CoolDown.objects.filter(profile_id=profile.pk).order_by("after").values_list("type", "after")
    }
    all_cooldown_types = set([c[0] for c in CoolDown.COOLDOWN_TYPE_CHOICES])
    if not profile.player_guild:
        all_cooldown_types = all_cooldown_types - {"guild"}
    else:
        warn = True if profile.player_guild.raid_dibbs else False
        cooldowns["guild"] = profile.player_guild.after if profile.player_guild.after else default
    selected_cooldown_types = sorted(
        filter(cooldown_filter, all_cooldown_types),
        key=lambda x: cooldowns[x] if x in cooldowns else default,
    )
    for cooldown_type in selected_cooldown_types:
        after = cooldowns.get(cooldown_type, None)
        if not after or after <= now:
            icon = ":warning:" if warn and cooldown_type == "guild" else ":white_check_mark:"
            warning = " (dibbs) " if warn and cooldown_type == "guild" else ""
            msg += f"{icon} `{cooldown_type + warning:15} {'Ready!':>20}` \n"
        elif tokens[0] == "cd":  # don't show if "rd" command
            cooldown_after = cooldowns[cooldown_type].astimezone(profile_tz)
            icon = ":warning:" if warn and cooldown_type == "guild" else ":clock2:"
            warning = " (dibbs) " if warn and cooldown_type == "guild" else ""
            msg += f"{icon} `{cooldown_type + warning:15} {cooldown_after.strftime(profile.time_format):>20}`\n"
    if not msg:
        msg = (
            "All commands on cooldown! (You may need to use `rpg cd` to populate your cooldowns for the first time.)\n"
        )
    event_info = ""
    active_events = Event.objects.active().values_list("event_name", flat=True)
    if active_events:
        event_info = ", ".join(active_events) + " event(s) currently active.\n"
    return NormalMessage(
        msg,
        title=f"**{nickname}'s** Cooldowns",
        footer=f"{event_info}Timezone is {profile.timezone}, change with rcd p tz.",
    )