async def _clan_invite(self, ctx, nickname, clan_tag=None, masterserver="ac"): async with ACPClient(admin=ctx.author, masterserver=masterserver) as acp: await ctx.send(await acp.clan_invite(nickname, clan_tag))
async def _testers_access_view(self, ctx, nickname: str, masterserver: str = "rc"): nickname = nickname.replace("\\", "") translation = {"WTC": "SBT", "WRC": "RCT"} async with ACPClient(ctx.author, masterserver=masterserver) as acp: if account_id := await acp.nickname_to_aid(nickname): current_access = await acp.user_test_access(account_id)
async def _testers_access_grant(self, ctx, nickname: str, masterserver: str = "rc"): nickname = nickname.replace("\\", "") required_clicks = {"None": 2, "WTC": 1, "WRC": 0, "Both": 0} clicks_done = 0 async with ACPClient(ctx.author, masterserver=masterserver) as acp: if account_id := await acp.nickname_to_aid(nickname): current_access = await acp.user_test_access(account_id) clicks = required_clicks[current_access] for _ in range(clicks): if await acp.toggle_test_access(account_id): clicks_done += 1
async def _testers_create(self, ctx, nickname: str, masterserver: str = "rc"): nickname = nickname.replace("\\", "") async with aiohttp.ClientSession() as session: game = Client(masterserver="ac", session=session) nickname = (await game.nick2id(nickname))["nickname"] async with ACPClient(admin=ctx.author, masterserver=masterserver) as acp: account_id, nickname, password = await acp.create_account(nickname) nickname = discord.utils.escape_markdown(nickname) await ctx.send( f"Created **{nickname}** ({account_id}). Use: **{password}**")
async def tap(self, ctx, *nicknames): """Generate and set a new account password for HoNTour Caster accounts used by Tournament Organizers. Nicknames can be passed in as space separated commands arguments manually. """ if not nicknames: nicknames = ("TourAdmin1", "TourAdmin2", "TourAdmin3") alphabet = string.ascii_letters + string.digits password = "".join(secrets.choice(alphabet) for i in range(16)) await ctx.send(f"Attempting to set password to: ```\n{password}```") async with ACPClient(admin=ctx.author, masterserver="ac") as acp: for nickname in nicknames: await ctx.send( discord.utils.escape_markdown(await acp.change_password( nickname, password)))
async def password(self, ctx): self.changing_pw = ctx.author tester = await self.testers.find_one({"discord_id": ctx.author.id}, {"_id": 0, "nickname": 1}) self.changing_pw = tester["nickname"] if not tester: return await ctx.send("You are not a tester!") await ctx.send( f'Enter a new test client password for **{discord.utils.escape_markdown(tester["nickname"])}**:' ) try: password = await self.bot.wait_for( "message", check=lambda m: m.author.id == ctx.author.id and m.channel.id == ctx.channel.id, timeout=45.0, ) except asyncio.TimeoutError: return await ctx.send("You took too long. Please use the command again if you wish to continue.") async with ACPClient(admin=ctx.author, masterserver="rc") as acp: await ctx.send( discord.utils.escape_markdown(await acp.change_password(tester["nickname"], password.content)) )
async def lookup(self, ctx, player: Union[str, int], masterserver: str = "ac", *args): # pylint: disable=keyword-arg-before-vararg """Yes.""" if masterserver.startswith("-"): args += (masterserver, ) masterserver = "ac" session = aiohttp.ClientSession() ms = Client(masterserver, session=session) if player.isdigit(): result = await ms.id2nick(player) if result is not None and not isinstance( result, dict): # Till id2nick returns nick player = result.lower() else: return await ctx.send( f"{ctx.author.mention} Account does not exist.") else: player = player.lower() upgrades = bool("-u" in args or "--upgrades" in args) subs = bool("-s" in args or "--sub-accounts" in args) avatar = bool("-a" in args or "--avatar" in args) suspension = bool("-r" in args or "--rap" in args) data = await ms.show_stats(player, "ranked") if b"account_id" not in data: return await ctx.send( f"{ctx.author.mention} Account does not exist.") account_id = data[b"account_id"].decode() super_id = data[b"super_id"].decode() if upgrades: data_ss = await ms.show_simple_stats(player) data_mu = await ms.show_stats(player, "mastery") selected_upgrades = ", ".join([ v.decode() for v in data_mu[b"selected_upgrades"].values() if isinstance(v, bytes) ]) other_upgrades = ", ".join([ v.decode() for v in data[b"my_upgrades"].values() if isinstance(v, bytes) ]) await session.close() if subs or suspension: async with ACPClient(admin=ctx.author, masterserver=masterserver) as acp: if subs: sub_accounts = await acp.get_sub_accounts(account_id) if suspension: active_suspension = await acp.check_suspension(super_id) active_suspension = (active_suspension.replace( "<strong>", "").replace("</strong>", "").replace("<br />", "\n")) default_avatar = "https://s3.amazonaws.com/naeu-icb2/icons/default/account/default.png" if masterserver == "ac": if avatar: account_icon_url = await get_avatar(account_id) else: account_icon_url = default_avatar else: account_icon_url = default_avatar clan_tag_match = re.match(r"\[[0-9a-zA-Z]+\]", data[b"nickname"].decode()) if clan_tag_match: clan_tag = clan_tag_match.group(0) else: clan_tag = "\u2063" nickname = data[b"nickname"].decode().replace(clan_tag, "") clan_name = data[b"name"].decode() if b"name" in data else "\u2063" clan_rank = data[b"rank"].decode() if b"rank" in data else "\u2063" if clan_rank != "\u2063" and clan_name == "\u2063" and clan_tag == "\u2063": # Ah yes, the ghost clan. clan_tag = "[]" embed_nickname = f"{clan_tag}{nickname}" last_activity = (data[b"last_activity"].decode() if b"last_activity" in data and data[b"last_activity"] is not None else "\u2063") account_type = rctbot.config.HON_TYPE_MAP[ data[b"account_type"].decode()] standing = rctbot.config.HON_STANDING_MAP[data[b"standing"].decode()] embed = discord.Embed( title=ms.client_name, type="rich", description="Account Information", color=ms.color, timestamp=ctx.message.created_at, ) embed.set_author( name=embed_nickname, url= f"https://www.heroesofnewerth.com/playerstats/ranked/{nickname}", icon_url=account_icon_url, ) embed.add_field(name="Nickname", value=nickname, inline=True) embed.add_field(name="Account ID", value=account_id, inline=True) embed.add_field(name="Super ID", value=super_id, inline=True) embed.add_field(name="Created", value=data[b"create_date"].decode(), inline=True) embed.add_field(name="Last Activity", value=last_activity, inline=True) embed.add_field(name="Account Type", value=account_type, inline=True) embed.add_field(name="Standing", value=standing, inline=True) embed.add_field(name="Clan Tag", value=clan_tag, inline=True) embed.add_field(name="Clan Name", value=clan_name, inline=True) embed.add_field(name="Clan Rank", value=clan_rank, inline=True) embed.add_field( name="Level", value=(data[b"level"].decode() if not isinstance(data[b"level"], int) else data[b"level"]), inline=True, ) embed.add_field(name="Level Experience", value=data[b"level_exp"], inline=True) if upgrades: embed.add_field(name="Avatars", value=data_ss[b"avatar_num"], inline=True) embed.add_field(name="Selected", value=selected_upgrades, inline=True) embed.add_field(name="Other", value=other_upgrades, inline=True) if subs: account_names = [account[1] for account in sub_accounts] embed.add_field( name=f"Accounts ({len(account_names)})", value=discord.utils.escape_markdown(", ".join(account_names)), inline=False, ) if suspension: embed.add_field( name="Suspension", value=discord.utils.escape_markdown(active_suspension), inline=False, ) embed.set_footer( text= "Requested by {0} ({1}#{2}). React with 🗑️ to delete, 💾 to keep this message." .format( ctx.author.display_name, ctx.author.name, ctx.author.discriminator, ), icon_url="https://i.imgur.com/Ou1k4lD.png", ) embed.set_thumbnail(url="https://i.imgur.com/q8KmQtw.png") message = await ctx.send(embed=embed) await message.add_reaction("🗑️") await message.add_reaction("💾") try: reaction, _ = await self.bot.wait_for( "reaction_add", check=lambda reaction, user: user == ctx.author and reaction. emoji in ["🗑️", "💾"] and reaction.message.id == message.id, timeout=300.0, ) if reaction.emoji == "🗑️": await message.delete() except asyncio.TimeoutError: await message.delete()
async def _clan_crown(self, ctx, nickname, masterserver="ac"): async with ACPClient(admin=ctx.author, masterserver=masterserver) as acp: await ctx.send(await acp.clan_crown(nickname))
async def ca(self, ctx, nickname, masterserver="rc"): async with ACPClient(admin=ctx.author, masterserver=masterserver) as acp: account_id, nickname, password = await acp.create_account(nickname) await ctx.send( f"Created {nickname} ({account_id}). Use: {password}")
async def rp(self, ctx, account_id, masterserver="ac"): async with ACPClient(admin=ctx.author, masterserver=masterserver) as acp: await ctx.send(await acp.remove_perks(account_id))
async def rct(self, ctx, member: str = ""): # TODO: Assign some values to variables start = timeit.default_timer() if member == "": discord_id = ctx.author.id elif len(ctx.message.raw_mentions) > 0: discord_id = ctx.message.raw_mentions[0] else: discord_id = None if discord_id is not None: user = await self.testers.find_one({"discord_id": discord_id}) else: member = member.replace("\\", "") user = await self.testers.find_one({"nickname": member.lower()}, collation={ "locale": "en", "strength": 1 }) requester_discord_id = ctx.author.id requester = await self.testers.find_one( {"discord_id": requester_discord_id}) if requester is not None: requester_name = requester["nickname"] else: requester_name = ctx.author.display_name requester_discord_id = None # print(user) if user is None: return await ctx.send( f"{ctx.author.mention} That player is neither former nor past RCT member.", delete_after=10.0, ) nick_with_clan_tag, clan_tag, name_color = await self._get_full_nickname( user["nickname"]) enabled = user["enabled"] # TODO: dict to tuples ranks = { 7: { "name": "Immortal", "icon_url": "https://i.imgur.com/dpugisO.png", "icon_emoji": rctbot.config.EMOJI_IMMORTAL_RANK, "chest_emoji": rctbot.config.EMOJI_IMMORTAL_CHEST, "multiplier": 2.5, }, 6: { "name": "Legendary", "icon_url": "https://i.imgur.com/59Jighv.png", "icon_emoji": rctbot.config.EMOJI_LEGENDARY_RANK, "chest_emoji": rctbot.config.EMOJI_LEGENDARY_CHEST, "multiplier": 2.0, }, 5: { "name": "Diamond", "icon_url": "https://i.imgur.com/AZYAK39.png", "icon_emoji": rctbot.config.EMOJI_DIAMOND_RANK, "chest_emoji": rctbot.config.EMOJI_DIAMOND_CHEST, "multiplier": 1.75, }, 4: { "name": "Gold", "icon_url": "https://i.imgur.com/ZDLUlqs.png", "icon_emoji": rctbot.config.EMOJI_GOLD_RANK, "chest_emoji": rctbot.config.EMOJI_GOLD_CHEST, "multiplier": 1.5, }, 3: { "name": "Silver", "icon_url": "https://i.imgur.com/xxxlPAq.png", "icon_emoji": rctbot.config.EMOJI_SILVER_RANK, "chest_emoji": rctbot.config.EMOJI_SILVER_CHEST, "multiplier": 1.25, }, 2: { "name": "Bronze", "icon_url": "https://i.imgur.com/svAUm00.png", "icon_emoji": rctbot.config.EMOJI_BRONZE_RANK, "chest_emoji": rctbot.config.EMOJI_BRONZE_CHEST, "multiplier": 1.0, }, 1: { "name": "Warning", "icon_url": "https://i.imgur.com/svAUm00.png", "icon_emoji": rctbot.config.EMOJI_BRONZE_RANK, "chest_emoji": rctbot.config.EMOJI_BRONZE_CHEST, "multiplier": 0.5, }, 0: { "name": "Unranked", "icon_url": "https://i.imgur.com/ys2UBNW.png", "icon_emoji": rctbot.config.EMOJI_UNRANKED_RANK, "chest_emoji": rctbot.config.EMOJI_UNRANKED_CHEST, "multiplier": 0.0, }, } # This cycle. TODO: f*****g yikes seconds = user["seconds"] dhms = "" for scale in 86400, 3600, 60: result, seconds = divmod(seconds, scale) if dhms != "" or result > 0: dhms += "{0:02d}:".format(result) dhms += "{0:02d}".format(seconds) gametime = f"{dhms}" # Total. seconds_total = user["total_seconds"] dhms_total = "" for scale_total in 86400, 3600, 60: result_total, seconds_total = divmod(seconds_total, scale_total) if dhms_total != "" or result_total > 0: dhms_total += "{0:02d}:".format(result_total) dhms_total += "{0:02d}".format(seconds_total) gametime_total = f"{dhms_total}" games = user["games"] bonus = [] if games >= 10: bonus.append("10") if games >= 20: bonus.append("20") if math.floor((user["total_games"] / 50) - user["bonuses_given"]) > 0: bonus.append("50") if len(bonus) == 0: bonus.append("None") bonus = ", ".join(bonus) else: bonus = ", ".join(bonus) + " games" unconfirmed_games = await self.testing_games.count_documents( {"participants.account_id": user["testing_account_id"]}) embed = discord.Embed( title="Retail Candidate Testers", type="rich", description= f'Information for {user["role"]} {discord.utils.escape_markdown(user["nickname"])}.', url= "https://forums.heroesofnewerth.com/forumdisplay.php?209-Retail-Candidate-Testers", color=name_color, timestamp=ctx.message.created_at, ) embed.set_author( name=nick_with_clan_tag, url= f'https://forums.heroesofnewerth.com/member.php?{user["account_id"]}', icon_url=(await get_avatar(user["account_id"])), ) if enabled: embed.add_field(name="Unconfirmed games", value=unconfirmed_games, inline=True) # embed.add_field(name=u"\u2063", value=u"\u2063", inline=True) embed.add_field( name="Games", value=f'{user["games"]} ({ordinal(user["ladder"]["games"])})', inline=True, ) if enabled: embed.add_field( name="Total games", value= f'{user["total_games"]} ({ordinal(user["ladder"]["total_games"])})', inline=True, ) else: embed.add_field(name="Total games", value=user["total_games"], inline=True) if enabled: embed.add_field(name="Game time", value=gametime, inline=True) embed.add_field(name="Total game time", value=gametime_total, inline=True) if enabled: embed.add_field( name="Bug reports", value=f'{user["bugs"]} ({ordinal(user["ladder"]["bugs"])})', inline=True, ) if enabled: embed.add_field( name="Total bug reports", value= f'{user["total_bugs"]} ({ordinal(user["ladder"]["total_bugs"])})', inline=True, ) else: embed.add_field( name="Total bug reports", value=user["total_bugs"], inline=True, ) if enabled: embed.add_field( name="Tokens earned", value=f'{user["tokens"]} ({ordinal(user["ladder"]["tokens"])})', inline=True, ) if requester_name.lower() == user["nickname"].lower(): owned_tokens_message = f"React with {rctbot.config.EMOJI_GOLD_COINS} to reveal." else: owned_tokens_message = ( f'Available when used by {discord.utils.escape_markdown(user["nickname"])} only!' ) embed.add_field( name="Tokens owned", value=owned_tokens_message, inline=True, ) embed.add_field( name="Activity rank", value= f'{ranks[user["rank_id"]]["icon_emoji"]} {ranks[user["rank_id"]]["name"]}', inline=True, ) # FIXME: Move Artificial Multiplier final_multiplier = self.cycle_values.multiplier[ user["rank_id"]] + self.cycle_values.artificial embed.add_field( name="Multiplier", value= f'{ranks[user["rank_id"]]["chest_emoji"]} {final_multiplier}x', inline=True, ) embed.add_field(name="Bonuses", value=bonus, inline=True) embed.add_field(name="Perks", value=user["perks"], inline=True) embed.add_field(name="Absence", value="Yes" if "absence" in user else "No", inline=True) embed.add_field( name="Join date", value=user["joined"].get( "last", user["joined"]["first"]).strftime("%A, %B %d, %Y"), inline=True, ) # embed.add_field(name="Trivia points", value=trivia_points, inline=True) if not enabled and "removal_reason" in user: embed.add_field(name="Reason for removal", value=user["removal_reason"], inline=False) if len(user["awards"]) > 0: embed.add_field(name="Awards", value="\u2063" + " ".join(user["awards"]), inline=True) if user["perks"] == "Pending" and requester_name.lower( ) == user["nickname"].lower(): if clan_tag is not None: if clan_tag == "[RCT]": perks_message = f"React with {rctbot.config.EMOJI_RCT} to claim your rewards now! Note that it may take several minutes for them to show up in your vault." perks_ready_to_claim = True elif clan_tag in ["[FB]", "[GM]"]: perks_message = "However, you likely own other volunteer or staff perks. Contact an SRCT if you don't want this message to show again." perks_ready_to_claim = False else: perks_message = "Unfortunately, you are not in the RCT clan. Please contact an SRCT to join the clan if you wish to claim your rewards." perks_ready_to_claim = False else: perks_message = "Unfortunately, we could not retireve your clan tag. Please contact an SRCT if HoN servers are operational and you see this messsage." perks_ready_to_claim = False embed.add_field( name= "Congratulations! You are eligible for the RCT Chat Symbol and Name Color!", value=perks_message, inline=False, ) else: perks_ready_to_claim = False if user["perks"] == "Requested" and requester_name.lower( ) == user["nickname"].lower(): embed.add_field( name="Did you receive your RCT Chat Symbol and Name Color?", value= f"React with {rctbot.config.EMOJI_YAY} if they are in your vault or with {rctbot.config.EMOJI_NAY} if they are not.", inline=False, ) if requester_discord_id is not None: embed.set_footer( text= f"Requested by {requester_name} (✓). React with 🗑️ to delete or with 💾 to preserve this message. No action results in deletion after 5 minutes.", icon_url="https://i.imgur.com/q8KmQtw.png", ) else: embed.set_footer( text= "Requested by {.display_name} ({.name}#{.discriminator}). React with 🗑️ to delete or with 💾 to preserve this message. No action results in deletion after 5 minutes." .format(ctx.author), icon_url="https://i.imgur.com/q8KmQtw.png", ) # embed.set_footer(text="React with 🆗 to delete this message.", icon_url="https://i.imgur.com/Ou1k4lD.png") # embed.set_thumbnail(url="https://i.imgur.com/q8KmQtw.png") embed.set_thumbnail(url=ranks[user["rank_id"]]["icon_url"]) # embed.set_image(url="https://i.imgur.com/PlO2rtf.png") # Hmmm if user["signature"]["purchased"]: if user["signature"]["url"] != "": embed.set_image(url=user["signature"]["url"]) else: embed.add_field( name="You own a Discord Embedded Signature!", value= "Set it up using the `.signature` command to make Merrick even more jealous of you.", inline=False, ) message = await ctx.send(embed=embed) stop = timeit.default_timer() print(stop - start) await message.add_reaction("🗑️") await message.add_reaction("💾") if requester_name.lower() == user["nickname"].lower(): await message.add_reaction(rctbot.config.EMOJI_GOLD_COINS) if perks_ready_to_claim and requester_name.lower( ) == user["nickname"].lower(): await message.add_reaction(rctbot.config.EMOJI_RCT) if user["perks"] == "Requested" and requester_name.lower( ) == user["nickname"].lower(): await message.add_reaction(rctbot.config.EMOJI_YAY) await message.add_reaction(rctbot.config.EMOJI_NAY) async def set_perks_status(status): return await self.testers.update_one( {"nickname": user["nickname"]}, {"$set": { "perks": status }}, collation={ "locale": "en", "strength": 1 }, ) try: reaction, _ = await self.bot.wait_for( "reaction_add", check=lambda reaction, user: user == ctx.author and str( reaction.emoji) in [ "🗑️", "💾", rctbot.config.EMOJI_GOLD_COINS, rctbot.config.EMOJI_RCT, rctbot.config.EMOJI_YAY, rctbot.config.EMOJI_NAY, ] and reaction.message.id == message.id, timeout=300.0, ) if reaction.emoji == "🗑️": await message.delete() if (str(reaction.emoji) == rctbot.config.EMOJI_RCT and perks_ready_to_claim and requester_name.lower() == user["nickname"].lower()): async with ACPClient(admin=ctx.author, masterserver="ac") as acp: if not await acp.add_perks(user["account_id"]): return await ctx.send( f"{ctx.author.mention} Uh oh, something went wrong." ) await set_perks_status("Requested") await ctx.send( f"{ctx.author.mention} Done! Please use this command again to confirm whether you received the RCT Chat Symbol and Name Color after checking your in-game vault." ) if (str(reaction.emoji) == rctbot.config.EMOJI_YAY and user["perks"] == "Requested" and requester_name.lower() == user["nickname"].lower()): await set_perks_status("Yes") await ctx.send( f"{ctx.author.mention} Awesome! Thanks for using RCTBot.") if (str(reaction.emoji) == rctbot.config.EMOJI_NAY and user["perks"] == "Requested" and requester_name.lower() == user["nickname"].lower()): await set_perks_status("Pending") await ctx.send( f"{ctx.author.mention} Perks status set to Pending. You should be able to use the same command and request rewards again." ) if (str(reaction.emoji) == rctbot.config.EMOJI_GOLD_COINS and requester_name.lower() == user["nickname"].lower()): await message.clear_reactions() async with VPClient() as portal: tokens = await portal.get_tokens(user["account_id"]) embed.set_field_at(index=8, name="Tokens owned", value=tokens, inline=True) await message.edit(embed=embed) await message.add_reaction("🗑️") await message.add_reaction("💾") try: reaction, _ = await self.bot.wait_for( "reaction_add", check=lambda reaction, user: user == ctx.author and str(reaction.emoji) in ["🗑️", "💾"] and reaction.message .id == message.id, timeout=300.0, ) if reaction.emoji == "🗑️": await message.delete() except: await message.delete() except asyncio.TimeoutError: await message.delete()