1use super::Rng;
4use super::history::Civilization;
5use super::mythology::Myth;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum ArtifactType { Weapon, Armor, Jewelry, Tome, Relic, Instrument, Tool, Crown, Staff, Amulet }
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum ArtifactRarity { Common, Uncommon, Rare, Legendary, Mythic }
12
13#[derive(Debug, Clone)]
14pub struct Artifact {
15 pub id: u32,
16 pub name: String,
17 pub artifact_type: ArtifactType,
18 pub rarity: ArtifactRarity,
19 pub description: String,
20 pub origin_civ: u32,
21 pub creation_year: i32,
22 pub creator_name: String,
23 pub related_myth: Option<u32>,
24 pub power_level: f32,
25 pub properties: Vec<String>,
26}
27
28pub fn generate(civs: &[Civilization], myths: &[Myth], rng: &mut Rng) -> Vec<Artifact> {
29 let mut artifacts = Vec::new();
30 let mut next_id = 0u32;
31
32 for civ in civs {
33 let num = (civ.culture_score * 5.0) as usize + 1;
34 for _ in 0..num {
35 let atype = random_type(rng);
36 let rarity = if rng.coin(0.05) { ArtifactRarity::Mythic }
37 else if rng.coin(0.1) { ArtifactRarity::Legendary }
38 else if rng.coin(0.2) { ArtifactRarity::Rare }
39 else if rng.coin(0.3) { ArtifactRarity::Uncommon }
40 else { ArtifactRarity::Common };
41
42 let related_myth = myths.iter()
43 .filter(|m| m.source_civ == civ.id)
44 .next()
45 .map(|m| m.id);
46
47 let (name, desc, props) = generate_artifact_details(atype, rarity, &civ.name, rng);
48
49 artifacts.push(Artifact {
50 id: next_id,
51 name, artifact_type: atype, rarity, description: desc,
52 origin_civ: civ.id,
53 creation_year: civ.founding_year + rng.range_u32(0, 1000) as i32,
54 creator_name: format!("{}smith", &civ.name[..civ.name.len().min(4)]),
55 related_myth,
56 power_level: rarity_power(rarity) * rng.range_f32(0.8, 1.2),
57 properties: props,
58 });
59 next_id += 1;
60 }
61 }
62 artifacts
63}
64
65fn random_type(rng: &mut Rng) -> ArtifactType {
66 match rng.range_u32(0, 10) {
67 0 => ArtifactType::Weapon, 1 => ArtifactType::Armor, 2 => ArtifactType::Jewelry,
68 3 => ArtifactType::Tome, 4 => ArtifactType::Relic, 5 => ArtifactType::Instrument,
69 6 => ArtifactType::Tool, 7 => ArtifactType::Crown, 8 => ArtifactType::Staff,
70 _ => ArtifactType::Amulet,
71 }
72}
73
74fn rarity_power(r: ArtifactRarity) -> f32 {
75 match r {
76 ArtifactRarity::Common => 1.0, ArtifactRarity::Uncommon => 2.0,
77 ArtifactRarity::Rare => 4.0, ArtifactRarity::Legendary => 8.0, ArtifactRarity::Mythic => 16.0,
78 }
79}
80
81fn generate_artifact_details(atype: ArtifactType, rarity: ArtifactRarity, civ_name: &str, rng: &mut Rng) -> (String, String, Vec<String>) {
82 let prefixes = ["Shadow", "Storm", "Void", "Star", "Moon", "Sun", "Blood", "Soul", "Dream", "Fate"];
83 let prefix = prefixes[rng.next_u64() as usize % prefixes.len()];
84
85 let type_name = match atype {
86 ArtifactType::Weapon => "Blade", ArtifactType::Armor => "Shield",
87 ArtifactType::Jewelry => "Ring", ArtifactType::Tome => "Codex",
88 ArtifactType::Relic => "Fragment", ArtifactType::Instrument => "Horn",
89 ArtifactType::Tool => "Compass", ArtifactType::Crown => "Crown",
90 ArtifactType::Staff => "Staff", ArtifactType::Amulet => "Amulet",
91 };
92
93 let name = format!("{}{} of {}", prefix, type_name, civ_name);
94 let desc = format!("A {} {} forged in the {} tradition.", rarity_adj(rarity), type_name.to_lowercase(), civ_name);
95 let props = match rarity {
96 ArtifactRarity::Mythic => vec!["Reality-warping".to_string(), "Sentient".to_string(), "Indestructible".to_string()],
97 ArtifactRarity::Legendary => vec!["Elemental mastery".to_string(), "Soul-bound".to_string()],
98 ArtifactRarity::Rare => vec!["Enhanced".to_string(), "Self-repairing".to_string()],
99 ArtifactRarity::Uncommon => vec!["Durable".to_string()],
100 ArtifactRarity::Common => vec![],
101 };
102 (name, desc, props)
103}
104
105fn rarity_adj(r: ArtifactRarity) -> &'static str {
106 match r {
107 ArtifactRarity::Common => "simple", ArtifactRarity::Uncommon => "finely crafted",
108 ArtifactRarity::Rare => "exquisite", ArtifactRarity::Legendary => "legendary",
109 ArtifactRarity::Mythic => "mythic",
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 #[test]
117 fn test_generate_artifacts() {
118 let mut rng = Rng::new(42);
119 let civs = vec![Civilization {
120 id: 0, name: "TestCiv".to_string(), founding_year: -1000, collapse_year: None,
121 capital_settlement: 0, settlements: vec![0], population: 10000,
122 technology_level: 0.5, military_strength: 0.3, culture_score: 0.6,
123 trade_score: 0.3, government: super::super::history::GovernmentType::Monarchy,
124 religion: super::super::history::ReligionType::Polytheism,
125 relations: Vec::new(), historical_events: Vec::new(), traits: Vec::new(),
126 }];
127 let artifacts = generate(&civs, &[], &mut rng);
128 assert!(!artifacts.is_empty());
129 }
130}