Skip to content

New features#75

Open
Arieswaran wants to merge 50 commits intomainfrom
aries/QoL
Open

New features#75
Arieswaran wants to merge 50 commits intomainfrom
aries/QoL

Conversation

@Arieswaran
Copy link
Collaborator

  • MV Guess
  • PvP
  • Emoji Quiz
  • Monthly leaderboard
  • Game reward changes to Card Reward
  • Profile Revamp

Arieswaran and others added 30 commits November 1, 2025 14:47
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
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revert

Removed an early return in CardPool.process_new_cards, allowing the method to process new images in the new cards folder as intended.
Copilot AI review requested due to automatic review settings November 28, 2025 14:20
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?"
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in the warning message: "Conver" should be "Convert".

Suggested change
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?"

Copilot uses AI. Check for mistakes.
@@ -1,4 +1,4 @@
import os, time, copy, json, random, logging, discord
import os, time, copy, json, random, logging, discord, Levenshtein
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.
Comment on lines +205 to +208
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)))},
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name actived_potions is grammatically incorrect. It should be activated_potions or active_potions.

Suggested change
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)))},

Copilot uses AI. Check for mistakes.

async def on_timeout(self) -> None:
for child in self.children:
child.TextStyle = discord.ButtonStyle.grey
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The attribute access on line 347 uses child.TextStyle which should be child.style. The attribute name is incorrect and will cause an AttributeError.

Suggested change
child.TextStyle = discord.ButtonStyle.grey
child.style = discord.ButtonStyle.grey

Copilot uses AI. Check for mistakes.
# 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:
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Suggested change
except Exception:
except Exception:
# Ignore logging errors to avoid interrupting reroll flow

Copilot uses AI. Check for mistakes.
Comment on lines +294 to +295
except:
pass
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Suggested change
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}")

Copilot uses AI. Check for mistakes.
child.disabled = True
try:
await self.message.edit(content="Challenge canceled.", view=self)
except Exception:
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Suggested change
except Exception:
except Exception:
# Ignore errors when editing the message (e.g., message may have been deleted or is uneditable).

Copilot uses AI. Check for mistakes.
try:
if self.message:
await self.message.edit(content="Challenge expired.", view=self)
except Exception:
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Copilot uses AI. Check for mistakes.
# Fail silently but log
try:
func.logger.exception("Failed to present normal quiz reward card view")
except:
Copy link

Copilot AI Nov 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Suggested change
except:
except:
# Logging failed; ignore to avoid masking the original error

Copilot uses AI. Check for mistakes.
Arieswaran and others added 15 commits November 28, 2025 20:19
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants