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 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 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}