Skip to main content

proof_engine/narrative/
dialogue.rs

1//! Dialogue generation — context-sensitive dialogue from character state.
2
3use super::motivation::{Motivation, Personality, Need};
4use crate::worldgen::Rng;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum Tone { Friendly, Hostile, Neutral, Fearful, Respectful, Sarcastic, Desperate, Wise }
8
9#[derive(Debug, Clone)]
10pub struct DialogueLine { pub speaker: String, pub text: String, pub tone: Tone }
11
12/// Generate a greeting based on personality and relationship.
13pub fn generate_greeting(name: &str, personality: &Personality, relationship: f32, rng: &mut Rng) -> DialogueLine {
14    let tone = if relationship > 0.5 { Tone::Friendly }
15        else if relationship < -0.3 { Tone::Hostile }
16        else { Tone::Neutral };
17
18    let templates = match tone {
19        Tone::Friendly => vec![
20            format!("Welcome, friend! What brings you to my door?"),
21            format!("Ah, good to see you again! Come, sit."),
22            format!("A familiar face! The day grows brighter."),
23        ],
24        Tone::Hostile => vec![
25            format!("What do you want? Make it quick."),
26            format!("You again. I thought I made myself clear."),
27            format!("Speak, before I change my mind about listening."),
28        ],
29        _ => vec![
30            format!("Greetings, traveler."),
31            format!("What can I do for you?"),
32            format!("Hmm? Oh. You need something?"),
33        ],
34    };
35
36    DialogueLine {
37        speaker: name.to_string(),
38        text: templates[rng.next_u64() as usize % templates.len()].clone(),
39        tone,
40    }
41}
42
43/// Generate dialogue about a topic based on NPC beliefs.
44pub fn generate_topic_response(name: &str, topic: &str, belief_value: f32, rng: &mut Rng) -> DialogueLine {
45    let tone = if belief_value > 0.5 { Tone::Respectful }
46        else if belief_value < -0.3 { Tone::Sarcastic }
47        else { Tone::Neutral };
48
49    let text = if belief_value > 0.5 {
50        format!("{} is something I hold dear. Let me tell you more...", topic)
51    } else if belief_value < -0.3 {
52        format!("{}? Hah. Don't get me started on that nonsense.", topic)
53    } else {
54        format!("{}? I suppose I have some thoughts on the matter.", topic)
55    };
56
57    DialogueLine { speaker: name.to_string(), text, tone }
58}
59
60/// Unreliable narrator: modify a description based on bias.
61pub fn unreliable_narrate(event: &str, bias: f32, perspective: &str, rng: &mut Rng) -> String {
62    if bias > 0.5 {
63        format!("As {} recalls it, {} — though they may be too generous in their retelling.", perspective, event)
64    } else if bias < -0.3 {
65        format!("According to {}, {} — but one wonders if spite colors the memory.", perspective, event)
66    } else {
67        format!("{} remembers: {}", perspective, event)
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn test_greeting_friendly() {
77        let personality = Personality { openness: 0.8, conscientiousness: 0.5, extraversion: 0.7, agreeableness: 0.8, neuroticism: 0.2 };
78        let mut rng = Rng::new(42);
79        let line = generate_greeting("Elder", &personality, 0.8, &mut rng);
80        assert_eq!(line.tone, Tone::Friendly);
81    }
82
83    #[test]
84    fn test_unreliable_narrator() {
85        let mut rng = Rng::new(42);
86        let biased = unreliable_narrate("the battle was fierce", 0.8, "the general", &mut rng);
87        assert!(biased.contains("generous"));
88    }
89}