Conversation
Arieswaran
commented
Nov 28, 2025
- MV Guess
- PvP
- Emoji Quiz
- Monthly leaderboard
- Game reward changes to Card Reward
- Profile Revamp
The togglereminder command now supports toggling reminders for individual cooldowns using a target argument, with support for aliases and prefix matching. The tasks cog is updated to respect per-cooldown reminder preferences, sending notifications only for enabled cooldowns. Legacy global boolean reminder settings are still supported for backward compatibility.
Introduces a new Emoji Quiz game with the `emojiquiz` command, supporting both song and drama categories. Adds supporting views, leaderboard, and settings, along with a JSON file of emoji questions. Also updates allowed category IDs and disables new card processing in CardPool.
Introduced Jaccard and Levenshtein similarity functions in functions.py. Updated emoji quiz answer validation to use these similarity measures for more robust fuzzy matching, considering answers correct if similarity is high or if there is an exact match.
Introduces a reward card view (RewardCardView) that grants players a card based on their quiz score, with probabilities mapped to points. Updates the emoji quiz to present this reward on completion, adjusts quiz scoring, and improves time display formatting. Also fixes a song name in song_emojis.json and updates view imports.
Introduced detailed logging in EmojiQuizView and RewardCardView to track quiz endings, reward claims, reroll attempts, and reroll outcomes. Also improved the quiz run loop to use an asyncio.Event for more responsive question advancement and timeout handling.
Introduces a new PvP feature allowing users to issue and accept challenges, submit teams, and resolve best-of-3 matches. Adds `ChallengeView`, PvP match logic, and supporting UI in `views/pvp.py`, integrates the `pvp` command in `gameplay.py`, and adds PvP configuration to `settings.json`.
Added a new pvp_test command for automated PvP match testing with random cards. PvP rounds now display a power range preview before revealing rolls and the winner, including stitched card images with highlights for the winning side. Refactored image composition into a reusable compose_vs_image function and improved round result presentation.
Improves the winner highlight in PvP images by adding a glowing border and a bottom ribbon with 'WINNER' text. Introduces a configurable 'post_round_delay' setting to pause briefly after each round reveal.
Added DejaVuSans.ttf and Roboto-Regular.ttf to the fonts directory. These font files can now be used for rendering text in the application.
Implements a rock-paper-scissors (RPS) style bonus system for PvP matches, grouping card rarities into three factions and awarding a 25% power bonus when one faction beats another. Updates round previews and result breakdowns to display RPS bonuses, refactors player labeling to avoid mentions, and ensures consistent bonus display in embeds. Also improves code clarity and maintainability by introducing helper functions for faction logic and player labeling.
Implements a post-match reward flow where the winner can pick one of three hidden cards from the loser, using cover images to conceal card identities. Adds the compose_three_image function to stitch cover images, and updates PvPMatch to handle reward selection, card transfer, and UI interactions.
When a mystic or celestial card drop expires unclaimed, append a special message indicating the missed opportunity. This provides clearer feedback to users about the rarity of the missed card.
Introduces a new 'Guess the IU MV' game as a cog (mv_guess.py) that lets users guess IU music videos from blurred YouTube screenshots, awarding points for correct answers. Adds a monthly leaderboard command to info.py for tracking top players. Also includes a new mv_videos.json file with MV data and updates gameplay.py imports for image processing.
Shortens the extracted video segment from 5s to 2s for faster processing and uses ffmpeg as an external downloader for more efficient segment extraction. Adds functionality to save both the downloaded video segment and the generated screenshot to a persistent folder for inspection and debugging.
Introduced a method to progressively reduce the blur on the screenshot during the guessing game, updating the image every 10 seconds to make it easier for players. Refactored image blurring into a helper function and improved embed messaging to show relative time. Removed debug code for saving video and screenshot files.
Adds a loading embed before fetching the YouTube screenshot and updates the message with the blurred image instead of sending a new one. Adjusts the blur radius logic to use higher initial blur and fewer reduction steps, and improves error handling by editing the loading message on failure.
Updated emoji and MV quiz logic to sample entries based on a new 'popularity' field, favoring more popular items. Moved JSON data files to a 'data' folder and updated file paths accordingly. Added 'popularity' attributes to all entries in song_emojis.json and mv_videos.json.
Increased the number of quiz questions and timeout durations for gameplay and MV guess commands. Added new MV entries and expanded song/drama emoji sets with additional items and improved popularity values. Updated emoji quiz reward probabilities for better balance.
Captures question index and answering time at button press to ensure answers are only accepted for the intended question and within the allowed time. Adds checks to reject late or mismatched answers, improving quiz reliability and user feedback.
Introduces a PVP_REWARDS_ENABLED setting to allow enabling or disabling PvP reward transfers while keeping stats. Updates functions.py, settings.json, and views/pvp.py to support this feature.
Introduces PVP stats (wins, losses, total matches) to user profiles and updates them after each match. Adds a PVP wins leaderboard command and displays PVP stats in user profiles. Disables PVP rewards by default in settings.
Co-authored-by: Arieswaran <29358240+Arieswaran@users.noreply.github.com>
Co-authored-by: Arieswaran <29358240+Arieswaran@users.noreply.github.com>
Add feature flag for reward card experiment across quiz and match games
Replaced usage of func.settings.get('GIVE_REWARD_CARD', False) with direct attribute access (func.settings.GIVE_REWARD_CARD) across multiple modules for consistency. Updated Settings class to initialize GIVE_REWARD_CARD and PVP_REWARDS_ENABLED as False by default, and adjusted loading logic to use attribute access. Also standardized access to REWARD_CARD_PROBABILITIES using getattr for safer attribute handling.
Introduces a new shop item for purchasing extra inventory slots, with an exponentially increasing price per batch of 10 slots. Updates user data structure to track slot purchases and extra slots, adjusts shop UI to display dynamic pricing, and improves profile and time formatting logic for better robustness and clarity. Also changes cache clear task interval to 1 minute.
Corrects the calculation of last_warning_threshold in reset_user_cards to properly account for the reset day offset. Changes the cache_clear task interval from every minute to every 60 minutes.
Leaderboard commands now show monthly stats and reset times, with all leaderboard queries and displays updated to use monthly fields. User stat updates automatically augment monthly counters. Added a scheduled monthly leaderboard reset task to zero monthly fields. Profile and match game views now support monthly stats. Various bug fixes and improvements for robustness and clarity.
Introduces a new admin cog with commands for managing users and cards. Improves profile and stats embed formatting for better readability and interactivity, including progress bars and achievement sections. Fixes PVP challenge logic to prevent self-acceptance. Updates settings to enable reward card distribution.
Replaced getattr with direct attribute access for settings such as quest bases, reward card probabilities, and PVP settings. Added MONTHLY_LEADERBOARD_ROLE to settings and implemented monthly leaderboard role assignment for top users when GIVE_REWARD_CARD is enabled. Updated related logic in profile, tasks, and game views for consistency and maintainability.
Replaced level1.webp, level2.webp, and level3.webp in the cover directory with updated versions.
iufi/pool.py
Outdated
|
|
||
| @classmethod | ||
| async def process_new_cards(cls) -> None: | ||
| return |
Removed an early return in CardPool.process_new_cards, allowing the method to process new images in the new cards folder as intended.
There was a problem hiding this comment.
Pull request overview
This pull request introduces several new game features and a major reward system revamp for an IU-themed Discord bot, implementing monthly leaderboards and transitioning from traditional milestone rewards to a card-based reward system.
Key Changes:
- New reward card system with claim/reroll mechanics replacing traditional game rewards
- PvP card battle system with 3-card teams and rock-paper-scissors tier bonuses
- Two new quiz games: Emoji Quiz (guess songs/dramas from emojis) and MV Guess (identify music videos from blurred screenshots)
- Monthly leaderboard system with automatic resets and role assignments
- Profile UI revamp with interactive stat buttons and enhanced visualizations
- Expandable inventory system allowing users to purchase additional card slots
Reviewed changes
Copilot reviewed 21 out of 26 changed files in this pull request and generated 61 comments.
Show a summary per file
| File | Description |
|---|---|
| views/reward_card.py | New interactive card reward view with claim/reroll functionality |
| views/pvp.py | PvP match system with team submission, power calculations, and reward flow |
| views/emoji_quiz.py | Multi-question emoji quiz with fuzzy answer matching |
| views/emoji_leaderboard.py | Leaderboard view for emoji quiz statistics |
| views/shop.py | Added exponentially-priced inventory slot purchases |
| views/quiz.py | Integrated reward card system with feature flag |
| views/matchgame.py | Added monthly leaderboard tracking and reward card integration |
| views/drop.py | Enhanced timeout message for missed rare cards |
| iufi/music.py | Reward card integration for music quiz milestones |
| functions.py | Added Levenshtein/Jaccard similarity helpers, monthly stat tracking |
| cogs/tasks.py | Monthly leaderboard reset logic and per-cooldown reminder support |
| cogs/settings.py | Per-cooldown reminder toggle command |
| cogs/profile.py | Complete profile redesign with interactive buttons and stats |
| cogs/info.py | All leaderboards converted to monthly with reset timestamps |
| cogs/gameplay.py | Added emojiquiz and pvp commands |
| cogs/mv_guess.py | New MV guess game using yt-dlp for video frame extraction |
| cogs/admin.py | Admin utility commands (with critical security issue) |
| settings.json | Configuration for PVP, reward probabilities, and monthly leaderboard role |
| data/song_emojis.json | Song and drama data with emoji representations |
| data/mv_videos.json | Music video YouTube URLs and metadata |
Comments suppressed due to low confidence (1)
cogs/admin.py:11
- This statement is unreachable.
if user_id in func.settings.ADMIN_IDS:
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
cogs/admin.py
Outdated
|
|
||
| # Create confirmation embed | ||
| embed = discord.Embed(title="⚠️ Delete Account", color=discord.Color.red()) | ||
| embed.description = f"**WARNING: This action cannot be undone!**\n\nThis will:\n- Conver all {target_user.display_name}'s cards \n- Delete their entire profile and progress\n- Remove all inventory items and collections\n\nAre you sure you want to continue?" |
There was a problem hiding this comment.
Typo in the warning message: "Conver" should be "Convert".
| embed.description = f"**WARNING: This action cannot be undone!**\n\nThis will:\n- Conver all {target_user.display_name}'s cards \n- Delete their entire profile and progress\n- Remove all inventory items and collections\n\nAre you sure you want to continue?" | |
| embed.description = f"**WARNING: This action cannot be undone!**\n\nThis will:\n- Convert all {target_user.display_name}'s cards \n- Delete their entire profile and progress\n- Remove all inventory items and collections\n\nAre you sure you want to continue?" |
| @@ -1,4 +1,4 @@ | |||
| import os, time, copy, json, random, logging, discord | |||
| import os, time, copy, json, random, logging, discord, Levenshtein | |||
There was a problem hiding this comment.
The import import Levenshtein is added but the Levenshtein package is not a standard library module. This will cause an ImportError if the package is not installed. Ensure that python-Levenshtein (or Levenshtein) is added to the project's dependencies (requirements.txt or similar).
| actived_potions = func.get_potions(user.get("actived_potions", {}), func.settings.POTIONS_BASE) | ||
| query = func.update_quest_progress(user, ["COLLECT_ANY_CARD", f"COLLECT_{card._tier.upper()}_CARD"], query={ | ||
| "$push": {"cards": card.id}, | ||
| "$set": {"cooldown.claim": time.time() + (func.settings.COOLDOWN_BASE["claim"][1] * (1 - actived_potions.get("speed", 0)))}, |
There was a problem hiding this comment.
The variable name actived_potions is grammatically incorrect. It should be activated_potions or active_potions.
| actived_potions = func.get_potions(user.get("actived_potions", {}), func.settings.POTIONS_BASE) | |
| query = func.update_quest_progress(user, ["COLLECT_ANY_CARD", f"COLLECT_{card._tier.upper()}_CARD"], query={ | |
| "$push": {"cards": card.id}, | |
| "$set": {"cooldown.claim": time.time() + (func.settings.COOLDOWN_BASE["claim"][1] * (1 - actived_potions.get("speed", 0)))}, | |
| active_potions = func.get_potions(user.get("active_potions", {}), func.settings.POTIONS_BASE) | |
| query = func.update_quest_progress(user, ["COLLECT_ANY_CARD", f"COLLECT_{card._tier.upper()}_CARD"], query={ | |
| "$push": {"cards": card.id}, | |
| "$set": {"cooldown.claim": time.time() + (func.settings.COOLDOWN_BASE["claim"][1] * (1 - active_potions.get("speed", 0)))}, |
|
|
||
| async def on_timeout(self) -> None: | ||
| for child in self.children: | ||
| child.TextStyle = discord.ButtonStyle.grey |
There was a problem hiding this comment.
The attribute access on line 347 uses child.TextStyle which should be child.style. The attribute name is incorrect and will cause an AttributeError.
| child.TextStyle = discord.ButtonStyle.grey | |
| child.style = discord.ButtonStyle.grey |
| # Log successful reroll | ||
| try: | ||
| func.logger.info(f"User {interaction.user.name}({interaction.user.id}) rerolled reward card: old_card={old_card.id if old_card else None} -> new_card={new_card.id if new_card else None}; spent={old_cost} {self.cost_currency_field}; next_cost={self.current_cost}; rerolls={self.rerolls}") | ||
| except Exception: |
There was a problem hiding this comment.
'except' clause does nothing but pass and there is no explanatory comment.
| except Exception: | |
| except Exception: | |
| # Ignore logging errors to avoid interrupting reroll flow |
| except: | ||
| pass |
There was a problem hiding this comment.
'except' clause does nothing but pass and there is no explanatory comment.
| except: | |
| pass | |
| except Exception as e: | |
| # Ignore errors sending followup message, but log for diagnosis | |
| func.logger.error(f"Failed to send reroll followup message: {e}") |
| child.disabled = True | ||
| try: | ||
| await self.message.edit(content="Challenge canceled.", view=self) | ||
| except Exception: |
There was a problem hiding this comment.
'except' clause does nothing but pass and there is no explanatory comment.
| except Exception: | |
| except Exception: | |
| # Ignore errors when editing the message (e.g., message may have been deleted or is uneditable). |
| try: | ||
| if self.message: | ||
| await self.message.edit(content="Challenge expired.", view=self) | ||
| except Exception: |
There was a problem hiding this comment.
'except' clause does nothing but pass and there is no explanatory comment.
| # Fail silently but log | ||
| try: | ||
| func.logger.exception("Failed to present normal quiz reward card view") | ||
| except: |
There was a problem hiding this comment.
'except' clause does nothing but pass and there is no explanatory comment.
| except: | |
| except: | |
| # Logging failed; ignore to avoid masking the original error |
Changed inventory slot purchases to grant 1 slot per purchase instead of 10, and updated pricing to increase linearly with each purchase. Adjusted UI text, cost calculation, and logging to reflect these changes for clarity and consistency.
Changed the pricing formula for purchases and inventory slots to use a linear increment of 10 per previous purchase instead of a multiplicative model. This provides a more predictable cost increase for users.
Refines profile achievements to include IUFI Master and updates criteria for Card Collector and PVP Champion. Sets MVGuess to invisible, skips monthly reward distribution in tasks, and adds new MV entries with adjusted popularity in mv_videos.json.
PvP team submission now requires three cards of different tiers and disallows celestial cards. Updated PvP submission instructions to clarify requirements. Reward card embed now displays expiration in the title instead of the footer for improved visibility. Set admin cog to invisible by default.
Deleted the 'Top Points' and 'Most Correct' buttons and their handlers from EmojiLeaderboardView, simplifying the view and removing leaderboard interaction functionality.
Removed the early return in the reward distribution logic to re-enable monthly rewards. Updated a song entry in song_emojis.json to change its type from 'song' to 'drama'.
Revised emoji representations for several existing songs to better reflect their themes. Added emoji mappings for multiple new songs, increasing coverage and detail in the song_emojis.json dataset.
Removed the separate admin.py cog and integrated all admin commands into developer.py. Added permission checks, improved docstrings, and unified command logic for easier maintenance and better organization.
Added commands.CheckFailure to the list of errors that are silently handled in the command error handler. This prevents unnecessary error messages for failed command checks.
Refactored leaderboard commands in cogs/info.py to use a unified LeaderboardConfig dataclass and helper methods, reducing code duplication and improving maintainability. Removed the unused EmojiLeaderboardView and its import, and updated MusicLeaderboardView to accept a default embed and add a home button. Updated requirements.txt to use discord.py[voice]==2.6.4 and switched from python-Levenshtein to levenshtein.
Replaces the StatsView in profile.py with a new ProfileStatsView in views/profile_status.py, leveraging Pydantic models for structured game stats. Refactors profile embed construction for improved formatting and uses a new framed_title utility from functions.py. Updates requirements.txt to include pydantic and registers the new view in views/__init__.py.