2024-04-05 12:06:44 +00:00
|
|
|
import asyncio
|
2023-07-14 15:51:26 +00:00
|
|
|
import random
|
2023-06-29 11:21:17 +00:00
|
|
|
import time
|
2024-03-25 12:46:55 +00:00
|
|
|
|
2024-03-20 17:15:10 +00:00
|
|
|
import discord
|
2024-04-05 12:06:44 +00:00
|
|
|
from discord.ext.commands import Cog
|
2023-06-29 11:21:17 +00:00
|
|
|
|
2024-03-25 12:46:55 +00:00
|
|
|
from config.parser import JsonCache
|
2024-03-20 17:15:10 +00:00
|
|
|
from lib import formatter
|
2024-06-20 10:34:03 +00:00
|
|
|
from services.config_service import GuildConfig
|
2024-04-04 11:03:51 +00:00
|
|
|
from services.xp_service import XpService, XpRewardService
|
2023-06-29 11:21:17 +00:00
|
|
|
|
2024-04-04 20:40:59 +00:00
|
|
|
_strings = JsonCache.read_json("strings")
|
|
|
|
_messages = JsonCache.read_json("levels")
|
2023-07-12 19:37:21 +00:00
|
|
|
|
|
|
|
|
2024-03-20 17:15:10 +00:00
|
|
|
class XPHandler:
|
2024-04-04 20:40:59 +00:00
|
|
|
def __init__(self, message):
|
|
|
|
self.message = message
|
|
|
|
self.author = message.author
|
|
|
|
self.guild = message.guild
|
|
|
|
self.channel = message.channel
|
2023-07-02 12:20:16 +00:00
|
|
|
|
2024-04-04 20:40:59 +00:00
|
|
|
self.xp_conf = XpService(self.author.id, self.guild.id)
|
|
|
|
self.guild_conf = None
|
2023-06-29 11:21:17 +00:00
|
|
|
|
2024-04-04 20:40:59 +00:00
|
|
|
def process(self) -> bool:
|
|
|
|
_xp = self.xp_conf
|
|
|
|
_now = time.time()
|
|
|
|
leveled_up = False
|
2023-07-15 15:33:58 +00:00
|
|
|
|
2024-04-04 20:40:59 +00:00
|
|
|
if _xp.cooldown_time and _now < _xp.cooldown_time:
|
|
|
|
return False
|
2023-07-14 15:51:26 +00:00
|
|
|
|
2024-04-04 20:40:59 +00:00
|
|
|
# award the amount of XP specified in .env
|
|
|
|
_xp.xp += _xp.xp_gain
|
2023-07-14 15:51:26 +00:00
|
|
|
|
2024-04-04 20:40:59 +00:00
|
|
|
# check if total xp now exceeds the xp required to level up
|
|
|
|
if _xp.xp >= XpService.xp_needed_for_next_level(_xp.level):
|
|
|
|
_xp.level += 1
|
|
|
|
_xp.xp = 0
|
|
|
|
leveled_up = True
|
2023-07-14 15:51:26 +00:00
|
|
|
|
2024-04-04 20:40:59 +00:00
|
|
|
_xp.cooldown_time = _now + _xp.new_cooldown
|
|
|
|
_xp.push()
|
|
|
|
return leveled_up
|
2023-07-14 15:51:26 +00:00
|
|
|
|
2024-04-04 20:40:59 +00:00
|
|
|
async def notify(self) -> None:
|
|
|
|
_xp = self.xp_conf
|
|
|
|
_gd = GuildConfig(self.guild.id)
|
2023-07-14 15:51:26 +00:00
|
|
|
|
2024-04-04 20:40:59 +00:00
|
|
|
level_message = await self.get_level_message(_gd, _xp, self.author)
|
2023-06-29 11:21:17 +00:00
|
|
|
|
2024-04-04 20:40:59 +00:00
|
|
|
if level_message:
|
|
|
|
level_channel = await self.get_level_channel(self.message, _gd)
|
2023-07-12 14:49:18 +00:00
|
|
|
|
2024-04-04 20:40:59 +00:00
|
|
|
if level_channel:
|
|
|
|
await level_channel.send(content=level_message)
|
|
|
|
else:
|
|
|
|
await self.message.reply(content=level_message)
|
|
|
|
|
|
|
|
async def reward(self) -> None:
|
|
|
|
_xp = self.xp_conf
|
|
|
|
_rew = XpRewardService(self.guild.id)
|
2023-06-29 11:21:17 +00:00
|
|
|
|
2024-04-04 20:40:59 +00:00
|
|
|
role_id = _rew.role(_xp.level)
|
|
|
|
reason = 'Automated Level Reward'
|
2024-04-03 16:06:03 +00:00
|
|
|
|
2024-04-04 20:40:59 +00:00
|
|
|
if role_id:
|
2024-03-20 17:15:10 +00:00
|
|
|
|
2024-04-04 20:40:59 +00:00
|
|
|
role = self.guild.get_role(role_id)
|
|
|
|
if role:
|
|
|
|
try:
|
|
|
|
await self.author.add_roles(role, reason=reason)
|
|
|
|
except (discord.Forbidden, discord.NotFound, discord.HTTPException):
|
|
|
|
pass
|
2023-06-29 11:21:17 +00:00
|
|
|
|
2024-04-04 20:40:59 +00:00
|
|
|
previous = _rew.replace_previous_reward(_xp.level)
|
|
|
|
if previous[1]:
|
|
|
|
role = self.guild.get_role(previous[0])
|
|
|
|
if role:
|
|
|
|
try:
|
|
|
|
await self.author.remove_roles(role, reason=reason)
|
|
|
|
except (discord.Forbidden, discord.NotFound, discord.HTTPException):
|
|
|
|
pass
|
2023-06-29 11:21:17 +00:00
|
|
|
|
2024-03-20 17:15:10 +00:00
|
|
|
@staticmethod
|
|
|
|
async def get_level_channel(message, guild_config):
|
|
|
|
if guild_config.level_channel_id:
|
2023-07-15 15:33:58 +00:00
|
|
|
try:
|
2024-03-20 17:15:10 +00:00
|
|
|
return message.guild.get_channel(guild_config.level_channel_id)
|
|
|
|
except discord.HTTPException:
|
|
|
|
pass # channel not found
|
2023-06-29 11:21:17 +00:00
|
|
|
|
2024-03-20 17:15:10 +00:00
|
|
|
return None
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
async def get_level_message(guild_config, level_config, author):
|
|
|
|
match guild_config.level_message_type:
|
|
|
|
case 0:
|
|
|
|
level_message = None
|
|
|
|
case 1:
|
2024-04-04 20:40:59 +00:00
|
|
|
level_message = XPHandler.messages_whimsical(level_config.level, author)
|
2024-03-20 17:15:10 +00:00
|
|
|
case 2:
|
|
|
|
if not guild_config.level_message:
|
|
|
|
level_message = XPHandler.level_message_generic(level_config.level, author)
|
|
|
|
else:
|
2024-03-29 17:17:51 +00:00
|
|
|
level_message = formatter.template(guild_config.level_message, author.name, level_config.level)
|
2024-03-20 17:15:10 +00:00
|
|
|
case _:
|
|
|
|
raise Exception
|
|
|
|
|
|
|
|
return level_message
|
2023-06-29 11:21:17 +00:00
|
|
|
|
2024-03-20 17:15:10 +00:00
|
|
|
@staticmethod
|
|
|
|
def level_message_generic(level, author):
|
2024-04-04 20:40:59 +00:00
|
|
|
return _strings["level_up"].format(author.name, level)
|
2023-06-29 11:21:17 +00:00
|
|
|
|
|
|
|
@staticmethod
|
2024-04-04 20:40:59 +00:00
|
|
|
def messages_whimsical(level, author):
|
2024-03-20 17:15:10 +00:00
|
|
|
"""
|
|
|
|
v2 of the level messages, randomized output from levels.en-US.JSON.
|
|
|
|
:param level:
|
|
|
|
:param author:
|
|
|
|
:return:
|
|
|
|
"""
|
|
|
|
|
|
|
|
level_range = None
|
2024-04-04 20:40:59 +00:00
|
|
|
for key in _messages.keys():
|
2024-03-20 17:15:10 +00:00
|
|
|
start, end = map(int, key.split('-'))
|
|
|
|
if start <= level <= end:
|
|
|
|
level_range = key
|
|
|
|
break
|
|
|
|
|
|
|
|
if level_range is None:
|
|
|
|
# generic fallback
|
|
|
|
return XPHandler.level_message_generic(level, author)
|
|
|
|
|
2024-04-04 20:40:59 +00:00
|
|
|
message_list = _messages[level_range]
|
2024-03-20 17:15:10 +00:00
|
|
|
random_message = random.choice(message_list)
|
2024-04-04 20:40:59 +00:00
|
|
|
start_string = _strings["level_up_prefix"].format(author.name)
|
2024-03-20 17:15:10 +00:00
|
|
|
return start_string + random_message.format(level)
|
2024-04-05 12:05:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
class XpListener(Cog):
|
|
|
|
def __init__(self, client):
|
|
|
|
self.client = client
|
|
|
|
|
|
|
|
@Cog.listener('on_message')
|
|
|
|
async def xp_listener(self, message):
|
|
|
|
if (
|
|
|
|
message.author.bot or
|
|
|
|
message.guild is None
|
|
|
|
):
|
|
|
|
return
|
|
|
|
|
|
|
|
_xp = XPHandler(message)
|
|
|
|
leveled_up = _xp.process()
|
|
|
|
|
|
|
|
if leveled_up:
|
2024-06-20 17:48:49 +00:00
|
|
|
coroutines = [
|
2024-04-05 12:05:36 +00:00
|
|
|
asyncio.create_task(_xp.notify()),
|
|
|
|
asyncio.create_task(_xp.reward())
|
|
|
|
]
|
2024-06-20 17:48:49 +00:00
|
|
|
await asyncio.wait(coroutines)
|
2024-04-05 12:05:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
def setup(client):
|
|
|
|
client.add_cog(XpListener(client))
|