[V3 Economy] Expand payday output (#1386)

* [V3 Economy] implement suggestions from #1371

* Fix a typo

* Add functions for getting leaderboard and leaderboard position

* Use the new functions to get leaderboard position and leaderboard (overrides https://github.com/Cog-Creators/Red-DiscordBot/pull/1435)

* Actually implement showing only guild members on leaderboard when bank is global

* get_leaderboard_position needs to be awaited

* For global bank, pass None for guild to get_leaderboard when trying to find position

* Remove some unneeded code

* Wrong index...

* Combine 3 messages into 1

* Fix guild leaderboard while bank is global

* add missing parentheses

* Modify the leaderboard formatting

* More work on leaderboard formatting

* no subtraction
This commit is contained in:
palmtree5 2018-03-20 14:22:10 -08:00 committed by Will
parent a8f4659552
commit f83e3cc3e7
2 changed files with 88 additions and 66 deletions

View File

@ -235,14 +235,17 @@ class Economy:
await bank.deposit_credits(author, await self.config.PAYDAY_CREDITS()) await bank.deposit_credits(author, await self.config.PAYDAY_CREDITS())
next_payday = cur_time + await self.config.PAYDAY_TIME() next_payday = cur_time + await self.config.PAYDAY_TIME()
await self.config.user(author).next_payday.set(next_payday) await self.config.user(author).next_payday.set(next_payday)
await ctx.send(
_("{} Here, take some {}. Enjoy! (+{}" pos = await bank.get_leaderboard_position(author)
" {}!)").format( await ctx.send(_(
author.mention, credits_name, "{0.mention} Here, take some {1}. Enjoy! (+{2}\n\n"
str(await self.config.PAYDAY_CREDITS()), "You currently have {3} {1}.\n\n"
credits_name "You are currently #{4} on the leaderboard!"
) ).format(
) author, credits_name, str(await self.config.PAYDAY_CREDITS()),
str(await bank.get_balance(author)), pos
))
else: else:
dtime = self.display_time(next_payday - cur_time) dtime = self.display_time(next_payday - cur_time)
await ctx.send( await ctx.send(
@ -255,12 +258,15 @@ class Economy:
await bank.deposit_credits(author, await self.config.guild(guild).PAYDAY_CREDITS()) await bank.deposit_credits(author, await self.config.guild(guild).PAYDAY_CREDITS())
next_payday = cur_time + await self.config.guild(guild).PAYDAY_TIME() next_payday = cur_time + await self.config.guild(guild).PAYDAY_TIME()
await self.config.member(author).next_payday.set(next_payday) await self.config.member(author).next_payday.set(next_payday)
await ctx.send( pos = await bank.get_leaderboard_position(author)
_("{} Here, take some {}. Enjoy! (+{}" await ctx.send(_(
" {}!)").format( "{0.mention} Here, take some {1}. Enjoy! (+{2})\n\n"
author.mention, credits_name, "You currently have {3} {1}.\n\n"
str(await self.config.guild(guild).PAYDAY_CREDITS()), "You are currently #{4} on the leaderboard!"
credits_name)) ).format(
author, credits_name, str(await self.config.PAYDAY_CREDITS()),
str(await bank.get_balance(author)), pos
))
else: else:
dtime = self.display_time(next_payday - cur_time) dtime = self.display_time(next_payday - cur_time)
await ctx.send( await ctx.send(
@ -269,7 +275,7 @@ class Economy:
@commands.command() @commands.command()
@guild_only_check() @guild_only_check()
async def leaderboard(self, ctx: commands.Context, top: int = 10): async def leaderboard(self, ctx: commands.Context, top: int = 10, show_global: bool=False):
"""Prints out the leaderboard """Prints out the leaderboard
Defaults to top 10""" Defaults to top 10"""
@ -277,26 +283,23 @@ class Economy:
guild = ctx.guild guild = ctx.guild
if top < 1: if top < 1:
top = 10 top = 10
if await bank.is_global(): if await bank.is_global() and show_global: # show_global is only applicable if bank is global
bank_sorted = sorted(await bank.get_global_accounts(), guild = None
key=lambda x: x.balance, reverse=True) bank_sorted = await bank.get_leaderboard(positions=top, guild=guild)
else:
bank_sorted = sorted(await bank.get_guild_accounts(guild),
key=lambda x: x.balance, reverse=True)
if len(bank_sorted) < top: if len(bank_sorted) < top:
top = len(bank_sorted) top = len(bank_sorted)
topten = bank_sorted[:top]
highscore = "" highscore = ""
place = 1 for pos, acc in enumerate(bank_sorted, 1):
for acc in topten: pos = pos
dname = str(acc.name) poswidth = 2
if len(dname) >= 23 - len(str(acc.balance)): name = acc[1]["name"]
dname = dname[:(23 - len(str(acc.balance))) - 3] namewidth = 35
dname += "... " balance = acc[1]["balance"]
highscore += str(place).ljust(len(str(top)) + 1) balwidth = 2
highscore += dname.ljust(23 - len(str(acc.balance))) highscore += "{pos: <{poswidth}} {name: <{namewidth}s} {balance: >{balwidth}}\n".format(
highscore += str(acc.balance) + "\n" pos=pos, poswidth=poswidth, name=name, namewidth=namewidth,
place += 1 balance=balance, balwidth=balwidth
)
if highscore != "": if highscore != "":
for page in pagify(highscore, shorten_by=12): for page in pagify(highscore, shorten_by=12):
await ctx.send(box(page, lang="py")) await ctx.send(box(page, lang="py"))

View File

@ -243,7 +243,7 @@ async def deposit_credits(member: discord.Member, amount: int) -> int:
""" """
if _invalid_amount(amount): if _invalid_amount(amount):
raise ValueError("Invalid withdrawal amount {} <= 0".format(amount)) raise ValueError("Invalid deposit amount {} <= 0".format(amount))
bal = await get_balance(member) bal = await get_balance(member)
return await set_balance(member, amount + bal) return await set_balance(member, amount + bal)
@ -287,62 +287,81 @@ async def wipe_bank():
await _conf.clear_all_members() await _conf.clear_all_members()
async def get_guild_accounts(guild: discord.Guild) -> List[Account]: async def get_leaderboard(positions: int=None, guild: discord.Guild=None) -> List[tuple]:
"""Get all account data for the given guild. """
Gets the bank's leaderboard
Parameters Parameters
---------- ----------
positions : `int`
The number of positions to get
guild : discord.Guild guild : discord.Guild
The guild to get accounts for. The guild to get the leaderboard of. If the bank is global and this
is provided, get only guild members on the leaderboard
Returns Returns
------- -------
`list` of `Account` `list` of `tuple`
A list of all guild accounts. The sorted leaderboard in the form of :code:`(user_id, raw_account)`
Raises Raises
------ ------
RuntimeError TypeError
If the bank is currently global. If the bank is guild-specific and no guild was specified
""" """
if await is_global(): if await is_global():
raise RuntimeError("The bank is currently global.") raw_accounts = await _conf.all_users()
if guild is not None:
ret = [] tmp = raw_accounts.copy()
accs = await _conf.all_members(guild) for acc in tmp:
for user_id, acc in accs.items(): if not guild.get_member(acc):
acc_data = acc.copy() # There ya go kowlin del raw_accounts[acc]
acc_data['created_at'] = _decode_time(acc_data['created_at']) else:
ret.append(Account(**acc_data)) if guild is None:
return ret raise TypeError("Expected a guild, got NoneType object instead!")
raw_accounts = await _conf.all_members(guild)
sorted_acc = sorted(raw_accounts.items(), key=lambda x: x[1]['balance'], reverse=True)
if positions is None:
return sorted_acc
else:
return sorted_acc[:positions]
async def get_global_accounts() -> List[Account]: async def get_leaderboard_position(member: Union[discord.User, discord.Member]) -> Union[int, None]:
"""Get all global account data. """
Get the leaderboard position for the specified user
Parameters
----------
member : `discord.User` or `discord.Member`
The user to get the leaderboard position of
Returns Returns
------- -------
`list` of `Account` `int`
A list of all global accounts. The position of the user on the leaderboard
Raises Raises
------ ------
RuntimeError TypeError
If the bank is currently guild specific. If the bank is currently guild-specific and a `discord.User` object was passed in
""" """
if not await is_global(): if await is_global():
raise RuntimeError("The bank is not currently global.") guild = None
else:
ret = [] guild = member.guild if hasattr(member, "guild") else None
accs = await _conf.all_users() # this is a dict of user -> acc try:
for user_id, acc in accs.items(): leaderboard = await get_leaderboard(None, guild)
acc_data = acc.copy() except TypeError:
acc_data['created_at'] = _decode_time(acc_data['created_at']) raise
ret.append(Account(**acc_data)) else:
pos = discord.utils.find(lambda x: x[1][0] == member.id, enumerate(leaderboard, 1))
return ret if pos is None:
return None
else:
return pos[0]
async def get_account(member: Union[discord.Member, discord.User]) -> Account: async def get_account(member: Union[discord.Member, discord.User]) -> Account: