mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 03:08:55 -05:00
[Bank] Allow bank managers to set the maximum allowed balance in the bank (#2926)
* Removes `MAX_BALANCE` from bank, user `bank.get_max_balance()` now `[p]bankset maxbal` can be used to set the maximum bank balance Signed-off-by: Guy <guyreis96@gmail.com> * Removes `MAX_BALANCE` from bank, user `bank.get_max_balance()` now `[p]bankset maxbal` can be used to set the maximum bank balance Signed-off-by: Guy <guyreis96@gmail.com> * Removes `MAX_BALANCE` from bank, user `bank.get_max_balance()` now `[p]bankset maxbal` can be used to set the maximum bank balance Signed-off-by: Guy <guyreis96@gmail.com> * Rename method 🤦 Signed-off-by: Guy <guyreis96@gmail.com> * Updated this to be aware of #2925 Signed-off-by: guyre <27962761+drapersniper@users.noreply.github.com> * Addressed Flames review + Fixed 1 bug in errors.py + `[p]leaderboard` and `[p]bank balance` will set the users balance to max balance if the bank maxbal is lower than the previous user balance Signed-off-by: guyre <27962761+drapersniper@users.noreply.github.com> * Missed this clarification Signed-off-by: guyre <27962761+drapersniper@users.noreply.github.com> * address Flames review Signed-off-by: guyre <27962761+drapersniper@users.noreply.github.com>
This commit is contained in:
parent
b490942bcd
commit
e04eed4a89
1
changelog.d/2926.breaking.rst
Normal file
1
changelog.d/2926.breaking.rst
Normal file
@ -0,0 +1 @@
|
||||
Removed :cons:`bank.MAX_BALANCE`, use :meth:`bank.get_max_balance()` from now.
|
||||
1
changelog.d/2926.feature.rst
Normal file
1
changelog.d/2926.feature.rst
Normal file
@ -0,0 +1 @@
|
||||
`[p]bankset maxbal` can be used to set the maximum bank balance.
|
||||
@ -86,11 +86,12 @@ class Bank(commands.Cog):
|
||||
|
||||
settings = _(
|
||||
"Bank settings:\n\nBank name: {bank_name}\nCurrency: {currency_name}\n"
|
||||
"Default balance: {default_balance}"
|
||||
"Default balance: {default_balance}\nMaximum allowed balance: {maximum_bal}"
|
||||
).format(
|
||||
bank_name=bank_name,
|
||||
currency_name=currency_name,
|
||||
default_balance=humanize_number(default_balance),
|
||||
maximum_bal=humanize_number(await bank.get_max_balance(ctx.guild)),
|
||||
)
|
||||
await ctx.send(box(settings))
|
||||
|
||||
@ -130,4 +131,21 @@ class Bank(commands.Cog):
|
||||
await bank.set_currency_name(name, ctx.guild)
|
||||
await ctx.send(_("Currency name has been set to: {name}").format(name=name))
|
||||
|
||||
@bankset.command(name="maxbal")
|
||||
@check_global_setting_guildowner()
|
||||
async def bankset_maxbal(self, ctx: commands.Context, *, amount: int):
|
||||
"""Set the maximum balance a user can get."""
|
||||
try:
|
||||
await bank.set_max_balance(amount, ctx.guild)
|
||||
except ValueError:
|
||||
# noinspection PyProtectedMember
|
||||
return await ctx.send(
|
||||
_("Amount must be greater than zero and less than {max}.").format(
|
||||
max=humanize_number(bank._MAX_BALANCE)
|
||||
)
|
||||
)
|
||||
await ctx.send(
|
||||
_("Maximum balance has been set to: {amount}").format(amount=humanize_number(amount))
|
||||
)
|
||||
|
||||
# ENDSECTION
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import calendar
|
||||
import logging
|
||||
import random
|
||||
from collections import defaultdict, deque
|
||||
from collections import defaultdict, deque, namedtuple
|
||||
from enum import Enum
|
||||
from typing import cast, Iterable
|
||||
|
||||
@ -20,6 +20,7 @@ T_ = Translator("Economy", __file__)
|
||||
logger = logging.getLogger("red.economy")
|
||||
|
||||
NUM_ENC = "\N{COMBINING ENCLOSING KEYCAP}"
|
||||
MOCK_MEMBER = namedtuple("Member", "id guild")
|
||||
|
||||
|
||||
class SMReel(Enum):
|
||||
@ -159,7 +160,10 @@ class Economy(commands.Cog):
|
||||
|
||||
bal = await bank.get_balance(user)
|
||||
currency = await bank.get_currency_name(ctx.guild)
|
||||
|
||||
max_bal = await bank.get_max_balance(ctx.guild)
|
||||
if bal > max_bal:
|
||||
bal = max_bal
|
||||
await bank.set_balance(user, bal)
|
||||
await ctx.send(
|
||||
_("{user}'s balance is {num} {currency}").format(
|
||||
user=user.display_name, num=humanize_number(bal), currency=currency
|
||||
@ -363,6 +367,7 @@ class Economy(commands.Cog):
|
||||
"""
|
||||
guild = ctx.guild
|
||||
author = ctx.author
|
||||
max_bal = await bank.get_max_balance(ctx.guild)
|
||||
if top < 1:
|
||||
top = 10
|
||||
if await bank.is_global() and show_global:
|
||||
@ -372,6 +377,9 @@ class Economy(commands.Cog):
|
||||
bank_sorted = await bank.get_leaderboard(positions=top, guild=guild)
|
||||
try:
|
||||
bal_len = len(humanize_number(bank_sorted[0][1]["balance"]))
|
||||
bal_len_max = len(humanize_number(max_bal))
|
||||
if bal_len > bal_len_max:
|
||||
bal_len = bal_len_max
|
||||
# first user is the largest we'll see
|
||||
except IndexError:
|
||||
return await ctx.send(_("There are no accounts in the bank."))
|
||||
@ -394,8 +402,12 @@ class Economy(commands.Cog):
|
||||
if await ctx.bot.is_owner(ctx.author):
|
||||
user_id = f"({str(acc[0])})"
|
||||
name = f"{acc[1]['name']} {user_id}"
|
||||
balance = humanize_number(acc[1]["balance"])
|
||||
|
||||
balance = acc[1]["balance"]
|
||||
if balance > max_bal:
|
||||
balance = max_bal
|
||||
await bank.set_balance(MOCK_MEMBER(acc[0], guild), balance)
|
||||
balance = humanize_number(balance)
|
||||
if acc[0] != author.id:
|
||||
temp_msg += (
|
||||
f"{f'{humanize_number(pos)}.': <{pound_len+2}} "
|
||||
@ -560,7 +572,8 @@ class Economy(commands.Cog):
|
||||
"Slot cooldown: {slot_time}\n"
|
||||
"Payday amount: {payday_amount}\n"
|
||||
"Payday cooldown: {payday_time}\n"
|
||||
"Amount given at account registration: {register_amount}"
|
||||
"Amount given at account registration: {register_amount}\n"
|
||||
"Maximum allowed balance: {maximum_bal}"
|
||||
).format(
|
||||
slot_min=humanize_number(await conf.SLOT_MIN()),
|
||||
slot_max=humanize_number(await conf.SLOT_MAX()),
|
||||
@ -568,6 +581,7 @@ class Economy(commands.Cog):
|
||||
payday_time=humanize_number(await conf.PAYDAY_TIME()),
|
||||
payday_amount=humanize_number(await conf.PAYDAY_CREDITS()),
|
||||
register_amount=humanize_number(await bank.get_default_balance(guild)),
|
||||
maximum_bal=humanize_number(await bank.get_max_balance(guild)),
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -639,9 +653,13 @@ class Economy(commands.Cog):
|
||||
async def paydayamount(self, ctx: commands.Context, creds: int):
|
||||
"""Set the amount earned each payday."""
|
||||
guild = ctx.guild
|
||||
if creds <= 0 or creds > bank.MAX_BALANCE:
|
||||
await ctx.send(_("Har har so funny."))
|
||||
return
|
||||
max_balance = await bank.get_max_balance(ctx.guild)
|
||||
if creds <= 0 or creds > max_balance:
|
||||
return await ctx.send(
|
||||
_("Amount must be greater than zero and less than {maxbal}.").format(
|
||||
maxbal=humanize_number(max_balance)
|
||||
)
|
||||
)
|
||||
credits_name = await bank.get_currency_name(guild)
|
||||
if await bank.is_global():
|
||||
await self.config.PAYDAY_CREDITS.set(creds)
|
||||
@ -657,9 +675,13 @@ class Economy(commands.Cog):
|
||||
async def rolepaydayamount(self, ctx: commands.Context, role: discord.Role, creds: int):
|
||||
"""Set the amount earned each payday for a role."""
|
||||
guild = ctx.guild
|
||||
if creds <= 0 or creds > bank.MAX_BALANCE:
|
||||
await ctx.send(_("Har har so funny."))
|
||||
return
|
||||
max_balance = await bank.get_max_balance(ctx.guild)
|
||||
if creds <= 0 or creds > max_balance:
|
||||
return await ctx.send(
|
||||
_("Amount must be greater than zero and less than {maxbal}.").format(
|
||||
maxbal=humanize_number(max_balance)
|
||||
)
|
||||
)
|
||||
credits_name = await bank.get_currency_name(guild)
|
||||
if await bank.is_global():
|
||||
await ctx.send(_("The bank must be per-server for per-role paydays to work."))
|
||||
@ -676,10 +698,16 @@ class Economy(commands.Cog):
|
||||
async def registeramount(self, ctx: commands.Context, creds: int):
|
||||
"""Set the initial balance for new bank accounts."""
|
||||
guild = ctx.guild
|
||||
if creds < 0:
|
||||
creds = 0
|
||||
max_balance = await bank.get_max_balance(ctx.guild)
|
||||
credits_name = await bank.get_currency_name(guild)
|
||||
await bank.set_default_balance(creds, guild)
|
||||
try:
|
||||
await bank.set_default_balance(creds, guild)
|
||||
except ValueError:
|
||||
return await ctx.send(
|
||||
_("Amount must be greater than or equal to zero and less than {maxbal}.").format(
|
||||
maxbal=humanize_number(max_balance)
|
||||
)
|
||||
)
|
||||
await ctx.send(
|
||||
_("Registering an account will now give {num} {currency}.").format(
|
||||
num=humanize_number(creds), currency=credits_name
|
||||
|
||||
@ -12,7 +12,6 @@ from .i18n import Translator
|
||||
_ = Translator("Bank API", __file__)
|
||||
|
||||
__all__ = [
|
||||
"MAX_BALANCE",
|
||||
"Account",
|
||||
"get_balance",
|
||||
"set_balance",
|
||||
@ -30,20 +29,28 @@ __all__ = [
|
||||
"set_currency_name",
|
||||
"get_default_balance",
|
||||
"set_default_balance",
|
||||
"get_max_balance",
|
||||
"set_max_balance",
|
||||
"cost",
|
||||
"AbortPurchase",
|
||||
]
|
||||
|
||||
MAX_BALANCE = 2 ** 63 - 1
|
||||
_MAX_BALANCE = 2 ** 63 - 1
|
||||
|
||||
_DEFAULT_GLOBAL = {
|
||||
"is_global": False,
|
||||
"bank_name": "Twentysix bank",
|
||||
"currency": "credits",
|
||||
"default_balance": 100,
|
||||
"max_balance": _MAX_BALANCE,
|
||||
}
|
||||
|
||||
_DEFAULT_GUILD = {"bank_name": "Twentysix bank", "currency": "credits", "default_balance": 100}
|
||||
_DEFAULT_GUILD = {
|
||||
"bank_name": "Twentysix bank",
|
||||
"currency": "credits",
|
||||
"default_balance": 100,
|
||||
"max_balance": _MAX_BALANCE,
|
||||
}
|
||||
|
||||
_DEFAULT_MEMBER = {"name": "", "balance": 0, "created_at": 0}
|
||||
|
||||
@ -186,10 +193,11 @@ async def set_balance(member: discord.Member, amount: int) -> int:
|
||||
"""
|
||||
if amount < 0:
|
||||
raise ValueError("Not allowed to have negative balance.")
|
||||
if amount > MAX_BALANCE:
|
||||
max_bal = await get_max_balance(member.guild)
|
||||
if amount > max_bal:
|
||||
currency = await get_currency_name(member.guild)
|
||||
raise errors.BalanceTooHigh(
|
||||
user=member.display_name, max_balance=MAX_BALANCE, currency_name=currency
|
||||
user=member.display_name, max_balance=max_bal, currency_name=currency
|
||||
)
|
||||
if await is_global():
|
||||
group = _conf.user(member)
|
||||
@ -329,10 +337,12 @@ async def transfer_credits(from_: discord.Member, to: discord.Member, amount: in
|
||||
)
|
||||
)
|
||||
|
||||
if await get_balance(to) + amount > MAX_BALANCE:
|
||||
max_bal = await get_max_balance(to.guild)
|
||||
|
||||
if await get_balance(to) + amount > max_bal:
|
||||
currency = await get_currency_name(to.guild)
|
||||
raise errors.BalanceTooHigh(
|
||||
user=to.display_name, max_balance=MAX_BALANCE, currency_name=currency
|
||||
user=to.display_name, max_balance=max_bal, currency_name=currency
|
||||
)
|
||||
|
||||
await withdraw_credits(from_, amount)
|
||||
@ -635,6 +645,75 @@ async def set_currency_name(name: str, guild: discord.Guild = None) -> str:
|
||||
return name
|
||||
|
||||
|
||||
async def get_max_balance(guild: discord.Guild = None) -> int:
|
||||
"""Get the max balance for the bank.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
guild : `discord.Guild`, optional
|
||||
The guild to get the max balance for (required if bank is
|
||||
guild-specific).
|
||||
|
||||
Returns
|
||||
-------
|
||||
int
|
||||
The maximum allowed balance.
|
||||
|
||||
Raises
|
||||
------
|
||||
RuntimeError
|
||||
If the bank is guild-specific and guild was not provided.
|
||||
|
||||
"""
|
||||
if await is_global():
|
||||
return await _conf.max_balance()
|
||||
elif guild is not None:
|
||||
return await _conf.guild(guild).max_balance()
|
||||
else:
|
||||
raise RuntimeError("Guild must be provided.")
|
||||
|
||||
|
||||
async def set_max_balance(amount: int, guild: discord.Guild = None) -> int:
|
||||
"""Set the maximum balance for the bank.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
amount : int
|
||||
The new maximum balance.
|
||||
guild : `discord.Guild`, optional
|
||||
The guild to set the max balance for (required if bank is
|
||||
guild-specific).
|
||||
|
||||
Returns
|
||||
-------
|
||||
int
|
||||
The new maximum balance.
|
||||
|
||||
Raises
|
||||
------
|
||||
RuntimeError
|
||||
If the bank is guild-specific and guild was not provided.
|
||||
ValueError
|
||||
If the amount is less than 0 or higher than 2 ** 63 - 1.
|
||||
"""
|
||||
if not (0 < amount <= _MAX_BALANCE):
|
||||
raise ValueError(
|
||||
"Amount must be greater than zero and less than {max}.".format(
|
||||
max=humanize_number(_MAX_BALANCE, override_locale="en_US")
|
||||
)
|
||||
)
|
||||
|
||||
if await is_global():
|
||||
await _conf.max_balance.set(amount)
|
||||
elif guild is not None:
|
||||
await _conf.guild(guild).max_balance.set(amount)
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"Guild must be provided if setting the maximum balance of a guild-specific bank."
|
||||
)
|
||||
return amount
|
||||
|
||||
|
||||
async def get_default_balance(guild: discord.Guild = None) -> int:
|
||||
"""Get the current default balance amount.
|
||||
|
||||
@ -684,12 +763,18 @@ async def set_default_balance(amount: int, guild: discord.Guild = None) -> int:
|
||||
RuntimeError
|
||||
If the bank is guild-specific and guild was not provided.
|
||||
ValueError
|
||||
If the amount is invalid.
|
||||
If the amount is less than 0 or higher than the max allowed balance.
|
||||
|
||||
"""
|
||||
amount = int(amount)
|
||||
if amount < 0:
|
||||
raise ValueError("Amount must be greater than zero.")
|
||||
max_bal = await get_max_balance(guild)
|
||||
|
||||
if not (0 < amount <= max_bal):
|
||||
raise ValueError(
|
||||
"Amount must be greater than zero and less than {max}.".format(
|
||||
max=humanize_number(max_bal, override_locale="en_US")
|
||||
)
|
||||
)
|
||||
|
||||
if await is_global():
|
||||
await _conf.default_balance.set(amount)
|
||||
@ -714,7 +799,7 @@ def cost(amount: int):
|
||||
You can intentionally refund by raising `AbortPurchase`
|
||||
(this error will be consumed and not show to users)
|
||||
|
||||
Other exceptions will propogate and will be handled by Red's (and/or
|
||||
Other exceptions will propagate and will be handled by Red's (and/or
|
||||
any other configured) error handling.
|
||||
"""
|
||||
if not isinstance(amount, int) or amount < 0:
|
||||
|
||||
@ -46,7 +46,7 @@ class BalanceTooHigh(BankError, OverflowError):
|
||||
self.currency_name = currency_name
|
||||
|
||||
def __str__(self) -> str:
|
||||
return _("{user}'s balance cannot rise above max {currency}.").format(
|
||||
return _("{user}'s balance cannot rise above {max} {currency}.").format(
|
||||
user=self.user, max=humanize_number(self.max_balance), currency=self.currency_name
|
||||
)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user