[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())
next_payday = cur_time + await self.config.PAYDAY_TIME()
await self.config.user(author).next_payday.set(next_payday)
await ctx.send(
_("{} Here, take some {}. Enjoy! (+{}"
" {}!)").format(
author.mention, credits_name,
str(await self.config.PAYDAY_CREDITS()),
credits_name
)
)
pos = await bank.get_leaderboard_position(author)
await ctx.send(_(
"{0.mention} Here, take some {1}. Enjoy! (+{2}\n\n"
"You currently have {3} {1}.\n\n"
"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:
dtime = self.display_time(next_payday - cur_time)
await ctx.send(
@ -255,12 +258,15 @@ class Economy:
await bank.deposit_credits(author, await self.config.guild(guild).PAYDAY_CREDITS())
next_payday = cur_time + await self.config.guild(guild).PAYDAY_TIME()
await self.config.member(author).next_payday.set(next_payday)
await ctx.send(
_("{} Here, take some {}. Enjoy! (+{}"
" {}!)").format(
author.mention, credits_name,
str(await self.config.guild(guild).PAYDAY_CREDITS()),
credits_name))
pos = await bank.get_leaderboard_position(author)
await ctx.send(_(
"{0.mention} Here, take some {1}. Enjoy! (+{2})\n\n"
"You currently have {3} {1}.\n\n"
"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:
dtime = self.display_time(next_payday - cur_time)
await ctx.send(
@ -269,7 +275,7 @@ class Economy:
@commands.command()
@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
Defaults to top 10"""
@ -277,26 +283,23 @@ class Economy:
guild = ctx.guild
if top < 1:
top = 10
if await bank.is_global():
bank_sorted = sorted(await bank.get_global_accounts(),
key=lambda x: x.balance, reverse=True)
else:
bank_sorted = sorted(await bank.get_guild_accounts(guild),
key=lambda x: x.balance, reverse=True)
if await bank.is_global() and show_global: # show_global is only applicable if bank is global
guild = None
bank_sorted = await bank.get_leaderboard(positions=top, guild=guild)
if len(bank_sorted) < top:
top = len(bank_sorted)
topten = bank_sorted[:top]
highscore = ""
place = 1
for acc in topten:
dname = str(acc.name)
if len(dname) >= 23 - len(str(acc.balance)):
dname = dname[:(23 - len(str(acc.balance))) - 3]
dname += "... "
highscore += str(place).ljust(len(str(top)) + 1)
highscore += dname.ljust(23 - len(str(acc.balance)))
highscore += str(acc.balance) + "\n"
place += 1
for pos, acc in enumerate(bank_sorted, 1):
pos = pos
poswidth = 2
name = acc[1]["name"]
namewidth = 35
balance = acc[1]["balance"]
balwidth = 2
highscore += "{pos: <{poswidth}} {name: <{namewidth}s} {balance: >{balwidth}}\n".format(
pos=pos, poswidth=poswidth, name=name, namewidth=namewidth,
balance=balance, balwidth=balwidth
)
if highscore != "":
for page in pagify(highscore, shorten_by=12):
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):
raise ValueError("Invalid withdrawal amount {} <= 0".format(amount))
raise ValueError("Invalid deposit amount {} <= 0".format(amount))
bal = await get_balance(member)
return await set_balance(member, amount + bal)
@ -287,62 +287,81 @@ async def wipe_bank():
await _conf.clear_all_members()
async def get_guild_accounts(guild: discord.Guild) -> List[Account]:
"""Get all account data for the given guild.
async def get_leaderboard(positions: int=None, guild: discord.Guild=None) -> List[tuple]:
"""
Gets the bank's leaderboard
Parameters
----------
positions : `int`
The number of positions to get
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
-------
`list` of `Account`
A list of all guild accounts.
`list` of `tuple`
The sorted leaderboard in the form of :code:`(user_id, raw_account)`
Raises
------
RuntimeError
If the bank is currently global.
TypeError
If the bank is guild-specific and no guild was specified
"""
if await is_global():
raise RuntimeError("The bank is currently global.")
ret = []
accs = await _conf.all_members(guild)
for user_id, acc in accs.items():
acc_data = acc.copy() # There ya go kowlin
acc_data['created_at'] = _decode_time(acc_data['created_at'])
ret.append(Account(**acc_data))
return ret
raw_accounts = await _conf.all_users()
if guild is not None:
tmp = raw_accounts.copy()
for acc in tmp:
if not guild.get_member(acc):
del raw_accounts[acc]
else:
if guild is None:
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]:
"""Get all global account data.
async def get_leaderboard_position(member: Union[discord.User, discord.Member]) -> Union[int, None]:
"""
Get the leaderboard position for the specified user
Parameters
----------
member : `discord.User` or `discord.Member`
The user to get the leaderboard position of
Returns
-------
`list` of `Account`
A list of all global accounts.
`int`
The position of the user on the leaderboard
Raises
------
RuntimeError
If the bank is currently guild specific.
TypeError
If the bank is currently guild-specific and a `discord.User` object was passed in
"""
if not await is_global():
raise RuntimeError("The bank is not currently global.")
ret = []
accs = await _conf.all_users() # this is a dict of user -> acc
for user_id, acc in accs.items():
acc_data = acc.copy()
acc_data['created_at'] = _decode_time(acc_data['created_at'])
ret.append(Account(**acc_data))
return ret
if await is_global():
guild = None
else:
guild = member.guild if hasattr(member, "guild") else None
try:
leaderboard = await get_leaderboard(None, guild)
except TypeError:
raise
else:
pos = discord.utils.find(lambda x: x[1][0] == member.id, enumerate(leaderboard, 1))
if pos is None:
return None
else:
return pos[0]
async def get_account(member: Union[discord.Member, discord.User]) -> Account: