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
|
||||
|
||||
Reference in New Issue
Block a user