1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use serde::{Deserialize, Serialize};
use vek::{Vec2, Vec3};

use super::Item;

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AskedLocation {
    pub name: String,
    pub origin: Vec2<i32>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum PersonType {
    Merchant,
    Villager { name: String },
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AskedPerson {
    pub person_type: PersonType,
    pub origin: Option<Vec3<i32>>,
}

impl AskedPerson {
    pub fn name(&self) -> String {
        match &self.person_type {
            PersonType::Merchant => "The Merchant".to_string(),
            PersonType::Villager { name } => name.clone(),
        }
    }
}

/// Conversation subject
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum Subject {
    /// Using simple interaction with NPC
    /// This is meant to be the default behavior of talking
    /// NPC will throw a random dialogue to you
    Regular,
    /// Asking for trading
    /// Ask the person to trade with you
    /// NPC will either invite you to trade, or decline
    Trade,
    /// Inquiring the mood of the NPC
    /// NPC will explain what his mood is, and why.
    /// Can lead to potential quests if the NPC has a bad mood
    /// Else it'll just be flavor text explaining why he got this mood
    Mood,
    /// Asking for a location
    /// NPC will either know where this location is, or not
    /// It'll tell you which direction and approx what distance it is from you
    Location(AskedLocation),
    /// Asking for a person's location
    /// NPC will either know where this person is, or not
    /// It'll tell you which direction and approx what distance it is from you
    Person(AskedPerson),
    /// Asking for work
    /// NPC will give you a quest if his mood is bad enough
    /// So either it'll tell you something to do, or just say that he got
    /// nothing
    Work,
}

/// Context of why a NPC has a specific mood (good, neutral, bad, ...)
#[derive(Clone, Debug)]
pub enum MoodContext {
    /// The weather is good, sunny, appeasing, etc...
    GoodWeather,
    /// Someone completed a quest and enlightened this NPC's day
    QuestSucceeded { hero: String, quest_desc: String },

    /// Normal day, same as yesterday, nothing relevant to say about it, that's
    /// everyday life
    EverydayLife,
    /// Need one or more items in order to complete a personal task, or for
    /// working
    NeedItem { item: Item, quantity: u16 },

    /// A personal good has been robbed! Gotta find a replacement
    MissingItem { item: Item },
}

// Note: You can add in-between states if needed
/// NPC mood status indicator
#[derive(Clone, Debug)]
pub enum MoodState {
    /// The NPC is happy!
    Good(MoodContext),
    /// The NPC is having a normal day
    Neutral(MoodContext),
    /// The NPC got a pretty bad day. He may even need player's help!
    Bad(MoodContext),
}

// TODO: this should return common_i18n::Content
impl MoodState {
    pub fn describe(&self) -> String {
        match self {
            MoodState::Good(context) => format!("I'm so happy, {}", context.describe()),
            MoodState::Neutral(context) => context.describe(),
            MoodState::Bad(context) => {
                format!("I'm mad, {}", context.describe())
            },
        }
    }
}

// TODO: this should return common_i18n::Content
impl MoodContext {
    pub fn describe(&self) -> String {
        match &self {
            MoodContext::GoodWeather => "The weather is great today!".to_string(),
            MoodContext::QuestSucceeded { hero, quest_desc } => {
                format!("{} helped me on {}", hero, quest_desc)
            },
            &MoodContext::EverydayLife => "Life's going as always.".to_string(),
            MoodContext::NeedItem {
                item: _,
                quantity: _,
            } => {
                // format!("I need {} {}!", quantity, item.name())
                "I need some item, not just any item!".to_string()
            },
            &MoodContext::MissingItem { item: _ } => {
                // format!("Someone robbed my {}!", item.name())
                "Someone robbed me of my item!".to_string()
            },
        }
    }
}