From 39b49974e3e063e9875d291e0188581ecdc90b3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Oberl=C3=A4nder?= Date: Thu, 9 Apr 2026 13:04:04 +0300 Subject: [PATCH 1/2] Delete bot/exts/levels directory --- bot/exts/levels/__init__.py | 10 - bot/exts/levels/_cog.py | 449 ---------------------- bot/exts/levels/rules/README.md | 46 --- bot/exts/levels/rules/blazing_fast.toml | 9 - bot/exts/levels/rules/java.toml | 4 - bot/exts/levels/rules/monty_python.toml | 29 -- bot/exts/levels/rules/numbers.toml | 9 - bot/exts/levels/rules/python_mention.toml | 19 - bot/exts/levels/rules/rust_mention.toml | 4 - bot/exts/levels/rules/slorb_mention.toml | 4 - bot/exts/levels/rules/wordle.toml | 14 - bot/exts/levels/rules/xkcd.toml | 14 - 12 files changed, 611 deletions(-) delete mode 100644 bot/exts/levels/__init__.py delete mode 100644 bot/exts/levels/_cog.py delete mode 100644 bot/exts/levels/rules/README.md delete mode 100644 bot/exts/levels/rules/blazing_fast.toml delete mode 100644 bot/exts/levels/rules/java.toml delete mode 100644 bot/exts/levels/rules/monty_python.toml delete mode 100644 bot/exts/levels/rules/numbers.toml delete mode 100644 bot/exts/levels/rules/python_mention.toml delete mode 100644 bot/exts/levels/rules/rust_mention.toml delete mode 100644 bot/exts/levels/rules/slorb_mention.toml delete mode 100644 bot/exts/levels/rules/wordle.toml delete mode 100644 bot/exts/levels/rules/xkcd.toml diff --git a/bot/exts/levels/__init__.py b/bot/exts/levels/__init__.py deleted file mode 100644 index 3dcfc32..0000000 --- a/bot/exts/levels/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from bot.bot import SirRobin - - -async def setup(bot: "SirRobin") -> None: - """Load the CodeJams cog.""" - from bot.exts.levels._cog import Levels - await bot.add_cog(Levels(bot)) diff --git a/bot/exts/levels/_cog.py b/bot/exts/levels/_cog.py deleted file mode 100644 index 77a4ea2..0000000 --- a/bot/exts/levels/_cog.py +++ /dev/null @@ -1,449 +0,0 @@ -import operator -import random -import re -import tomllib -from pathlib import Path -from typing import Annotated, Literal, cast - -import discord -from async_rediscache import RedisCache -from discord.ext import commands, tasks -from pydantic import BaseModel, Field, TypeAdapter, ValidationError -from pydis_core.utils.logging import get_logger - -from bot import constants -from bot.bot import SirRobin -from bot.utils import members -from bot.utils.decorators import in_whitelist - -logger = get_logger(__name__) - -ELEVATED_ROLES = (constants.Roles.admins, constants.Roles.moderation_team, constants.Roles.events_lead) - -ALLOWED_COMMAND_CHANNELS = (constants.Channels.bot_commands, constants.Channels.sir_lancebot_playground,) - -# Channels where the game runs. -ALLOWED_CHANNELS = ( - constants.Channels.off_topic_0, - constants.Channels.off_topic_1, - constants.Channels.off_topic_2, -) - -LEVEL_ROLES = frozenset({ - constants.Roles.levels_crystal, - constants.Roles.levels_level3, - constants.Roles.levels_s_tier, - constants.Roles.levels_diamond_rank, - constants.Roles.levels_GOAT, - constants.Roles.levels_mtfn, - constants.Roles.levels_champion, - constants.Roles.levels_mythical_python_charmer, - constants.Roles.levels_supernova_wonder, - constants.Roles.levels_ascension_20, -}) - -class Levels(commands.Cog): - """Cog that handles all Level functionality.""" - - #RedisCache[user_id: int, points: int] - user_points_cache = RedisCache() - - #RedisCache[role_id: int, point_threshold: int] - levels_cache = RedisCache() - - #RedisCache["value", bool] - running = RedisCache() - - def __init__(self, bot: SirRobin): - self.bot = bot - - self.rules_folder_path = Path("./bot/exts/levels/rules/") - - self.rules_all: list[LevelRules] = [] - self.rules_pool: list[LevelRules] = [] - self.rules_active: list[LevelRules] = [] # Active rules earn the points - self.rules_anti_active: list[LevelRules] = [] # Anti-active rules will halve the current points - - self.active_rules_num = 3 - self.anti_active_rules_num = 1 - - self.active_reaction_rule_triggers: list[ReactionRuleTrigger] = [] - self.active_message_rule_triggers: list[MessageRuleTrigger] = [] - self.anti_active_message_rule_triggers: list[MessageRuleTrigger] = [] - self.anti_active_reaction_rule_triggers: list[ReactionRuleTrigger] = [] - self.all_message_rule_triggers: list[MessageRuleTrigger] = [] - self.sorted_level_thresholds: list[tuple[int, int]] = [] - - - async def cog_load(self) -> None: - """Run startup tasks needed when cog is first loaded.""" - await self._load_rules() - - # Fill in cache with data for later functions to use - if await self.levels_cache.length() == 0: - shuffled_roles = random.sample(sorted(LEVEL_ROLES), len(LEVEL_ROLES)) - init_threshold_dict = dict.fromkeys(shuffled_roles, 0) - await self.levels_cache.update(init_threshold_dict) # type: ignore[arg-type] - logger.info("Filled levels cache with initial thresholds") - - await self._refresh_sorted_thresholds() - - if await self.running.get("value", False): - logger.debug("Starting Rules and Point Renormalization tasks") - self._cycle_rules_task.start() - logger.info("Started rule cycle task") - self._calculate_point_thresholds_task.start() - logger.info("Started point threshold task") - - async def _load_rules(self) -> None: - """ - Load and parse levels rules for usage. - - If a rule file does not comply with the format - and throws an error, it is skipped over. - """ - total_files_loaded = 0 - for toml_file in self.rules_folder_path.glob("*.toml"): - with open(toml_file, "rb") as f: - rule_dict = tomllib.load(f) - - rule_name = toml_file.stem - try: - rule_triggers = _rule_trigger_adapter.validate_python(rule_dict["rule"]) - rule = LevelRules(name=rule_name, rule_triggers=rule_triggers) - except (KeyError, ValidationError): - logger.info(f"{toml_file} not properly formatted, skipping.") - continue - - self.rules_all.append(rule) - total_files_loaded += 1 - - self.all_message_rule_triggers = [ - rule_trigger for rule in self.rules_all - for rule_trigger in rule.rule_triggers if rule_trigger.interaction_type == "message" - ] - logger.info(f"Total rules loaded: {total_files_loaded}") - - @tasks.loop(minutes=42.0) - async def _cycle_rules_task(self) -> None: - """ - Change which rules are currently active and anti-active. - - Rules will statistically be used before a repeat is seen. - This is not a guarantee though. - """ - if len(self.rules_pool) < (self.active_rules_num + self.anti_active_rules_num): - # If pool is empty, reshuffle completely to avoid activating same rule twice - self.rules_pool = random.sample(self.rules_all, len(self.rules_all)) - - self.rules_active = [self.rules_pool.pop() for _ in range(self.active_rules_num)] - self.rules_anti_active = [self.rules_pool.pop() for _ in range(self.anti_active_rules_num)] - logger.info(f"Cycled active rules to: {[rule.name for rule in self.rules_active]}") - logger.info(f"Cycled anti-active rule(s) to: {[rule.name for rule in self.rules_anti_active]}") - - self.active_message_rule_triggers = [ - rule_trigger for rule in self.rules_active - for rule_trigger in rule.rule_triggers if rule_trigger.interaction_type == "message" - ] - self.active_reaction_rule_triggers = [ - rule_trigger for rule in self.rules_active - for rule_trigger in rule.rule_triggers if rule_trigger.interaction_type == "reaction" - ] - - self.anti_active_message_rule_triggers = [ - rule_trigger for rule in self.rules_anti_active - for rule_trigger in rule.rule_triggers if rule_trigger.interaction_type == "message" - ] - self.anti_active_reaction_rule_triggers = [ - rule_trigger for rule in self.rules_anti_active - for rule_trigger in rule.rule_triggers if rule_trigger.interaction_type == "reaction" - ] - - @tasks.loop(minutes=90.0) - async def _calculate_point_thresholds_task(self) -> None: - """ - Calculate point thresholds based on number of roles, aiming for even deciles based on scores. - - If current max score is less than 100, it will fix deciles to increments of 10. - """ - user_points = await self.user_points_cache.to_dict() - all_scores = sorted(user_points.values()) - if all_scores and all_scores[-1] >= 100: - num_scores = len(all_scores) - num_levels = len(LEVEL_ROLES) - thresholds = [ - all_scores[round(num_scores * level/num_levels) - 1] - for level in range(1, num_levels+1) - ] - else: - # At the start of the event, just use multiples of 10 up to 100 - thresholds = [10 * i for i in range(1, len(LEVEL_ROLES) + 1)] - - levels = await self.levels_cache.to_dict() - new_levels = dict(zip(levels.keys(), thresholds, strict=False)) - await self.levels_cache.update(new_levels) # type: ignore[arg-type] - await self._refresh_sorted_thresholds() - logger.debug(f"Renormalizing score thresholds. Total scores: {len(all_scores)}") - logger.debug(f"New thresholds: {thresholds}") - - - async def _refresh_sorted_thresholds(self) -> None: - """Refresh the in-memory sorted threshold list from the levels cache.""" - levels = await self.levels_cache.to_dict() - self.sorted_level_thresholds = sorted(levels.items(), key=operator.itemgetter(1)) - - - async def _update_points(self, user_id: int, points: int, halve_points: bool=False) -> None: - """Updates user's score and ensures correct role is assigned.""" - logger.debug(f"User {user_id} getting {points} points, halving override: {halve_points}.") - if not await self.user_points_cache.contains(user_id): - await self.user_points_cache.set(user_id, points) - else: - if points == 0 and not halve_points: - return - current_points = cast(int, await self.user_points_cache.get(user_id, default=0)) - new_point_total = current_points + points - if halve_points: - new_point_total = new_point_total // 2 - - await self.user_points_cache.set(user_id, new_point_total) - - await self._update_role_assignment(user_id) - - - async def _update_role_assignment(self, user_id: int) -> None: - """Updates user's role based on current points and role-point thresholds.""" - user_points = cast(int, await self.user_points_cache.get(user_id, default=0)) - role_id_to_assign = None - - for role_id, point_threshold in self.sorted_level_thresholds: - role_id_to_assign = role_id - if point_threshold >= user_points: - break - - if role_id_to_assign is None: - logger.error("levels_cache is empty, cannot assign a role.") - return - - guild = self.bot.get_guild(constants.Bot.guild) - if guild is None: - logger.error("Could not find guild, cannot assign a role.") - return - - role = guild.get_role(role_id_to_assign) - user = await members.get_or_fetch_member(guild, user_id) - if user is None: - logger.debug(f"Could not find member {user_id} to assign role, skipping.") - return - if role is None: - logger.error(f"Could not resolve role {role_id_to_assign} to assign to {user_id}.") - return - - roles_to_remove = [ - user_role for user_role in user.roles - if user_role.id in LEVEL_ROLES and user_role != role - ] - if roles_to_remove: - await members.handle_role_change(user, user.remove_roles, *roles_to_remove) - if role in user.roles: - return - logger.debug(f"Assigning {role.name} to {user.name}") - await members.handle_role_change(user, user.add_roles, role) - - - @commands.Cog.listener() - async def on_message(self, msg: discord.Message) -> None: - """Listens to messages and checks against active message rules.""" - if not await self.running.get("value", False): - return - if msg.channel.id not in ALLOWED_CHANNELS or msg.author.bot: - return - if len(self.active_message_rule_triggers) == 0: - return - - user_id = msg.author.id - - total_points = 0 - rule_matches = 0 - for rule_trigger in self.active_message_rule_triggers: - match = re.search(rule_trigger.message_content, msg.content) - if match: - total_points += rule_trigger.points - rule_matches += 1 - - anti_active_rule_matches = 0 - for anti_active_rule_trigger in self.anti_active_message_rule_triggers: - match = re.search(anti_active_rule_trigger.message_content, msg.content) - if match: - anti_active_rule_matches += 1 - rule_matches += 1 - - halving_points = anti_active_rule_matches > 0 - - # Only update points if they've matched any rules - # If they match multiple rules and earn 0 points, - # that should still get them a role - if rule_matches != 0: - await self._update_points(user_id, total_points, halve_points=halving_points) - - total_rule_matches = 0 - for rule_trigger in self.all_message_rule_triggers: - match = re.search(rule_trigger.message_content, msg.content) - if match: - total_rule_matches += 1 - if total_rule_matches >= 3: - break - if total_rule_matches >= 3: - await self._update_points(user_id, -5) - - - @commands.Cog.listener() - async def on_reaction_add(self, reaction: discord.Reaction, user: discord.Member) -> None: - """ - Listens for reactions and checks against active reaction rules. - - It will only listen for reactions added to messages within the bot's message cache. - """ - if not await self.running.get("value", False): - return - if reaction.message.channel.id not in ALLOWED_CHANNELS or user.bot: - return - if len(self.active_reaction_rule_triggers) == 0: - return - - if isinstance(reaction.emoji, str): - emoji_name = reaction.emoji - else: - emoji_name = reaction.emoji.name - - total_points = 0 - rule_matches = 0 - for rule_trigger in self.active_reaction_rule_triggers: - if emoji_name in rule_trigger.reaction_content: - total_points += rule_trigger.points - rule_matches += 1 - - anti_active_rule_matches = 0 - for anti_active_rule_trigger in self.anti_active_reaction_rule_triggers: - if emoji_name in anti_active_rule_trigger.reaction_content: - anti_active_rule_matches += 1 - rule_matches += 1 - - halving_points = anti_active_rule_matches > 0 - - # Only update points if they've matched any rules - # If they match multiple rules and earn 0 points, - # that should still get them a role - if rule_matches != 0: - await self._update_points(user.id, total_points, halve_points=halving_points) - - - @commands.group(name="levels") - async def levels_command_group(self, ctx: commands.Context) -> None: - """Levels group command.""" - if not ctx.invoked_subcommand: - await self.bot.invoke_help_command(ctx) - - - @levels_command_group.command() - @in_whitelist(channels=ALLOWED_COMMAND_CHANNELS) - async def points(self, ctx: commands.Context) -> None: - """Check how many points you've accrued for the Role Level system.""" - user_id = ctx.author.id - - if await self.user_points_cache.contains(user_id): - points = await self.user_points_cache.get(user_id) - await ctx.reply(f"You have {points} points.") - else: - await ctx.reply("You have not earned any points so far! :D") - - - @levels_command_group.command() - @commands.has_any_role(*ELEVATED_ROLES) - async def shuffle_role_order(self, ctx: commands.Context) -> None: - """Shuffle which roles are assigned to which point thresholds.""" - levels = await self.levels_cache.to_dict() - thresholds = levels.values() - - role_order = random.sample(sorted(LEVEL_ROLES), len(LEVEL_ROLES)) - updated_ordering = dict(zip(role_order, thresholds, strict=False)) - - await self.levels_cache.update(updated_ordering) # type: ignore[arg-type] - logger.info(f"Roles have been re-shuffled per request of {ctx.author.name}") - - @levels_command_group.command() - @commands.has_any_role(*ELEVATED_ROLES) - async def start(self, ctx: commands.Context) -> None: - """Allows Levels to run, check messages, and assign roles.""" - current_state = await self.running.get("value", False) - if current_state: - await ctx.reply("Levels is already running.") - return - - self._cycle_rules_task.start() - self._calculate_point_thresholds_task.start() - await self.running.set("value", True) - await ctx.reply("Levels is now turned on.") - - @levels_command_group.command() - @commands.has_any_role(*ELEVATED_ROLES) - async def stop(self, ctx: commands.Context) -> None: - """Disallows Levels to run, check messages, and assign roles.""" - current_state = await self.running.get("value", False) - if not current_state: - await ctx.reply("Levels is already off.") - return - - self._cycle_rules_task.cancel() - self._calculate_point_thresholds_task.cancel() - await self.running.set("value", False) - await ctx.reply("Levels is now turned off.") - - @levels_command_group.command() - @commands.has_any_role(*ELEVATED_ROLES) - async def status(self, ctx: commands.Context) -> None: - """Replies with current status of Levels.""" - current_state = await self.running.get("value", False) - if current_state: - await ctx.reply(":white_check_mark: Levels is currently running.") - else: - await ctx.reply(":x: Levels is currently **not** running.") - - @levels_command_group.command() - @commands.has_any_role(*ELEVATED_ROLES) - async def points_award(self, ctx: commands.Context, member: discord.Member, point_offset: int) -> None: - """Edits the given user's current points value by the given point_offset.""" - member_id = member.id - current_points = cast(int, await self.user_points_cache.get(member_id, default=0)) - await self._update_points(member_id, point_offset) - await ctx.reply(f"Awarded {member} {point_offset} points. They now have {current_points+point_offset} points.") - - @levels_command_group.command() - @commands.has_any_role(*ELEVATED_ROLES) - async def role_reset(self, ctx: commands.Context, member: discord.Member) -> None: - """Reset a given user's 'level' roles. Role will be re-applied at the next rule trigger.""" - member_id = member.id - await self._update_role_assignment(member_id) - await ctx.reply(f"Reset {member}'s roles.") - -# Please see ./rules/README.md for how to format rules - -class MessageRuleTrigger(BaseModel): - interaction_type: Literal["message"] - message_content: str - points: int = 0 - -class ReactionRuleTrigger(BaseModel): - interaction_type: Literal["reaction"] - reaction_content: list[str] - points: int = 0 - -RuleTrigger = Annotated[ - MessageRuleTrigger | ReactionRuleTrigger, - Field(discriminator="interaction_type"), -] -_rule_trigger_adapter = TypeAdapter(list[RuleTrigger]) - -class LevelRules(BaseModel): - name: str - rule_triggers: list[RuleTrigger] diff --git a/bot/exts/levels/rules/README.md b/bot/exts/levels/rules/README.md deleted file mode 100644 index 6bf51b0..0000000 --- a/bot/exts/levels/rules/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# Rules format -Each rule should be in the following format: -```toml -[[rule]] -type = "message" | "reaction" -reaction_content = [] # each list item should be the name of a reaction or the reaction unicode itself -message_content = '''...''' # this should be a valid regex that can be compiled -points = 0 # the number of points that should be added -``` - -You can have multiple triggers with different point values for each rule file. -Each rule trigger is independent of each other. Any of them can trigger, they do not all have to trigger for points to be given. - -Notes: -- Each rule trigger needs to start with `[[rule]]` -- `reaction_content` - If the reaction is a default reaction, it should be the unicode emoji itself. If the reaction is a custom one, use the reaction name. -- `message_content` - Use triple quotes to avoid an escaping problem within toml, especially with regex. -- `points` - Can be a negative number. - -Examples of different rules: -```toml -[[rule]] -type = "message" -message_content = '''\b((?:p|P)ython)\b''' -points = 1 -``` - -```toml -[[rule]] -type = "reaction" -reaction_content = ["🦀", "rust"] -points = -1 -``` - -```toml -[[rule]] -interaction_type = "message" -message_content = '''((?:b|B)lazing(?:ly)*\sfast)''' -points = -1 - -[[rule]] -interaction_type = "message" -message_content = '''(?:🚀)+.*((?:b|B)lazing(?:ly)*\sfast).*(?:🚀)+''' -points = -2 -# A message that with the rocket emojis *and* blazing(ly) fast will get a total of -3 points with these triggers -``` diff --git a/bot/exts/levels/rules/blazing_fast.toml b/bot/exts/levels/rules/blazing_fast.toml deleted file mode 100644 index 62a9582..0000000 --- a/bot/exts/levels/rules/blazing_fast.toml +++ /dev/null @@ -1,9 +0,0 @@ -[[rule]] -interaction_type = "message" -message_content = '''((?:b|B)lazing(?:ly)*\sfast)''' -points = -1 - -[[rule]] -interaction_type = "message" -message_content = '''(?:🚀)+.*((?:b|B)lazing(?:ly)*\sfast).*?(?:🚀)+''' -points = -2 diff --git a/bot/exts/levels/rules/java.toml b/bot/exts/levels/rules/java.toml deleted file mode 100644 index 3b0c716..0000000 --- a/bot/exts/levels/rules/java.toml +++ /dev/null @@ -1,4 +0,0 @@ -[[rule]] -interaction_type = "message" -message_content = '''\b((?:j|J)ava)''' -points = -2 diff --git a/bot/exts/levels/rules/monty_python.toml b/bot/exts/levels/rules/monty_python.toml deleted file mode 100644 index ec74112..0000000 --- a/bot/exts/levels/rules/monty_python.toml +++ /dev/null @@ -1,29 +0,0 @@ -[[rule]] -interaction_type = "message" -message_content = '''\b([Ss]panish [Ii]nquisition)\b''' -points = 2 - -[[rule]] -interaction_type = "message" -message_content = '''\b([Cc]heese [Ss]hop)\b''' -points = 2 - -[[rule]] -interaction_type = "message" -message_content = '''\b(Ni!)\b''' -points = 3 - -[[rule]] -interaction_type = "message" -message_content = '''\b(IDLE|Idle|Cleese|Gilliam|Jones|Chapman|Palin)\b''' -points = 1 - -[[rule]] -interaction_type = "message" -message_content = '''\b(\'[Tt]is but a scratch)\b''' -points = 1 - -[[rule]] -interaction_type = "message" -message_content = '''\b([Ff]light [Ss]peed|[Uu]nladen [Ss]wallow|[Aa]frican or [Ee]uropean)\b''' -points = 2 diff --git a/bot/exts/levels/rules/numbers.toml b/bot/exts/levels/rules/numbers.toml deleted file mode 100644 index 22e8ce8..0000000 --- a/bot/exts/levels/rules/numbers.toml +++ /dev/null @@ -1,9 +0,0 @@ -[[rule]] -interaction_type = "message" -message_content = '''\b(42|23|1337)\b''' -points = 2 - -[[rule]] -interaction_type = "message" -message_content = '''\b(67|69|420)\b''' -points = -1 diff --git a/bot/exts/levels/rules/python_mention.toml b/bot/exts/levels/rules/python_mention.toml deleted file mode 100644 index 919f61c..0000000 --- a/bot/exts/levels/rules/python_mention.toml +++ /dev/null @@ -1,19 +0,0 @@ -[[rule]] -interaction_type = "message" -message_content = '''\b((?:p|P)ython)\b''' -points = 1 - -[[rule]] -interaction_type = "message" -message_content = '''\b((?:import\s+)?antigravity)\b''' -points = 2 - -[[rule]] -interaction_type = "message" -message_content = '''(<>|\b[Bb]arry(?:_as_FLUFL)?\b|[Bb][Dd][Ff][Ll]|\b(?:PEP|pep)\s401\b)''' -points = 1 - -[[rule]] -interaction_type = "message" -message_content = '''\b([Gg]uido(?:\s[Vv]an\s[Rr]ossum)?)\b''' -points = 1 diff --git a/bot/exts/levels/rules/rust_mention.toml b/bot/exts/levels/rules/rust_mention.toml deleted file mode 100644 index b9a2189..0000000 --- a/bot/exts/levels/rules/rust_mention.toml +++ /dev/null @@ -1,4 +0,0 @@ -[[rule]] -interaction_type = "reaction" -reaction_content = ['🦀', "rust"] -points = 1 diff --git a/bot/exts/levels/rules/slorb_mention.toml b/bot/exts/levels/rules/slorb_mention.toml deleted file mode 100644 index ad03b08..0000000 --- a/bot/exts/levels/rules/slorb_mention.toml +++ /dev/null @@ -1,4 +0,0 @@ -[[rule]] -interaction_type = "message" -message_content = '''(!slorb)''' -points = 3 diff --git a/bot/exts/levels/rules/wordle.toml b/bot/exts/levels/rules/wordle.toml deleted file mode 100644 index 75804e5..0000000 --- a/bot/exts/levels/rules/wordle.toml +++ /dev/null @@ -1,14 +0,0 @@ -[[rule]] -interaction_type = "message" -message_content = '''(🟩🟩🟩🟩🟩)''' -points = 2 - -[[rule]] -interaction_type = "message" -message_content = '''(⬜⬜⬜⬜⬜)''' -points = -1 - -[[rule]] -interaction_type = "message" -message_content = '''(⬛⬛⬛⬛⬛)''' -points = -1 diff --git a/bot/exts/levels/rules/xkcd.toml b/bot/exts/levels/rules/xkcd.toml deleted file mode 100644 index e6ac649..0000000 --- a/bot/exts/levels/rules/xkcd.toml +++ /dev/null @@ -1,14 +0,0 @@ -[[rule]] -interaction_type = "message" -message_content = '''\b([Bb]obby [Tt]ables|[Ss]hibboleet)\b''' -points = 2 - -[[rule]] -interaction_type = "message" -message_content = '''\b(xkcd)\b''' -points = 1 - -[[rule]] -interaction_type = "message" -message_content = '''\b(is just applied)\b''' -points = 1 From 55b10f0c00e38baceefb29844789610bbec0afa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Oberl=C3=A4nder?= Date: Thu, 9 Apr 2026 15:36:07 +0300 Subject: [PATCH 2/2] Remove level-specific constants --- bot/constants.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/bot/constants.py b/bot/constants.py index b0a7b0b..e742ead 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -169,17 +169,6 @@ class _Roles(EnvConfig, env_prefix="ROLE_"): team_dict: int = 1222691368653033652 team_tuple: int = 1222691399246286888 - levels_crystal: int = 1488465184803524758 - levels_level3: int = 1488465669401088000 - levels_s_tier: int = 1488465793082462248 - levels_diamond_rank: int = 1488465915560460399 - levels_GOAT: int = 1488465529835487232 #noqa: N815 - levels_mtfn: int = 1488537117976957030 - levels_champion: int = 1488464806855053433 - levels_mythical_python_charmer: int = 1488466097412771853 - levels_supernova_wonder: int = 1488466164106395718 - levels_ascension_20: int = 1488466329672351876 - Roles = _Roles()