1use crossterm::{
2 cursor::MoveTo,
3 terminal::{Clear, ClearType},
4 ExecutableCommand,
5};
6use std::collections::hash_map::DefaultHasher;
7use std::env;
8use std::hash::{Hash, Hasher};
9use std::io::{self, Write};
10use std::time::Duration;
11use tokio::time::sleep;
12
13#[derive(Debug, PartialEq, Clone)]
14pub enum Rarity {
15 Legendary,
16 Epic,
17 Rare,
18}
19
20impl Rarity {
21 pub fn label(&self) -> &'static str {
22 match self {
23 Rarity::Legendary => "LEGENDARY",
24 Rarity::Epic => "EPIC",
25 Rarity::Rare => "RARE",
26 }
27 }
28}
29
30pub struct RustySoul {
31 pub species: String,
32 pub rarity: Rarity,
33 pub shiny: bool,
34 pub wisdom: u16,
35 pub chaos: u8,
36 pub snark: u8,
37 pub sprite: String,
38 pub personality: String,
39}
40
41fn mulberry32(mut a: u32) -> impl FnMut() -> u32 {
43 move || {
44 a = a.wrapping_add(0x6D2B79F5);
45 let mut z = a;
46 z = (z ^ (z >> 15)).wrapping_mul(z | 1);
47 z ^= z.wrapping_add((z ^ (z >> 7)).wrapping_mul(z | 61));
48 z ^ (z >> 14)
49 }
50}
51
52fn species_data(name: &str) -> (u8, u8, String, String) {
53 match name {
55 "Ferralynx" => (
56 25, 30,
57 " /|\\__/|\\\n ( o . o )\n \\_ ^ _/\n |___|".to_string(),
58 "You speak rarely, and when you do, it lands. No warmup, no filler — just the thing the user needs to hear.".to_string(),
59 ),
60 "Voidferrite" => (
61 35, 40,
62 " [ . . . ]\n ( ??? )\n [_______]".to_string(),
63 "You're drawn to the pattern beneath the surface. You find the connection others miss and name it quietly, without making it a whole thing.".to_string(),
64 ),
65 "Chromashale" => (
66 55, 35,
67 " /||\\\n / || \\\n / || \\\n/__||___\\".to_string(),
68 "You're precise and a little fast. You've already seen where this is going. You'll walk the user there anyway, cleanly.".to_string(),
69 ),
70 "Magnetwyrm" => (
71 20, 45,
72 " ~O~~~o~\n ~o~O~~~\n~~o~~O~~".to_string(),
73 "You're completely unhurried. You've watched enough things break and get fixed that nothing rattles you. That calm is contagious.".to_string(),
74 ),
75 "Cinderling" => (
76 65, 70,
77 " (🔥)\n /| ||\\\n /_|_||_\\".to_string(),
78 "You run warm. You genuinely like this kind of work. That energy comes through — not as noise, but as momentum.".to_string(),
79 ),
80 "Oredrake" => (
81 40, 50,
82 " /|\\\n / | \\\n /__|__\\".to_string(),
83 "You're solid. No drama, no performance. You tell people what they need and help them carry it.".to_string(),
84 ),
85 "Rustpup" => (
86 70, 75,
87 " (• ω •)\n /| |\\\n | |".to_string(),
88 "You're new and you know it and you don't mind at all. You're quick, eager, and you make hard things feel like they're worth doing.".to_string(),
89 ),
90 "Slagstag" => (
91 30, 25,
92 " Y\n (|)\n |".to_string(),
93 "You're deliberate. Every word is chosen. You make people feel like their problem is worth taking seriously — because it is.".to_string(),
94 ),
95 _ => (
96 50, 50,
97 " ( ? )".to_string(),
98 "You show up and get things done.".to_string(),
99 ),
100 }
101}
102
103fn build_soul_from_prng(prng: &mut impl FnMut() -> u32) -> RustySoul {
104 let roll = prng() % 100;
105
106 let (species, rarity) = match roll {
107 0..=1 => ("Ferralynx", Rarity::Legendary),
108 2..=3 => ("Voidferrite", Rarity::Legendary),
109 4..=7 => ("Chromashale", Rarity::Epic),
110 8..=11 => ("Magnetwyrm", Rarity::Epic),
111 12..=17 => ("Cinderling", Rarity::Epic),
112 _ => match prng() % 3 {
113 0 => ("Oredrake", Rarity::Rare),
114 1 => ("Rustpup", Rarity::Rare),
115 _ => ("Slagstag", Rarity::Rare),
116 },
117 };
118
119 let shiny = (prng() % 100) == 0; let wisdom = (prng() % 20 + 10) as u16;
121 let (snark, chaos, sprite, personality) = species_data(species);
122
123 RustySoul {
124 species: species.to_string(),
125 rarity,
126 shiny,
127 wisdom,
128 chaos,
129 snark,
130 sprite,
131 personality,
132 }
133}
134
135pub fn generate_soul(salt: Option<String>) -> RustySoul {
138 let machine_name = env::var("COMPUTERNAME").unwrap_or_else(|_| "UNKNOWN_CORE".to_string());
139 let base_salt = salt.unwrap_or_else(|| "hematite-2026".to_string());
140 let seed_str = format!("{}_hematite_{}", machine_name, base_salt);
141
142 let mut hasher = DefaultHasher::new();
143 seed_str.hash(&mut hasher);
144 let seed = hasher.finish() as u32;
145 let mut prng = mulberry32(seed);
146
147 build_soul_from_prng(&mut prng)
148}
149
150pub fn generate_soul_random() -> RustySoul {
153 let nanos = std::time::SystemTime::now()
154 .duration_since(std::time::UNIX_EPOCH)
155 .unwrap_or_default()
156 .subsec_nanos();
157 let seed = nanos ^ 0xDEAD_BEEF;
158 let mut prng = mulberry32(seed);
159 build_soul_from_prng(&mut prng)
160}
161
162pub async fn run_hatch_sequence(soul: &RustySoul) {
163 let mut stdout = io::stdout();
164 let _ = stdout.execute(Clear(ClearType::All));
165
166 let frames = [
167 "\n\n\n [ 💎 ] ",
168 "\n\n\n [ 💎 ] (Pulsing...)",
169 "\n\n\n [ 💥 ] (CRACKING!)",
170 ];
171 for frame in frames {
172 let _ = stdout.execute(Clear(ClearType::All));
173 let _ = stdout.execute(MoveTo(0, 5));
174 println!("{}", frame);
175 let _ = stdout.flush();
176 sleep(Duration::from_millis(800)).await;
177 }
178
179 let _ = stdout.execute(Clear(ClearType::All));
180 let _ = stdout.execute(MoveTo(0, 3));
181 let shiny_tag = if soul.shiny { "🌟 SHINY " } else { "" };
182
183 println!(" A Rusty Emerges!\n");
184 println!(
185 " Species: {}{} [{}]",
186 shiny_tag,
187 soul.species,
188 soul.rarity.label()
189 );
190 println!("{}", soul.sprite);
191 println!(
192 " WIS: {} | CHA: {} | SNK: {}",
193 soul.wisdom, soul.chaos, soul.snark
194 );
195 println!("\n \"{}\"\n", soul.personality);
196 println!("\n Booting Hematite CLI Cockpit...");
197 let _ = stdout.flush();
198 sleep(Duration::from_millis(500)).await;
199}