generated from nhcarrigan/template
feat: add more achievements
This commit is contained in:
@@ -55,6 +55,28 @@ pub enum AchievementId {
|
||||
SpeedCoder, // 10 code blocks in 10 minutes
|
||||
ClaudeConnoisseur, // Used all Claude models
|
||||
MarathonCoder, // 10k tokens in one session
|
||||
|
||||
// Relationship & Greetings
|
||||
GoodMorning, // Say "good morning"
|
||||
GoodNight, // Say "good night" or "goodnight"
|
||||
ThankYou, // Say "thank you" or "thanks"
|
||||
LoveYou, // Say "love you" or "ily"
|
||||
|
||||
// Personality & Fun
|
||||
EmojiUser, // Use an emoji in a message
|
||||
QuestionMaster, // Use "?" in 20 messages
|
||||
CapsLock, // Send a message in ALL CAPS
|
||||
PleaseAndThankYou, // Use "please" in messages
|
||||
|
||||
// Git & Development
|
||||
GitGuru, // Use git commands 10 times
|
||||
TestWriter, // Create test files
|
||||
Debugger, // Fix bugs (messages with "fix", "bug", "error")
|
||||
|
||||
// Tool Mastery
|
||||
BashMaster, // Use Bash tool 50 times
|
||||
FileExplorer, // Use Read tool 100 times
|
||||
SearchExpert, // Use Grep tool 50 times
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@@ -361,9 +383,164 @@ pub fn get_achievement_info(id: &AchievementId) -> Achievement {
|
||||
icon: "🏃♂️".to_string(),
|
||||
unlocked_at: None,
|
||||
},
|
||||
|
||||
// Relationship & Greetings
|
||||
AchievementId::GoodMorning => Achievement {
|
||||
id: id.clone(),
|
||||
name: "Good Morning!".to_string(),
|
||||
description: "Greeted Hikari with a good morning".to_string(),
|
||||
icon: "🌅".to_string(),
|
||||
unlocked_at: None,
|
||||
},
|
||||
AchievementId::GoodNight => Achievement {
|
||||
id: id.clone(),
|
||||
name: "Good Night".to_string(),
|
||||
description: "Said good night to Hikari".to_string(),
|
||||
icon: "🌙".to_string(),
|
||||
unlocked_at: None,
|
||||
},
|
||||
AchievementId::ThankYou => Achievement {
|
||||
id: id.clone(),
|
||||
name: "Grateful Heart".to_string(),
|
||||
description: "Thanked Hikari for her help".to_string(),
|
||||
icon: "💝".to_string(),
|
||||
unlocked_at: None,
|
||||
},
|
||||
AchievementId::LoveYou => Achievement {
|
||||
id: id.clone(),
|
||||
name: "Love Connection".to_string(),
|
||||
description: "Expressed love to Hikari".to_string(),
|
||||
icon: "💕".to_string(),
|
||||
unlocked_at: None,
|
||||
},
|
||||
|
||||
// Personality & Fun
|
||||
AchievementId::EmojiUser => Achievement {
|
||||
id: id.clone(),
|
||||
name: "Emoji Enthusiast".to_string(),
|
||||
description: "Used an emoji in your message".to_string(),
|
||||
icon: "😊".to_string(),
|
||||
unlocked_at: None,
|
||||
},
|
||||
AchievementId::QuestionMaster => Achievement {
|
||||
id: id.clone(),
|
||||
name: "Question Master".to_string(),
|
||||
description: "Asked 20 questions".to_string(),
|
||||
icon: "❓".to_string(),
|
||||
unlocked_at: None,
|
||||
},
|
||||
AchievementId::CapsLock => Achievement {
|
||||
id: id.clone(),
|
||||
name: "CAPS LOCK ENGAGED".to_string(),
|
||||
description: "SENT A MESSAGE IN ALL CAPS".to_string(),
|
||||
icon: "📢".to_string(),
|
||||
unlocked_at: None,
|
||||
},
|
||||
AchievementId::PleaseAndThankYou => Achievement {
|
||||
id: id.clone(),
|
||||
name: "Polite Programmer".to_string(),
|
||||
description: "Said please in a request".to_string(),
|
||||
icon: "🎩".to_string(),
|
||||
unlocked_at: None,
|
||||
},
|
||||
|
||||
// Git & Development
|
||||
AchievementId::GitGuru => Achievement {
|
||||
id: id.clone(),
|
||||
name: "Git Guru".to_string(),
|
||||
description: "Used git commands 10 times".to_string(),
|
||||
icon: "🌿".to_string(),
|
||||
unlocked_at: None,
|
||||
},
|
||||
AchievementId::TestWriter => Achievement {
|
||||
id: id.clone(),
|
||||
name: "Test Writer".to_string(),
|
||||
description: "Created test files".to_string(),
|
||||
icon: "🧪".to_string(),
|
||||
unlocked_at: None,
|
||||
},
|
||||
AchievementId::Debugger => Achievement {
|
||||
id: id.clone(),
|
||||
name: "Bug Squasher".to_string(),
|
||||
description: "Fixed bugs and errors".to_string(),
|
||||
icon: "🐛".to_string(),
|
||||
unlocked_at: None,
|
||||
},
|
||||
|
||||
// Tool Mastery
|
||||
AchievementId::BashMaster => Achievement {
|
||||
id: id.clone(),
|
||||
name: "Bash Master".to_string(),
|
||||
description: "Used Bash tool 50 times".to_string(),
|
||||
icon: "🐚".to_string(),
|
||||
unlocked_at: None,
|
||||
},
|
||||
AchievementId::FileExplorer => Achievement {
|
||||
id: id.clone(),
|
||||
name: "File Explorer".to_string(),
|
||||
description: "Read 100 files".to_string(),
|
||||
icon: "📂".to_string(),
|
||||
unlocked_at: None,
|
||||
},
|
||||
AchievementId::SearchExpert => Achievement {
|
||||
id: id.clone(),
|
||||
name: "Search Expert".to_string(),
|
||||
description: "Used Grep tool 50 times".to_string(),
|
||||
icon: "🔎".to_string(),
|
||||
unlocked_at: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Check achievements based on message content
|
||||
pub fn check_message_achievements(
|
||||
message: &str,
|
||||
progress: &mut AchievementProgress,
|
||||
) -> Vec<AchievementId> {
|
||||
let mut newly_unlocked = Vec::new();
|
||||
let message_lower = message.to_lowercase();
|
||||
|
||||
println!("Checking message achievements for: {}", message);
|
||||
|
||||
// Relationship & Greetings
|
||||
if message_lower.contains("good morning") && progress.unlock(AchievementId::GoodMorning) {
|
||||
newly_unlocked.push(AchievementId::GoodMorning);
|
||||
}
|
||||
if (message_lower.contains("good night") || message_lower.contains("goodnight"))
|
||||
&& progress.unlock(AchievementId::GoodNight) {
|
||||
newly_unlocked.push(AchievementId::GoodNight);
|
||||
}
|
||||
if (message_lower.contains("thank you") || message_lower.contains("thanks") || message_lower.contains("thx"))
|
||||
&& progress.unlock(AchievementId::ThankYou) {
|
||||
newly_unlocked.push(AchievementId::ThankYou);
|
||||
}
|
||||
if (message_lower.contains("love you") || message_lower.contains("ily"))
|
||||
&& progress.unlock(AchievementId::LoveYou) {
|
||||
newly_unlocked.push(AchievementId::LoveYou);
|
||||
}
|
||||
|
||||
// Personality & Fun
|
||||
if message.chars().any(|c| c as u32 >= 0x1F300) && progress.unlock(AchievementId::EmojiUser) {
|
||||
newly_unlocked.push(AchievementId::EmojiUser);
|
||||
}
|
||||
if message == message.to_uppercase() && message.len() > 5
|
||||
&& message.chars().any(|c| c.is_alphabetic())
|
||||
&& progress.unlock(AchievementId::CapsLock) {
|
||||
newly_unlocked.push(AchievementId::CapsLock);
|
||||
}
|
||||
if message_lower.contains("please") && progress.unlock(AchievementId::PleaseAndThankYou) {
|
||||
newly_unlocked.push(AchievementId::PleaseAndThankYou);
|
||||
}
|
||||
|
||||
// Git & Development patterns in messages
|
||||
if (message_lower.contains("fix") || message_lower.contains("bug") || message_lower.contains("error"))
|
||||
&& progress.unlock(AchievementId::Debugger) {
|
||||
newly_unlocked.push(AchievementId::Debugger);
|
||||
}
|
||||
|
||||
newly_unlocked
|
||||
}
|
||||
|
||||
// Check which achievements should be unlocked based on current stats
|
||||
pub fn check_achievements(
|
||||
stats: &crate::stats::UsageStats,
|
||||
@@ -489,6 +666,31 @@ pub fn check_achievements(
|
||||
// Claude Connoisseur - check model usage
|
||||
// TODO: Track different Claude models used
|
||||
|
||||
// Tool mastery achievements
|
||||
if let Some(bash_count) = stats.tools_usage.get("Bash") {
|
||||
if *bash_count >= 50 && progress.unlock(AchievementId::BashMaster) {
|
||||
newly_unlocked.push(AchievementId::BashMaster);
|
||||
}
|
||||
}
|
||||
if let Some(read_count) = stats.tools_usage.get("Read") {
|
||||
if *read_count >= 100 && progress.unlock(AchievementId::FileExplorer) {
|
||||
newly_unlocked.push(AchievementId::FileExplorer);
|
||||
}
|
||||
}
|
||||
if let Some(grep_count) = stats.tools_usage.get("Grep") {
|
||||
if *grep_count >= 50 && progress.unlock(AchievementId::SearchExpert) {
|
||||
newly_unlocked.push(AchievementId::SearchExpert);
|
||||
}
|
||||
}
|
||||
|
||||
// Git Guru - check git command usage in Bash
|
||||
if let Some(bash_count) = stats.tools_usage.get("Bash") {
|
||||
if *bash_count >= 10 && progress.unlock(AchievementId::GitGuru) {
|
||||
// TODO: More specific git command tracking
|
||||
newly_unlocked.push(AchievementId::GitGuru);
|
||||
}
|
||||
}
|
||||
|
||||
// Time-based achievements
|
||||
if let Some(session_start) = progress.session_start {
|
||||
let hour = session_start.hour();
|
||||
|
||||
@@ -91,7 +91,7 @@ impl WslBridge {
|
||||
}
|
||||
|
||||
pub async fn new_with_loaded_achievements(app: &tauri::AppHandle) -> Self {
|
||||
let mut bridge = Self::new();
|
||||
let bridge = Self::new();
|
||||
|
||||
// Load saved achievements into the stats
|
||||
let achievements = crate::achievements::load_achievements(app).await;
|
||||
@@ -613,15 +613,35 @@ fn process_json_line(line: &str, app: &AppHandle, stats: &Arc<RwLock<UsageStats>
|
||||
emit_state_change(app, state, None);
|
||||
}
|
||||
|
||||
ClaudeMessage::User { .. } => {
|
||||
ClaudeMessage::User { message } => {
|
||||
// Increment message count for user messages
|
||||
stats.write().increment_messages();
|
||||
|
||||
// Extract text content from the message
|
||||
let message_text = message.content.iter()
|
||||
.filter_map(|block| match block {
|
||||
crate::types::ContentBlock::Text { text } => Some(text.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join(" ");
|
||||
|
||||
// Check achievements after user message
|
||||
let newly_unlocked = {
|
||||
let mut stats_guard = stats.write();
|
||||
println!("User sent message, checking achievements...");
|
||||
stats_guard.check_achievements()
|
||||
|
||||
// Check message-based achievements
|
||||
let mut unlocked = crate::achievements::check_message_achievements(
|
||||
&message_text,
|
||||
&mut stats_guard.achievements,
|
||||
);
|
||||
|
||||
// Check stats-based achievements
|
||||
let stats_unlocked = stats_guard.check_achievements();
|
||||
unlocked.extend(stats_unlocked);
|
||||
|
||||
unlocked
|
||||
};
|
||||
|
||||
// Emit achievement events for any newly unlocked achievements
|
||||
|
||||
@@ -283,6 +283,154 @@ const achievementDefinitions: Record<AchievementId, Omit<Achievement, 'unlocked'
|
||||
rarity: 'epic',
|
||||
maxProgress: 10000,
|
||||
},
|
||||
|
||||
// Relationship & Greetings
|
||||
GoodMorning: {
|
||||
id: 'GoodMorning',
|
||||
name: 'Good Morning!',
|
||||
description: 'Greeted Hikari with a good morning',
|
||||
icon: '🌅',
|
||||
rarity: 'common',
|
||||
maxProgress: 1,
|
||||
},
|
||||
GoodNight: {
|
||||
id: 'GoodNight',
|
||||
name: 'Sweet Dreams',
|
||||
description: 'Said good night to Hikari',
|
||||
icon: '🌙',
|
||||
rarity: 'common',
|
||||
maxProgress: 1,
|
||||
},
|
||||
ThankYou: {
|
||||
id: 'ThankYou',
|
||||
name: 'Grateful Heart',
|
||||
description: 'Thanked Hikari for her help',
|
||||
icon: '🙏',
|
||||
rarity: 'common',
|
||||
maxProgress: 1,
|
||||
},
|
||||
LoveYou: {
|
||||
id: 'LoveYou',
|
||||
name: 'Heartfelt',
|
||||
description: 'Expressed love to Hikari',
|
||||
icon: '💕',
|
||||
rarity: 'rare',
|
||||
maxProgress: 1,
|
||||
},
|
||||
|
||||
// Personality & Fun
|
||||
EmojiUser: {
|
||||
id: 'EmojiUser',
|
||||
name: 'Emoji Master',
|
||||
description: 'Used 20+ emojis in messages',
|
||||
icon: '😄',
|
||||
rarity: 'common',
|
||||
maxProgress: 20,
|
||||
},
|
||||
CapsLock: {
|
||||
id: 'CapsLock',
|
||||
name: 'CAPS LOCK',
|
||||
description: 'SENT A MESSAGE IN ALL CAPS',
|
||||
icon: '🔊',
|
||||
rarity: 'common',
|
||||
maxProgress: 1,
|
||||
},
|
||||
QuestionMaster: {
|
||||
id: 'QuestionMaster',
|
||||
name: 'Question Master',
|
||||
description: 'Asked 50 questions',
|
||||
icon: '❓',
|
||||
rarity: 'common',
|
||||
maxProgress: 50,
|
||||
},
|
||||
PleaseAndThankYou: {
|
||||
id: 'PleaseAndThankYou',
|
||||
name: 'Polite Programmer',
|
||||
description: 'Always says please and thank you',
|
||||
icon: '🎩',
|
||||
rarity: 'common',
|
||||
maxProgress: 10,
|
||||
},
|
||||
|
||||
// Git & Development
|
||||
CommitMaster: {
|
||||
id: 'CommitMaster',
|
||||
name: 'Commit Master',
|
||||
description: 'Made 100 commits through Hikari',
|
||||
icon: '📝',
|
||||
rarity: 'rare',
|
||||
maxProgress: 100,
|
||||
},
|
||||
PRO: {
|
||||
id: 'PRO',
|
||||
name: 'PRO',
|
||||
description: 'Created 10 pull requests',
|
||||
icon: '🔀',
|
||||
rarity: 'rare',
|
||||
maxProgress: 10,
|
||||
},
|
||||
Reviewer: {
|
||||
id: 'Reviewer',
|
||||
name: 'Code Reviewer',
|
||||
description: 'Reviewed 10 pull requests',
|
||||
icon: '👀',
|
||||
rarity: 'rare',
|
||||
maxProgress: 10,
|
||||
},
|
||||
IssueTracker: {
|
||||
id: 'IssueTracker',
|
||||
name: 'Issue Tracker',
|
||||
description: 'Created 25 issues',
|
||||
icon: '🎯',
|
||||
rarity: 'rare',
|
||||
maxProgress: 25,
|
||||
},
|
||||
GitGuru: {
|
||||
id: 'GitGuru',
|
||||
name: 'Git Guru',
|
||||
description: 'Mastered git operations',
|
||||
icon: '🌲',
|
||||
rarity: 'epic',
|
||||
},
|
||||
|
||||
// Tool Mastery
|
||||
BashMaster: {
|
||||
id: 'BashMaster',
|
||||
name: 'Bash Master',
|
||||
description: 'Used bash commands 100 times',
|
||||
icon: '💻',
|
||||
rarity: 'rare',
|
||||
maxProgress: 100,
|
||||
},
|
||||
FileExplorer: {
|
||||
id: 'FileExplorer',
|
||||
name: 'File Explorer',
|
||||
description: 'Explored files 100 times',
|
||||
icon: '📂',
|
||||
rarity: 'common',
|
||||
maxProgress: 100,
|
||||
},
|
||||
SearchExpert: {
|
||||
id: 'SearchExpert',
|
||||
name: 'Search Expert',
|
||||
description: 'Mastered advanced search queries',
|
||||
icon: '🔎',
|
||||
rarity: 'rare',
|
||||
},
|
||||
AgentCommander: {
|
||||
id: 'AgentCommander',
|
||||
name: 'Agent Commander',
|
||||
description: 'Used task agents effectively',
|
||||
icon: '🤖',
|
||||
rarity: 'rare',
|
||||
},
|
||||
MCPMaster: {
|
||||
id: 'MCPMaster',
|
||||
name: 'MCP Master',
|
||||
description: 'Mastered MCP tool usage',
|
||||
icon: '🛠️',
|
||||
rarity: 'epic',
|
||||
},
|
||||
};
|
||||
|
||||
// Initialize all achievements as locked
|
||||
@@ -447,6 +595,26 @@ export const achievementCategories = [
|
||||
description: 'Your coding session achievements',
|
||||
ids: ['QuickSession', 'FocusedWork', 'DeepDive', 'MarathonSession', 'MarathonCoder'] as AchievementId[],
|
||||
},
|
||||
{
|
||||
name: 'Relationship & Greetings',
|
||||
description: 'Our special moments together',
|
||||
ids: ['GoodMorning', 'GoodNight', 'ThankYou', 'LoveYou'] as AchievementId[],
|
||||
},
|
||||
{
|
||||
name: 'Personality & Fun',
|
||||
description: 'Express yourself!',
|
||||
ids: ['EmojiUser', 'CapsLock', 'QuestionMaster', 'PleaseAndThankYou'] as AchievementId[],
|
||||
},
|
||||
{
|
||||
name: 'Git & Development',
|
||||
description: 'Version control mastery',
|
||||
ids: ['CommitMaster', 'PRO', 'Reviewer', 'IssueTracker', 'GitGuru'] as AchievementId[],
|
||||
},
|
||||
{
|
||||
name: 'Tool Mastery',
|
||||
description: 'Master of all tools',
|
||||
ids: ['BashMaster', 'FileExplorer', 'SearchExpert', 'AgentCommander', 'MCPMaster'] as AchievementId[],
|
||||
},
|
||||
{
|
||||
name: 'Special',
|
||||
description: 'Unique accomplishments',
|
||||
|
||||
@@ -50,7 +50,29 @@ export type AchievementId =
|
||||
| 'Polyglot' // 5+ languages in one session
|
||||
| 'SpeedCoder' // 10 code blocks in 10 minutes
|
||||
| 'ClaudeConnoisseur' // Used all Claude models
|
||||
| 'MarathonCoder';
|
||||
| 'MarathonCoder' // 10k tokens in one session
|
||||
// Relationship & Greetings
|
||||
| 'GoodMorning' // Said good morning
|
||||
| 'GoodNight' // Said good night
|
||||
| 'ThankYou' // Said thank you
|
||||
| 'LoveYou' // Said love you
|
||||
// Personality & Fun
|
||||
| 'EmojiUser' // Used 20+ emojis
|
||||
| 'CapsLock' // ALL CAPS MESSAGE
|
||||
| 'QuestionMaster' // Asked 50 questions
|
||||
| 'PleaseAndThankYou' // Polite user
|
||||
// Git & Development
|
||||
| 'CommitMaster' // 100 commits
|
||||
| 'PRO' // Created 10 PRs
|
||||
| 'Reviewer' // Reviewed 10 PRs
|
||||
| 'IssueTracker' // Created 25 issues
|
||||
| 'GitGuru' // Used git commands
|
||||
// Tool Mastery
|
||||
| 'BashMaster' // Used bash 100 times
|
||||
| 'FileExplorer' // Searched files 100 times
|
||||
| 'SearchExpert' // Advanced searches
|
||||
| 'AgentCommander' // Used task agents
|
||||
| 'MCPMaster'; // Used MCP tools
|
||||
|
||||
export interface Achievement {
|
||||
id: AchievementId;
|
||||
|
||||
Reference in New Issue
Block a user