pabitell_lib/
conditions.rs

1use crate::{ItemState, World};
2use anyhow::{anyhow, Result};
3use std::{collections::HashSet, fmt, ops, rc::Rc};
4
5pub trait Check: fmt::Debug {
6    fn check(&self, world: &dyn World) -> Result<bool>;
7}
8
9pub enum Condition {
10    Check(Rc<dyn Check>),
11    Not(Rc<Condition>),
12    And(Rc<Condition>, Rc<Condition>),
13    Or(Rc<Condition>, Rc<Condition>),
14}
15
16impl Condition {
17    pub fn new(check: impl Check + 'static) -> Self {
18        Self::Check(Rc::new(check))
19    }
20}
21
22impl Default for Condition {
23    fn default() -> Self {
24        // By default always return true
25        Self::Check(Rc::new(AlwaysCheck))
26    }
27}
28
29impl Check for Condition {
30    fn check(&self, world: &dyn World) -> Result<bool> {
31        match self {
32            Self::Check(check) => Ok(check.check(world)?),
33            Self::Not(cond) => Ok(!cond.check(world)?),
34            Self::And(cond1, cond2) => Ok(cond1.check(world)? && cond2.check(world)?),
35            Self::Or(cond1, cond2) => Ok(cond1.check(world)? || cond2.check(world)?),
36        }
37    }
38}
39
40impl fmt::Debug for Condition {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        match self {
43            Self::Check(check) => f.debug_struct("Check").field("check", check).finish(),
44            Self::Not(cond) => f.debug_struct("Not").field("cond", cond).finish(),
45            Self::And(cond1, cond2) => f
46                .debug_struct("And")
47                .field("cond1", cond1)
48                .field("cond2", cond2)
49                .finish(),
50            Self::Or(cond1, cond2) => f
51                .debug_struct("Or")
52                .field("cond1", cond1)
53                .field("cond2", cond2)
54                .finish(),
55        }
56    }
57}
58
59impl ops::Not for Condition {
60    type Output = Self;
61
62    fn not(self) -> Self::Output {
63        Self::Not(Rc::new(self))
64    }
65}
66
67impl ops::BitAnd for Condition {
68    type Output = Self;
69
70    fn bitand(self, rhs: Self) -> Self::Output {
71        Self::And(Rc::new(self), Rc::new(rhs))
72    }
73}
74
75impl ops::BitOr for Condition {
76    type Output = Self;
77
78    fn bitor(self, rhs: Self) -> Self::Output {
79        Self::Or(Rc::new(self), Rc::new(rhs))
80    }
81}
82
83pub struct AlwaysCheck;
84
85impl AlwaysCheck {
86    pub fn cond() -> Condition {
87        Self.into()
88    }
89}
90
91impl fmt::Debug for AlwaysCheck {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        f.debug_struct("Always").finish()
94    }
95}
96
97impl Check for AlwaysCheck {
98    fn check(&self, _world: &dyn World) -> Result<bool> {
99        Ok(true)
100    }
101}
102
103impl From<AlwaysCheck> for Condition {
104    fn from(check: AlwaysCheck) -> Self {
105        Condition::Check(Rc::new(check))
106    }
107}
108
109pub struct SameSceneCheck {
110    characters: Vec<String>,
111    items: Vec<String>,
112}
113
114impl SameSceneCheck {
115    pub fn cond(characters: Vec<String>, items: Vec<String>) -> Condition {
116        Self { characters, items }.into()
117    }
118}
119
120impl fmt::Debug for SameSceneCheck {
121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122        f.debug_struct("SameScene")
123            .field("characters", &self.characters)
124            .field("items", &self.items)
125            .finish()
126    }
127}
128
129impl Check for SameSceneCheck {
130    fn check(&self, world: &dyn World) -> Result<bool> {
131        let character_scenes = self
132            .characters
133            .iter()
134            .filter_map(|e| world.characters().get(e.as_str())?.scene().clone())
135            .collect::<Vec<_>>();
136        let item_scenes = self
137            .items
138            .iter()
139            .filter_map(|e| match world.items().get(e.as_str())?.state() {
140                ItemState::InScene(scene) => Some(scene),
141                _ => None,
142            })
143            .collect::<Vec<_>>();
144        // All characters and items are in some scene
145        if character_scenes.len() == self.characters.len() && item_scenes.len() == self.items.len()
146        {
147            if character_scenes
148                .iter()
149                .chain(item_scenes.into_iter())
150                .collect::<HashSet<_>>()
151                .len()
152                < 2
153            {
154                Ok(true)
155            } else {
156                Ok(false)
157            }
158        } else {
159            Ok(false)
160        }
161    }
162}
163
164impl From<SameSceneCheck> for Condition {
165    fn from(check: SameSceneCheck) -> Self {
166        Condition::new(check)
167    }
168}
169
170pub struct HasItemCheck {
171    character: String,
172    item: String,
173}
174
175impl HasItemCheck {
176    pub fn cond(character: String, item: String) -> Condition {
177        Self { character, item }.into()
178    }
179}
180
181impl fmt::Debug for HasItemCheck {
182    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183        f.debug_struct("HasItem")
184            .field("character", &self.character)
185            .field("item", &self.item)
186            .finish()
187    }
188}
189
190impl Check for HasItemCheck {
191    fn check(&self, world: &dyn World) -> Result<bool> {
192        if let Some(item) = world.items().get(&self.item) {
193            match item.state() {
194                ItemState::Owned(owner) => Ok(&self.character == owner),
195                _ => Ok(false),
196            }
197        } else {
198            Ok(false)
199        }
200    }
201}
202
203impl From<HasItemCheck> for Condition {
204    fn from(check: HasItemCheck) -> Self {
205        Condition::new(check)
206    }
207}
208
209pub struct CharacterInSceneCheck {
210    character: String,
211    scene: Option<String>,
212}
213
214impl CharacterInSceneCheck {
215    pub fn cond(character: String, scene: Option<String>) -> Condition {
216        Self { character, scene }.into()
217    }
218}
219
220impl fmt::Debug for CharacterInSceneCheck {
221    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222        f.debug_struct("CharacterInScene")
223            .field("character", &self.character)
224            .field("scene", &self.scene)
225            .finish()
226    }
227}
228
229impl Check for CharacterInSceneCheck {
230    fn check(&self, world: &dyn World) -> Result<bool> {
231        Ok(
232            if let Some(character) = world.characters().get(&self.character) {
233                &self.scene == character.scene()
234            } else {
235                false
236            },
237        )
238    }
239}
240
241impl From<CharacterInSceneCheck> for Condition {
242    fn from(check: CharacterInSceneCheck) -> Self {
243        Condition::new(check)
244    }
245}
246
247pub struct CanGiveCheck {
248    from_character: String,
249    to_character: String,
250    item: String,
251}
252
253impl CanGiveCheck {
254    pub fn cond(from_character: String, to_character: String, item: String) -> Condition {
255        Self {
256            from_character,
257            to_character,
258            item,
259        }
260        .into()
261    }
262}
263
264impl fmt::Debug for CanGiveCheck {
265    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266        f.debug_struct("CanGive")
267            .field("from_character", &self.from_character)
268            .field("to_character", &self.to_character)
269            .field("item", &self.item)
270            .finish()
271    }
272}
273
274impl Check for CanGiveCheck {
275    fn check(&self, world: &dyn World) -> Result<bool> {
276        (HasItemCheck::cond(self.from_character.clone(), self.item.clone())
277            & SameSceneCheck::cond(
278                vec![self.from_character.clone(), self.to_character.clone()],
279                vec![],
280            ))
281        .check(world)
282    }
283}
284
285impl From<CanGiveCheck> for Condition {
286    fn from(check: CanGiveCheck) -> Self {
287        Condition::new(check)
288    }
289}
290
291pub struct AllItemsWithTagInStateCheck {
292    tags: Vec<String>,
293    state: ItemState,
294}
295
296impl AllItemsWithTagInStateCheck {
297    pub fn cond(tags: Vec<String>, state: ItemState) -> Condition {
298        Self { tags, state }.into()
299    }
300}
301
302impl fmt::Debug for AllItemsWithTagInStateCheck {
303    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304        f.debug_struct("AllItemsWithTagInState")
305            .field("tags", &self.tags)
306            .field("state", &self.state)
307            .finish()
308    }
309}
310
311impl Check for AllItemsWithTagInStateCheck {
312    fn check(&self, world: &dyn World) -> Result<bool> {
313        Ok(world
314            .items()
315            .values()
316            .filter(|e| e.get_tags().iter().any(|t| self.tags.contains(t)))
317            .all(|e| e.state() == &self.state))
318    }
319}
320
321impl From<AllItemsWithTagInStateCheck> for Condition {
322    fn from(check: AllItemsWithTagInStateCheck) -> Self {
323        Condition::new(check)
324    }
325}
326
327pub struct SceneDialogCheck {
328    scene: String,
329    dialog: usize,
330}
331
332impl SceneDialogCheck {
333    pub fn cond(scene: String, dialog: usize) -> Condition {
334        Self { scene, dialog }.into()
335    }
336}
337
338impl fmt::Debug for SceneDialogCheck {
339    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
340        f.debug_struct("SceneDialog")
341            .field("scene", &self.scene)
342            .field("dialog", &self.dialog)
343            .finish()
344    }
345}
346
347impl Check for SceneDialogCheck {
348    fn check(&self, world: &dyn World) -> Result<bool> {
349        Ok(world
350            .scenes()
351            .get(&self.scene)
352            .ok_or_else(|| anyhow!("Scene {} not found", &self.scene))?
353            .dialog()
354            .ok_or_else(|| anyhow!("Scene {} doesn't have dialogs", &self.scene))?
355            == self.dialog)
356    }
357}
358
359impl From<SceneDialogCheck> for Condition {
360    fn from(check: SceneDialogCheck) -> Self {
361        Condition::new(check)
362    }
363}