Feature 15: Achievements & Collections
Overview
Long-term completionist goals: achievements across all game systems (combat, crafting, social, exploration, PVP, collection), the bestiary (creature catalog), item catalog, recipe collection, titles, and leaderboards. Achievements grant points, titles, and cosmetic rewards.
Dependencies
- Feature 07 (Quests & Runs) — combat and exploration achievements
- Feature 08 (Crafting & Gathering) — crafting achievements
- Feature 11 (PVP) — PVP achievements and leaderboards
- Feature 10 (Guilds) — social achievements
Technical Tasks
1. Static Game Data — Achievements
- Create
data/achievements/:combat.toml: First Blood, Dungeon Crawler (all dungeons), Deadly Survivor (complete Deadly), etc.progression.toml: level milestones, Paragon milestones, full feat selectioncrafting.toml: First Craft, Master Blacksmith (skill 100), Grand Master (all 100), Critical Crafter (10 crits)social.toml: Guilded (join guild), Raid Ready (first raid), Social Butterfly (10 friends)exploration.toml: Explorer (all regions), Lore Hunter, Cartographerpvp.toml: First Duel, Gladiator (Gold rating), Legend (Diamond)collection.toml: Bestiary Complete, Fashionista (25 cosmetics), Title Collector (10 titles)- Per achievement: id, name, description, category, points, reward (title?, portrait_frame?, gold?, materials?), criteria (structured conditions)
2. Achievement Tracking Types (crates/types)
- Create
src/achievement.rs:AchievementCriteriaenum:KillCount { creature_id: Option<String>, count: u32 }— kill N creatures (or specific type)DungeonComplete { dungeon_id: Option<String>, difficulty: Option<Difficulty> }CraftCount { profession: Option<String>, count: u32 }ReachLevel { level: u16 }ReachProficiency { weapon_type: String, level: u16 }ReachReputation { faction_id: String, tier: ReputationTier }PvpRating { bracket: String, rating: i32 }FriendCount { count: u32 }GuildAction { action: String }— join, create, etc.CollectionCount { collection: String, count: u32 }
Achievement: id, name, description, category, points, reward, criteria
3. Database Migration
- Create migration
0014_create_achievements.sql:character_achievements: character_id, achievement_id, earned_at — PK: character_id + achievement_idcharacter_bestiary: character_id, creature_id, kills, first_killed — PK: character_id + creature_idcharacter_titles: character_id, title_id, earned_at, is_active — PK: character_id + title_id
4. Achievement Engine (crates/game)
- Create
src/achievements.rs:check_achievements(character: &Character, event: &GameEvent, state: &AchievementState) -> Vec<String>:- Given a game event (kill, craft, level up, etc.), check all relevant achievements
- Return IDs of newly earned achievements
GameEventenum:CreatureKilled { creature_id: String }RunCompleted { quest_id: String, difficulty: Difficulty }ItemCrafted { profession: String }LevelReached { level: u16 }ProficiencyReached { weapon_type: String, level: u16 }ReputationChanged { faction_id: String, new_rep: i32 }PvpMatchCompleted { bracket: String, new_rating: i32 }FriendAdded { total_friends: u32 }GuildJoined/GuildCreated
AchievementState: set of already-earned achievement IDs (to avoid re-checking)
5. Bestiary Tracking
- Create
src/bestiary.rs:record_kill(character_id: Uuid, creature_id: &str):- Increment kill count
- If first kill, record timestamp
get_bestiary_completion(character_id: Uuid) -> BestiaryProgress:- Total creatures encountered / total creatures in game
- Per-region completion percentage
6. Queries (crates/db)
- Create
src/queries/achievements.rs:get_earned_achievements(pool, character_id) -> Vec<CharacterAchievement>grant_achievement(pool, character_id, achievement_id)get_achievement_points(pool, character_id) -> u32get_bestiary(pool, character_id) -> Vec<BestiaryEntry>upsert_bestiary_entry(pool, character_id, creature_id, kills_delta)get_active_title(pool, character_id) -> Option<String>set_active_title(pool, character_id, title_id)get_earned_titles(pool, character_id) -> Vec<Title>
7. Integrate Achievement Checks into Workers
- After every significant game event, call
check_achievements:- Simulation worker: after each encounter (CreatureKilled), after run (RunCompleted, LevelReached)
- Crafting worker: after craft (ItemCrafted)
- PVP worker: after match (PvpMatchCompleted)
- Reputation updates: after rep change (ReputationChanged)
- Social actions: on friend add, guild join/create
- For each newly earned achievement:
- Grant achievement record
- Grant reward (title, gold, materials)
- Create notification (AchievementEarned)
- Update bestiary after combat encounters (record creature kills)
8. Leaderboard System
- Redis sorted sets for leaderboards (already defined in tech architecture):
leaderboard:pvp:1v1:season:{n}— ratingleaderboard:pvp:3v3:season:{n}— ratingleaderboard:achievements— total pointsleaderboard:wealth— gold
- Update leaderboards when relevant data changes:
- PVP: after match resolution
- Achievements: after achievement granted
- Wealth: after gold change (debounced — update every 5 minutes via scheduler)
9. API Routes (crates/api)
- Create
src/routes/achievements.rs:GET /api/characters/:id/achievements:- Return earned achievements with timestamps + total points
- Include unearned achievements as “locked” entries with descriptions (progression visibility)
GET /api/characters/:id/bestiary:- Return creature entries: name, kills, first killed, completion percentage
GET /api/characters/:id/titles:- Return earned titles, active title
POST /api/characters/:id/titles/set:- Body:
{ title_id } - Set active title (displayed on profile)
- Body:
GET /api/leaderboards/:type:- Query params: page, bracket (for PVP)
- Return top 100 + requesting player’s rank
GET /api/characters/:id/showcase:- Return selected 5 achievements for profile display
PUT /api/characters/:id/showcase:- Body:
{ achievement_ids: [5 max] }
- Body:
10. Client — Achievements UI
- Create
routes/(game)/achievements/+page.svelte:- Category tabs: Combat, Progression, Crafting, Social, Exploration, PVP, Collection
- Achievement cards: name, description, progress bar (if trackable), earned/locked indicator, points, reward preview
- Total achievement points prominently displayed
- Create
routes/(game)/bestiary/+page.svelte:- Grid of creature entries (unlocked show art + stats, locked show silhouette)
- Regional filters
- Completion percentage
- Create
routes/(game)/leaderboards/+page.svelte:- Leaderboard tabs: PVP, Achievements, Wealth, Dungeon Speed, Weekly
- Top 100 table with rank, name, score
- “Your Rank” indicator
- Create
routes/(game)/profile/+page.svelte:- Character card: name, level, class, active title
- Achievement showcase (5 selected)
- Key stats: total achievements, bestiary %, PVP rating
Tests
Unit Tests
check_achievements: CreatureKilled event triggers “First Blood” when first killcheck_achievements: doesn’t re-trigger already-earned achievementscheck_achievements: LevelReached(10) triggers level 10 achievementcheck_achievements: multiple achievements can trigger from one eventrecord_kill: increments count, first kill sets timestampget_bestiary_completion: correct percentage calculation
Integration Tests
- Run completion triggers relevant combat achievements
- Achievement grant creates notification
- Achievement grant adds points to leaderboard
GET /api/characters/:id/achievementsreturns earned + locked achievementsGET /api/characters/:id/bestiaryreturns entries after combatGET /api/leaderboards/achievementsreturns sorted by pointsPOST /api/characters/:id/titles/setchanges active titlePUT /api/characters/:id/showcasesaves 5 achievement selections- Bestiary entry created after first encounter with creature
- Kill count increments across multiple runs