Give every achievement its own pixel-art badge

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-06 10:20:41 +01:00
1 parent 368a338ccf
commit fdce6c282b
5 files changed
+976 -33

No files matched your search

+41 -31
View File
@@ -15,40 +15,40 @@ pub const STAT_NAMES: [&str; k::COUNTERS] = [
"heroes", "bosses", "lost", "dug", "wood", "walls", "rooms", "spells", "slaps", "traps", "towers", "drowned", "burnt", "siege", "captured", "gold", "drawbridge",
];
// tiered achievements: id (= counter), thresholds, icon cell
// tiered achievements: id (= counter), thresholds, badge (badges.rs)
pub const TIERS: [(&str, &[f64], u32); 20] = [
("heroes", &[1.0, 50.0, 250.0, 1000.0], crate::gfx::I_ARROW),
("bosses", &[1.0, 5.0, 20.0], crate::gfx::I_RUNE),
("dug", &[100.0, 1000.0, 10000.0], crate::gfx::I_PICK),
("gold", &[10000.0, 100000.0, 1000000.0], crate::gfx::I_SELL),
("wood", &[50.0, 500.0, 2000.0], crate::gfx::I_BRIDGE),
("walls", &[10.0, 100.0], crate::gfx::I_WALL),
("rooms", &[50.0, 500.0, 2000.0], crate::gfx::I_STEEL),
("spells", &[10.0, 100.0, 500.0], crate::gfx::I_BOLT),
("slaps", &[10.0, 100.0, 1000.0], crate::gfx::I_HAND),
("traps", &[5.0, 50.0, 200.0], crate::gfx::I_TRAPS),
("towers", &[5.0, 50.0], crate::gfx::I_CANNON),
("drowned", &[1.0, 25.0, 100.0], crate::gfx::I_FREEZE),
("burnt", &[5.0, 50.0], crate::gfx::I_DRAWBRIDGE),
("siege", &[1.0, 10.0], crate::gfx::I_CATAPULT),
("captured", &[1.0, 25.0, 100.0], crate::gfx::I_SUMMON),
("drawbridge", &[1.0, 50.0], crate::gfx::I_DRAWBRIDGE),
("wins", &[1.0, 10.0, 50.0], crate::gfx::I_FLAG),
("missions", &[1.0, 10.0, 30.0], crate::gfx::I_MAGIC),
("coop", &[1.0, 10.0, 20.0], crate::gfx::I_HEAL),
("minutes", &[60.0, 600.0, 3000.0], crate::gfx::I_SPELLS),
("heroes", &[1.0, 50.0, 250.0, 1000.0], crate::badges::HEROES),
("bosses", &[1.0, 5.0, 20.0], crate::badges::BOSSES),
("dug", &[100.0, 1000.0, 10000.0], crate::badges::DUG),
("gold", &[10000.0, 100000.0, 1000000.0], crate::badges::GOLD),
("wood", &[50.0, 500.0, 2000.0], crate::badges::WOOD),
("walls", &[10.0, 100.0], crate::badges::WALLS),
("rooms", &[50.0, 500.0, 2000.0], crate::badges::ROOMS),
("spells", &[10.0, 100.0, 500.0], crate::badges::SPELLS),
("slaps", &[10.0, 100.0, 1000.0], crate::badges::SLAPS),
("traps", &[5.0, 50.0, 200.0], crate::badges::TRAPS),
("towers", &[5.0, 50.0], crate::badges::TOWERS),
("drowned", &[1.0, 25.0, 100.0], crate::badges::DROWNED),
("burnt", &[5.0, 50.0], crate::badges::BURNT),
("siege", &[1.0, 10.0], crate::badges::SIEGE),
("captured", &[1.0, 25.0, 100.0], crate::badges::CAPTURED),
("drawbridge", &[1.0, 50.0], crate::badges::DRAWBRIDGE),
("wins", &[1.0, 10.0, 50.0], crate::badges::WINS),
("missions", &[1.0, 10.0, 30.0], crate::badges::MISSIONS),
("coop", &[1.0, 10.0, 20.0], crate::badges::COOP),
("minutes", &[60.0, 600.0, 3000.0], crate::badges::MINUTES),
];
// special achievements: id, hidden until unlocked, icon cell
// special achievements: id, hidden until unlocked, badge (badges.rs)
pub const SPECIAL: [(&str, bool, u32); 8] = [
("flawless", false, crate::gfx::I_HEAL),
("speedrun", false, crate::gfx::I_BOLT),
("campaign", false, crate::gfx::I_RUNE),
("surface", false, crate::gfx::I_WALL),
("defeat", true, crate::gfx::I_SELL),
("legend", false, crate::gfx::I_ARROW),
("wyrm", true, crate::gfx::I_SUMMON),
("fullhand", true, crate::gfx::I_HAND),
("flawless", false, crate::badges::FLAWLESS),
("speedrun", false, crate::badges::SPEEDRUN),
("campaign", false, crate::badges::CAMPAIGN),
("surface", false, crate::badges::SURFACE),
("defeat", true, crate::badges::DEFEAT),
("legend", false, crate::badges::LEGEND),
("wyrm", true, crate::badges::WYRM),
("fullhand", true, crate::badges::FULLHAND),
];
// number of achievements in all
@@ -244,7 +244,7 @@ pub fn fmt_count(v: f64) -> String {
out
}
// every achievement in display order: (id, hidden, icon, tier 0..)
// every achievement in display order: (id, hidden, badge, tier 0..)
pub fn all() -> Vec<(String, bool, u32, usize)> {
let mut v = Vec::new();
for (id, steps, icon) in TIERS.iter() {
@@ -268,6 +268,16 @@ mod tests {
assert_eq!(all().len(), count());
}
#[test]
fn every_achievement_has_its_own_badge() {
let mut seen = std::collections::BTreeSet::new();
for b in TIERS.iter().map(|t| t.2).chain(SPECIAL.iter().map(|s| s.2)) {
assert!(b < crate::badges::COUNT, "badge {} out of range", b);
assert!(seen.insert(b), "badge {} used twice", b);
}
assert_eq!(seen.len() as u32, crate::badges::COUNT);
}
#[test]
fn the_tracker_counts_a_game_and_unlocks() {
let mut g = Game::new(3, 64, 64);