feat(rmenus): Support negative prices.
This commit is contained in:
@@ -49,16 +49,20 @@ class CoinSetting(IntegerSetting):
|
||||
|
||||
if num > cls._max:
|
||||
t = ctx_translator.get().t
|
||||
raise UserInputError(t(_p(
|
||||
'settype:coin|parse|error:too_large',
|
||||
"Provided number of coins was too high!"
|
||||
))) from None
|
||||
raise UserInputError(
|
||||
t(_p(
|
||||
'settype:coin|parse|error:too_large',
|
||||
"You cannot set this to more than {coin}**{max}**!"
|
||||
)).format(coin=conf.emojis.coin, max=cls._max)
|
||||
) from None
|
||||
elif num < cls._min:
|
||||
t = ctx_translator.get().t
|
||||
raise UserInputError(t(_p(
|
||||
'settype:coin|parse|error:too_large',
|
||||
"Provided number of coins was too low!"
|
||||
))) from None
|
||||
raise UserInputError(
|
||||
t(_p(
|
||||
'settype:coin|parse|error:too_small',
|
||||
"You cannot set this to less than {coin}**{min}**!"
|
||||
)).format(coin=conf.emojis.coin, min=cls._min)
|
||||
) from None
|
||||
|
||||
return num
|
||||
|
||||
|
||||
@@ -1192,7 +1192,7 @@ class RoleMenuCog(LionCog):
|
||||
label: Optional[appcmds.Range[str, 1, 100]] = None,
|
||||
emoji: Optional[appcmds.Range[str, 0, 100]] = None,
|
||||
description: Optional[appcmds.Range[str, 0, 100]] = None,
|
||||
price: Optional[appcmds.Range[int, 0, MAX_COINS]] = None,
|
||||
price: Optional[appcmds.Range[int, -MAX_COINS, MAX_COINS]] = None,
|
||||
duration: Optional[Transform[int, DurationTransformer(60)]] = None,
|
||||
):
|
||||
# Type checking guards
|
||||
@@ -1448,7 +1448,7 @@ class RoleMenuCog(LionCog):
|
||||
label: Optional[appcmds.Range[str, 1, 100]] = None,
|
||||
emoji: Optional[appcmds.Range[str, 0, 100]] = None,
|
||||
description: Optional[appcmds.Range[str, 0, 100]] = None,
|
||||
price: Optional[appcmds.Range[int, 0, MAX_COINS]] = None,
|
||||
price: Optional[appcmds.Range[int, -MAX_COINS, MAX_COINS]] = None,
|
||||
duration: Optional[Transform[int, DurationTransformer(60)]] = None,
|
||||
):
|
||||
# Type checking wards
|
||||
|
||||
@@ -165,7 +165,7 @@ class RoleMenu:
|
||||
await menu.attach()
|
||||
return menu
|
||||
|
||||
async def fetch_message(self, refresh=False):
|
||||
async def fetch_message(self, refresh=False) -> Optional[discord.Message]:
|
||||
"""
|
||||
Fetch the message the menu is attached to.
|
||||
"""
|
||||
@@ -529,11 +529,17 @@ class RoleMenu:
|
||||
"Role removed"
|
||||
))
|
||||
)
|
||||
if total_refund:
|
||||
if total_refund > 0:
|
||||
embed.description = t(_p(
|
||||
'rolemenu|deselect|success:refund|desc',
|
||||
"You have removed **{role}**, and been refunded {coin} **{amount}**."
|
||||
)).format(role=role.name, coin=self.bot.config.emojis.coin, amount=total_refund)
|
||||
if total_refund < 0:
|
||||
# TODO: Consider disallowing them from removing roles if their balance would go negative
|
||||
embed.description = t(_p(
|
||||
'rolemenu|deselect|success:negrefund|desc',
|
||||
"You have removed **{role}**, and have lost {coin} **{amount}**."
|
||||
)).format(role=role.name, coin=self.bot.config.emojis.coin, amount=-total_refund)
|
||||
else:
|
||||
embed.description = t(_p(
|
||||
'rolemenu|deselect|success:norefund|desc',
|
||||
@@ -551,7 +557,7 @@ class RoleMenu:
|
||||
raise UserInputError(
|
||||
t(_p(
|
||||
'rolemenu|select|error:required_role',
|
||||
"You need to have the **{role}** role to use this!"
|
||||
"You need to have the role **{role}** required to use this menu!"
|
||||
)).format(role=name)
|
||||
)
|
||||
|
||||
@@ -647,7 +653,7 @@ class RoleMenu:
|
||||
"Role equipped"
|
||||
))
|
||||
)
|
||||
if price > 0:
|
||||
if price:
|
||||
embed.description = t(_p(
|
||||
'rolemenu|select|success:purchase|desc',
|
||||
"You have purchased the role **{role}** for {coin}**{amount}**"
|
||||
@@ -665,6 +671,7 @@ class RoleMenu:
|
||||
)).format(
|
||||
timestamp=discord.utils.format_dt(expiry)
|
||||
)
|
||||
# TODO Event logging
|
||||
return embed
|
||||
|
||||
async def interactive_selection(self, interaction: discord.Interaction, menuroleid: int):
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
from typing import Optional
|
||||
import discord
|
||||
|
||||
from settings import ModelData
|
||||
from settings.groups import SettingGroup, ModelConfig, SettingDotDict
|
||||
from settings.setting_types import (
|
||||
RoleSetting, BoolSetting, StringSetting, DurationSetting, EmojiSetting
|
||||
RoleSetting, StringSetting, DurationSetting, EmojiSetting
|
||||
)
|
||||
from core.setting_types import CoinSetting
|
||||
from utils.ui import AButton, AsComponents
|
||||
from meta.errors import UserInputError
|
||||
from meta import conf
|
||||
from babel.translator import ctx_translator
|
||||
from constants import MAX_COINS
|
||||
|
||||
from .data import RoleMenuData
|
||||
from . import babel
|
||||
@@ -74,6 +77,9 @@ class RoleMenuRoleOptions(SettingGroup):
|
||||
"This menu item will now give the role {role}."
|
||||
)).format(role=self.formatted)
|
||||
return resp
|
||||
else:
|
||||
raise ValueError("Attempt to call update_message without a value.")
|
||||
|
||||
|
||||
@RoleMenuRoleConfig.register_model_setting
|
||||
class Label(ModelData, StringSetting):
|
||||
@@ -138,7 +144,9 @@ class RoleMenuRoleOptions(SettingGroup):
|
||||
return button
|
||||
|
||||
@classmethod
|
||||
async def _parse_string(cls, parent_id, string: str, interaction: discord.Interaction = None, **kwargs):
|
||||
async def _parse_string(cls, parent_id, string: str,
|
||||
interaction: Optional[discord.Interaction] = None,
|
||||
**kwargs):
|
||||
emojistr = await super()._parse_string(parent_id, string, interaction=interaction, **kwargs)
|
||||
if emojistr and interaction is not None:
|
||||
# Use the interaction to test
|
||||
@@ -151,7 +159,7 @@ class RoleMenuRoleOptions(SettingGroup):
|
||||
view=view,
|
||||
)
|
||||
except discord.HTTPException:
|
||||
t = interaction.client.translator.t
|
||||
t = ctx_translator.get().t
|
||||
raise UserInputError(t(_p(
|
||||
'roleset:emoji|error:test_emoji',
|
||||
"The selected emoji `{emoji}` is invalid or has been deleted."
|
||||
@@ -218,34 +226,43 @@ class RoleMenuRoleOptions(SettingGroup):
|
||||
_display_name = _p('roleset:price', "price")
|
||||
_desc = _p(
|
||||
'roleset:price|desc',
|
||||
"Price of the role, in LionCoins."
|
||||
"Price of the role, in LionCoins. May be negative."
|
||||
)
|
||||
_long_desc = _p(
|
||||
'roleset:price|long_desc',
|
||||
"How much the role costs when selected, in LionCoins."
|
||||
"How many LionCoins should be deducted from a member's account "
|
||||
"when they equip this role through this menu.\n"
|
||||
"The price may be negative, in which case the member will instead be rewarded "
|
||||
"coins when they equip the role."
|
||||
)
|
||||
_accepts = _p(
|
||||
'roleset:price|accepts',
|
||||
"Amount of coins that the role costs."
|
||||
"Amount of coins that the role costs when equipped."
|
||||
)
|
||||
_default = 0
|
||||
_min = - MAX_COINS
|
||||
_model = RoleMenuData.RoleMenuRole
|
||||
_column = RoleMenuData.RoleMenuRole.price.name
|
||||
|
||||
@property
|
||||
def update_message(self) -> str:
|
||||
t = ctx_translator.get().t
|
||||
value = self.value
|
||||
if value:
|
||||
value = self.value or 0
|
||||
if value > 0:
|
||||
resp = t(_p(
|
||||
'roleset:price|set_response:set',
|
||||
"This role will now cost {price} to equip."
|
||||
)).format(price=self.formatted)
|
||||
'roleset:price|set_response:positive',
|
||||
"Equipping this role will now cost {coin}**{price}**."
|
||||
)).format(price=value, coin=conf.emojis.coin)
|
||||
elif value == 0:
|
||||
resp = t(_p(
|
||||
'roleset:price|set_response:zero',
|
||||
"Equipping this role is now free."
|
||||
))
|
||||
else:
|
||||
resp = t(_p(
|
||||
'roleset:price|set_response:unset',
|
||||
"This role will now be free to equip from this role menu."
|
||||
))
|
||||
'roleset:price|set_response:negative',
|
||||
"Equipping this role will now reward {coin}**{price}**."
|
||||
)).format(price=-value, coin=conf.emojis.coin)
|
||||
return resp
|
||||
|
||||
@RoleMenuRoleConfig.register_model_setting
|
||||
|
||||
Reference in New Issue
Block a user