Skip to main content

proof_engine/narrative/
lore.rs

1//! Lore generation — create histories, myths, and cultural artifacts from simulation data.
2
3use crate::worldgen::Rng;
4use crate::worldgen::history::Civilization;
5
6/// A lore entry.
7#[derive(Debug, Clone)]
8pub struct LoreEntry {
9    pub title: String,
10    pub category: LoreCategory,
11    pub text: String,
12    pub source_civ: Option<u32>,
13    pub reliability: f32,
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum LoreCategory { History, Legend, Rumor, Scripture, Chronicle, Folklore, Science, Forbidden }
18
19/// Generate lore entries from civilization data.
20pub fn generate_lore(civs: &[Civilization], rng: &mut Rng) -> Vec<LoreEntry> {
21    let mut entries = Vec::new();
22
23    for civ in civs {
24        // Historical chronicle
25        entries.push(LoreEntry {
26            title: format!("Chronicles of {}", civ.name),
27            category: LoreCategory::Chronicle,
28            text: format!(
29                "The {} civilization was founded in the year {}. \
30                 Under {} rule, they grew to number {} souls. \
31                 Their legacy endures in {} great works.",
32                civ.name, civ.founding_year,
33                format!("{:?}", civ.government).to_lowercase(),
34                civ.population,
35                (civ.culture_score * 10.0) as u32,
36            ),
37            source_civ: Some(civ.id),
38            reliability: 0.8,
39        });
40
41        // Folklore
42        if rng.coin(0.7) {
43            entries.push(LoreEntry {
44                title: format!("Tales of the {}", civ.name),
45                category: LoreCategory::Folklore,
46                text: format!(
47                    "The people of {} tell stories of a time before time, \
48                     when the world was young and {} walked among mortals.",
49                    civ.name,
50                    if civ.religion == super::super::worldgen::history::ReligionType::Polytheism { "the gods" }
51                    else { "the divine" },
52                ),
53                source_civ: Some(civ.id),
54                reliability: 0.3,
55            });
56        }
57
58        // Forbidden knowledge
59        if civ.technology_level > 0.7 && rng.coin(0.3) {
60            entries.push(LoreEntry {
61                title: format!("The Forbidden Texts of {}", civ.name),
62                category: LoreCategory::Forbidden,
63                text: format!(
64                    "Hidden in the deepest vaults of {}, these texts describe \
65                     experiments that blur the line between mathematics and madness.",
66                    civ.name,
67                ),
68                source_civ: Some(civ.id),
69                reliability: 0.5,
70            });
71        }
72    }
73
74    entries
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80    use crate::worldgen::history::*;
81
82    #[test]
83    fn test_generate_lore() {
84        let mut rng = Rng::new(42);
85        let civs = vec![Civilization {
86            id: 0, name: "Eldheim".to_string(), founding_year: -2000, collapse_year: None,
87            capital_settlement: 0, settlements: vec![0], population: 50000,
88            technology_level: 0.8, military_strength: 0.5, culture_score: 0.7,
89            trade_score: 0.4, government: GovernmentType::Republic,
90            religion: ReligionType::Polytheism, relations: Vec::new(),
91            historical_events: Vec::new(), traits: Vec::new(),
92        }];
93        let lore = generate_lore(&civs, &mut rng);
94        assert!(!lore.is_empty());
95        assert!(lore.iter().any(|l| l.category == LoreCategory::Chronicle));
96    }
97}