1#[cfg(feature = "with_cli")]
2pub mod cli;
3pub mod conditions;
4pub mod data;
5pub mod events;
6pub mod items;
7pub mod protocol;
8pub mod scenes;
9pub mod translations;
10pub mod updates;
11#[cfg(feature = "with_webapp")]
12pub mod webapp;
13
14use anyhow::{anyhow, Result};
15use fluent::FluentArgs;
16use serde::{Deserialize, Serialize};
17use std::{any::Any, collections::HashMap, fmt};
18use uuid::Uuid;
19
20use conditions::Check;
21
22pub trait AsAny: Any {
23 fn as_any(&self) -> &dyn Any;
24 fn as_any_mut(&mut self) -> &mut dyn Any;
25}
26
27#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
28pub enum ItemState {
29 Owned(String),
30 InScene(String),
31 Unassigned,
32}
33
34#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Copy)]
35pub struct GeoLocation(f64, f64);
36
37impl Default for ItemState {
38 fn default() -> Self {
39 Self::Unassigned
40 }
41}
42
43impl Dumpable for ItemState {
44 fn dump(&self) -> serde_json::Value {
45 match self {
46 Self::Owned(character) => serde_json::json!({"kind": "character", "value": character}),
47 Self::InScene(scene) => serde_json::json!({"kind": "scene", "value": scene}),
48 Self::Unassigned => serde_json::Value::Null,
49 }
50 }
51 fn load(&mut self, data: serde_json::Value) -> Result<()> {
52 let new = match data {
53 serde_json::Value::Null => Self::Unassigned,
54 serde_json::Value::Object(mut inner) => {
55 let value = if let serde_json::Value::String(value) = inner
56 .remove("value")
57 .ok_or_else(|| anyhow!("missing value while parsing ItemState"))?
58 {
59 value
60 } else {
61 return Err(anyhow!("Mismatched type in ItemValue"));
62 };
63 match inner
64 .remove("kind")
65 .ok_or_else(|| anyhow!("missing kind while parsing ItemState"))?
66 {
67 serde_json::Value::String(kind) if kind == "character" => Self::Owned(value),
68 serde_json::Value::String(kind) if kind == "scene" => Self::InScene(value),
69 e => return Err(anyhow!("Unknown kind `{}`", e)),
70 }
71 }
72 _ => return Err(anyhow!("Failed to deserialize ItemState")),
73 };
74 *self = new;
75
76 Ok(())
77 }
78}
79
80pub trait Tagged {
81 fn get_tags(&self) -> Vec<String> {
82 vec![]
83 }
84 fn set_tags(&mut self, _tags: Vec<String>) {}
85}
86
87pub trait Named {
88 fn name(&self) -> &'static str;
90}
91
92pub trait Music {
93 fn music(&self) -> Option<String> {
95 None
96 }
97}
98
99pub trait Clean {
100 fn clean(&mut self) {}
102}
103
104pub trait Description: Named {
105 fn long(&self, world: &dyn World) -> String {
106 world.get_message(&format!("{}-{}-long", world.name(), self.name()), None)
107 }
108 fn short(&self, world: &dyn World) -> String {
109 world.get_message(&format!("{}-{}-short", world.name(), self.name()), None)
110 }
111}
112
113pub trait Dumpable {
114 fn dump(&self) -> serde_json::Value;
115 fn load(&mut self, data: serde_json::Value) -> Result<()>;
116}
117
118pub trait Item: Named + Tagged + AsAny + Description + Dumpable + fmt::Debug + Clean {
119 fn state(&self) -> &ItemState;
120 fn set_state(&mut self, state: ItemState);
121 fn last_event(&self) -> Option<usize>;
122 fn set_last_event(&mut self, event: usize);
123}
124
125pub trait Character: Named + Tagged + AsAny + Description + Dumpable + fmt::Debug + Clean {
126 fn scene(&self) -> &Option<String>;
127 fn set_scene(&mut self, scene: Option<String>);
128}
129
130pub trait Scene:
131 Named + Tagged + AsAny + Description + Dumpable + Music + fmt::Debug + Clean
132{
133 fn dialog(&self) -> Option<usize> {
134 None
135 }
136 fn next_dialog(&mut self) {}
137 fn geo_location(&self) -> Option<GeoLocation> {
138 None
139 }
140 fn set_geo_location(&mut self, _location: Option<GeoLocation>) {}
141}
142
143pub trait Event: Tagged + AsAny + fmt::Debug + PartialEq<[u8]> {
144 fn kind(&self) -> &str {
145 std::any::type_name::<Self>()
146 .rsplitn(2, "::")
147 .collect::<Vec<&str>>()[0]
148 }
149 fn name(&self) -> &str;
150 fn can_be_triggered(&self, world: &dyn World) -> bool {
151 self.get_condition().check(world).unwrap()
152 }
153 fn trigger(&mut self, world: &mut dyn World) {
154 for update in self.get_world_updates() {
155 update.change(world).unwrap();
156 for item in self.items() {
157 let last_event = world.event_count();
158 let item = world.items_mut().get_mut(&item).unwrap();
159 item.set_last_event(last_event);
160 }
161 }
162 world.event_inc();
163 }
164 fn perform(&mut self, world: &mut dyn World) -> bool {
165 if self.can_be_triggered(world) {
166 self.trigger(world);
167 true
168 } else {
169 false
170 }
171 }
172 fn action_text(&self, world: &dyn World) -> String {
173 let msg = format!("{}-action", self.msg_base(world));
174 world.get_message(&msg, None)
175 }
176 fn success_text(&self, world: &dyn World) -> String {
177 let msg = format!("{}-success", self.msg_base(world));
178 world.get_message(&msg, None)
179 }
180 fn fail_text(&self, world: &dyn World) -> String {
181 let msg = format!("{}-fail", self.msg_base(world));
182 world.get_message(&msg, None)
183 }
184 fn set_world_updates(&mut self, updates: Vec<Box<dyn updates::Change>>);
185 fn set_condition(&mut self, condition: conditions::Condition);
186
187 fn msg_base(&self, world: &dyn World) -> String {
188 format!("{}-{}", world.name(), self.name())
189 }
190
191 fn get_world_updates(&self) -> &[Box<dyn updates::Change>];
192 fn get_condition(&self) -> &conditions::Condition;
193
194 fn initiator(&self) -> String;
195 fn set_initiator(&mut self, initiator: String);
196 fn dump(&self) -> serde_json::Value;
197 fn matches(&self, value: &serde_json::Value) -> bool;
198
199 fn items(&self) -> Vec<String>;
200 fn characters(&self) -> Vec<String>;
201
202 fn sort_key(&self, world: &dyn World) -> (usize, String, String, String) {
203 let max_event_idx = self
204 .items()
205 .iter()
206 .map(|e| {
207 if let Some(item) = world.items().get(e) {
208 item.last_event().unwrap_or(0)
209 } else {
210 0
211 }
212 })
213 .max()
214 .unwrap_or(0);
215
216 let max_item_name = self.items().into_iter().max().unwrap_or_default();
217 (
218 max_event_idx,
219 max_item_name,
220 self.characters().into_iter().max().unwrap_or_default(),
221 self.name().to_string(),
222 )
223 }
224
225 fn geo_location(&self, _world: &dyn World) -> Option<(String, Option<String>, GeoLocation)> {
227 None
228 }
229}
230
231pub trait WorldBuilder<S>
232where
233 S: World,
234{
235 fn character(self, character: Box<dyn Character>) -> Self;
236 fn item(self, item: Box<dyn Item>) -> Self;
237 fn scene(self, scene: Box<dyn Scene>) -> Self;
238 fn build(self) -> Result<S>;
239 fn make_world() -> Result<S>;
240}
241
242pub trait World: Named + Dumpable + Clean {
243 fn available_languages(&self) -> Vec<String>;
244 fn lang(&self) -> &str;
245 fn set_lang(&mut self, lang: &str) -> bool;
246 fn description(&self) -> Box<dyn Description>;
247 fn scenes(&self) -> &HashMap<String, Box<dyn Scene>>;
248 fn scenes_mut(&mut self) -> &mut HashMap<String, Box<dyn Scene>>;
249 fn characters(&self) -> &HashMap<String, Box<dyn Character>>;
250 fn characters_mut(&mut self) -> &mut HashMap<String, Box<dyn Character>>;
251 fn items(&self) -> &HashMap<String, Box<dyn Item>>;
252 fn items_mut(&mut self) -> &mut HashMap<String, Box<dyn Item>>;
253 fn setup(&mut self, new_id: bool);
254 fn reset(&mut self) {
255 self.clean_world();
256 self.setup(false);
257 }
258 fn clean_world(&mut self) {
259 self.clean();
260 self.characters_mut().values_mut().for_each(|e| e.clean());
261 self.items_mut().values_mut().for_each(|e| e.clean());
262 self.scenes_mut().values_mut().for_each(|e| e.clean());
263 }
264 fn randomize_id(&mut self) {
265 self.set_id(Uuid::new_v4());
266 }
267 fn finished(&self) -> bool;
268 fn event_count(&self) -> usize;
269 fn event_inc(&mut self);
270
271 fn id(&self) -> &Uuid;
272 fn set_id(&mut self, id: Uuid);
273 fn get_message(&self, msgid: &str, _args: Option<FluentArgs>) -> String {
274 msgid.to_string()
275 }
276
277 fn version(&self) -> usize {
282 1
283 }
284}
285
286pub trait Narrator {
287 fn all_events(&self, world: &dyn World) -> Vec<Box<dyn Event>>;
288 fn available_events(&self, world: &dyn World) -> Vec<Box<dyn Event>> {
289 self.all_events(world)
290 .into_iter()
291 .filter(|e| e.can_be_triggered(world))
292 .collect()
293 }
294 fn parse_event(&self, world: &dyn World, value: serde_json::Value) -> Option<Box<dyn Event>>;
295 fn available_events_sorted(&self, world: &dyn World) -> Vec<Box<dyn Event>> {
296 let mut events = self.available_events(world);
297 events.sort_by_key(|e| e.sort_key(world));
298 events
299 }
300}
301
302#[cfg(test)]
303pub mod test {
304 use super::{
305 conditions, updates, AsAny, Character, Clean, Description, Dumpable, Event, Item,
306 ItemState, Music, Named, Scene, Tagged, World, WorldBuilder,
307 };
308 use anyhow::{anyhow, Result};
309 use std::{any::Any, collections::HashMap};
310 use uuid::Uuid;
311
312 #[derive(Debug, Default)]
313 struct TestCharacter {
314 scene: Option<String>,
315 }
316
317 impl Tagged for TestCharacter {}
318
319 impl Named for TestCharacter {
320 fn name(&self) -> &'static str {
321 "test_character"
322 }
323 }
324
325 impl Description for TestCharacter {}
326
327 impl AsAny for TestCharacter {
328 fn as_any(&self) -> &dyn Any {
329 self
330 }
331 fn as_any_mut(&mut self) -> &mut dyn Any {
332 self
333 }
334 }
335
336 impl Clean for TestCharacter {
337 fn clean(&mut self) {}
338 }
339
340 impl Character for TestCharacter {
341 fn scene(&self) -> &Option<String> {
342 &self.scene
343 }
344 fn set_scene(&mut self, scene: Option<String>) {
345 self.scene = scene
346 }
347 }
348
349 impl Dumpable for TestCharacter {
350 fn dump(&self) -> serde_json::Value {
351 serde_json::json!(
352 {
353 "name": self.name(),
354 }
355 )
356 }
357
358 fn load(&mut self, _data: serde_json::Value) -> Result<()> {
359 Ok(())
360 }
361 }
362
363 #[derive(Debug, Default)]
364 struct TestItem {
365 state: ItemState,
366 last_event: Option<usize>,
367 }
368
369 impl Tagged for TestItem {}
370
371 impl Named for TestItem {
372 fn name(&self) -> &'static str {
373 "test_item"
374 }
375 }
376
377 impl Clean for TestItem {
378 fn clean(&mut self) {}
379 }
380
381 impl Description for TestItem {}
382
383 impl AsAny for TestItem {
384 fn as_any(&self) -> &dyn Any {
385 self
386 }
387 fn as_any_mut(&mut self) -> &mut dyn Any {
388 self
389 }
390 }
391
392 impl Dumpable for TestItem {
393 fn dump(&self) -> serde_json::Value {
394 serde_json::json!(
395 {
396 "name": self.name(),
397 }
398 )
399 }
400
401 fn load(&mut self, _data: serde_json::Value) -> Result<()> {
402 Ok(())
403 }
404 }
405
406 impl Item for TestItem {
407 fn state(&self) -> &ItemState {
408 &self.state
409 }
410 fn set_state(&mut self, state: ItemState) {
411 self.state = state;
412 }
413 fn last_event(&self) -> Option<usize> {
414 self.last_event
415 }
416 fn set_last_event(&mut self, event: usize) {
417 self.last_event = Some(event);
418 }
419 }
420
421 #[derive(Debug, Default)]
422 struct TestScene {}
423
424 impl Tagged for TestScene {}
425
426 impl Named for TestScene {
427 fn name(&self) -> &'static str {
428 "test_scene"
429 }
430 }
431
432 impl Description for TestScene {}
433
434 impl Clean for TestScene {
435 fn clean(&mut self) {}
436 }
437
438 impl AsAny for TestScene {
439 fn as_any(&self) -> &dyn Any {
440 self
441 }
442 fn as_any_mut(&mut self) -> &mut dyn Any {
443 self
444 }
445 }
446
447 impl Dumpable for TestScene {
448 fn dump(&self) -> serde_json::Value {
449 serde_json::json!(
450 {
451 "name": self.name(),
452 }
453 )
454 }
455
456 fn load(&mut self, _data: serde_json::Value) -> Result<()> {
457 Ok(())
458 }
459 }
460
461 impl Music for TestScene {}
462
463 impl Scene for TestScene {}
464
465 #[derive(Clone, Debug)]
466 struct TestDescription;
467 impl Named for TestDescription {
468 fn name(&self) -> &'static str {
469 "test_description"
470 }
471 }
472
473 impl Description for TestDescription {}
474
475 #[derive(Debug)]
476 struct TestEvent {
477 #[allow(dead_code)]
478 description: TestDescription,
479 condition: conditions::Condition,
480 }
481 impl Tagged for TestEvent {}
482 impl Named for TestEvent {
483 fn name(&self) -> &'static str {
484 "test_event"
485 }
486 }
487 impl AsAny for TestEvent {
488 fn as_any(&self) -> &dyn Any {
489 self
490 }
491 fn as_any_mut(&mut self) -> &mut dyn Any {
492 self
493 }
494 }
495 impl PartialEq<[u8]> for TestEvent {
496 fn eq(&self, _other: &[u8]) -> bool {
497 false
498 }
499 }
500 impl Event for TestEvent {
501 fn trigger(&mut self, _world: &mut dyn World) {}
502
503 fn can_be_triggered(&self, _world: &dyn World) -> bool {
504 true
505 }
506
507 fn name(&self) -> &str {
508 "test_event"
509 }
510
511 fn action_text(&self, _: &dyn World) -> String {
512 "action".into()
513 }
514
515 fn success_text(&self, _: &dyn World) -> String {
516 "success".into()
517 }
518
519 fn fail_text(&self, _: &dyn World) -> String {
520 "fail".into()
521 }
522
523 fn set_world_updates(&mut self, _updates: Vec<Box<dyn updates::Change>>) {}
524 fn set_condition(&mut self, _condition: conditions::Condition) {}
525 fn get_world_updates(&self) -> &[Box<dyn updates::Change>] {
526 &[]
527 }
528 fn get_condition(&self) -> &conditions::Condition {
529 &self.condition
530 }
531
532 fn initiator(&self) -> String {
533 "test_character".into()
534 }
535
536 fn set_initiator(&mut self, _initiator: String) {}
537
538 fn dump(&self) -> serde_json::Value {
539 serde_json::json!({})
540 }
541
542 fn matches(&self, _value: &serde_json::Value) -> bool {
543 false
544 }
545
546 fn items(&self) -> Vec<String> {
547 vec![]
548 }
549
550 fn characters(&self) -> Vec<String> {
551 vec!["test_character".to_owned()]
552 }
553 }
554
555 #[derive(Debug, Default)]
556 struct TestWorld {
557 id: Uuid,
558 lang: String,
559 items: HashMap<String, Box<dyn Item>>,
560 scenes: HashMap<String, Box<dyn Scene>>,
561 characters: HashMap<String, Box<dyn Character>>,
562 event_count: usize,
563 }
564
565 impl Named for TestWorld {
566 fn name(&self) -> &'static str {
567 "test_world"
568 }
569 }
570
571 impl Clean for TestWorld {
572 fn clean(&mut self) {}
573 }
574
575 impl World for TestWorld {
576 fn description(&self) -> Box<dyn Description> {
577 Box::new(TestDescription)
578 }
579
580 fn scenes(&self) -> &HashMap<String, Box<dyn Scene>> {
581 &self.scenes
582 }
583
584 fn scenes_mut(&mut self) -> &mut HashMap<String, Box<dyn Scene>> {
585 &mut self.scenes
586 }
587
588 fn characters(&self) -> &HashMap<String, Box<dyn Character>> {
589 &self.characters
590 }
591
592 fn characters_mut(&mut self) -> &mut HashMap<String, Box<dyn Character>> {
593 &mut self.characters
594 }
595
596 fn items(&self) -> &HashMap<String, Box<dyn Item>> {
597 &self.items
598 }
599
600 fn items_mut(&mut self) -> &mut HashMap<String, Box<dyn Item>> {
601 &mut self.items
602 }
603
604 fn lang(&self) -> &str {
605 &self.lang
606 }
607
608 fn set_lang(&mut self, lang: &str) -> bool {
609 self.lang = lang.into();
610 true
611 }
612
613 fn available_languages(&self) -> Vec<String> {
614 vec!["en-US".to_string()]
615 }
616
617 fn setup(&mut self, _new_id: bool) {}
618
619 fn finished(&self) -> bool {
620 true
621 }
622
623 fn event_count(&self) -> usize {
624 self.event_count
625 }
626
627 fn event_inc(&mut self) {
628 self.event_count += 1;
629 }
630
631 fn id(&self) -> &Uuid {
632 &self.id
633 }
634
635 fn set_id(&mut self, id: Uuid) {
636 self.id = id
637 }
638 }
639
640 impl Dumpable for TestWorld {
641 fn dump(&self) -> serde_json::Value {
642 serde_json::json!({
643 "characters": self.characters.iter().map(|(k, v)| (k.clone(), v.dump())).collect::<HashMap<String, serde_json::Value>>(),
644 "items": self.items.iter().map(|(k, v)| (k.clone(), v.dump())).collect::<HashMap<String, serde_json::Value>>(),
645 "scenes": self.scenes.iter().map(|(k, v)| (k.clone(), v.dump())).collect::<HashMap<String, serde_json::Value>>(),
646 "event_count": self.event_count
647 })
648 }
649 fn load(&mut self, data: serde_json::Value) -> Result<()> {
650 match data {
651 serde_json::Value::Object(root) => {
654 for item in root {
655 match item {
656 (k, v) if k == "characters" => {
657 if let serde_json::Value::Object(characters) = v {
658 for (name, data) in characters.into_iter() {
659 let character = self
660 .characters_mut()
661 .get_mut(&name)
662 .ok_or_else(|| anyhow!(""))?;
663 character.load(data)?;
664 }
665 } else {
666 return Err(anyhow!(""));
667 }
668 }
669 (k, v) if k == "items" => {
670 if let serde_json::Value::Object(items) = v {
671 for (name, data) in items.into_iter() {
672 let item = self
673 .characters_mut()
674 .get_mut(&name)
675 .ok_or_else(|| anyhow!(""))?;
676 item.load(data)?;
677 }
678 } else {
679 return Err(anyhow!(""));
680 }
681 }
682 (k, v) if k == "scenes" => {
683 if let serde_json::Value::Object(scenes) = v {
684 for (name, data) in scenes.into_iter() {
685 let scene = self
686 .characters_mut()
687 .get_mut(&name)
688 .ok_or_else(|| anyhow!(""))?;
689 scene.load(data)?;
690 }
691 } else {
692 return Err(anyhow!(""));
693 }
694 }
695 (k, v) if k == "event_count" => {
696 if let serde_json::Value::Number(num) = v {
697 if let Some(count) = num.as_u64() {
698 self.event_count = count as usize;
699 } else {
700 return Err(anyhow!(""));
701 }
702 } else {
703 return Err(anyhow!(""));
704 }
705 }
706 _ => return Err(anyhow!("")),
707 }
708 }
709 }
710 _ => return Err(anyhow!("")),
711 }
712 Ok(())
713 }
714 }
715
716 #[derive(Default)]
717 struct TestWorldBuilder {
718 characters: Vec<Box<dyn Character>>,
719 items: Vec<Box<dyn Item>>,
720 scenes: Vec<Box<dyn Scene>>,
721 }
722
723 impl WorldBuilder<TestWorld> for TestWorldBuilder {
724 fn character(mut self, character: Box<dyn Character>) -> Self {
725 self.characters.push(character);
726 self
727 }
728
729 fn item(mut self, item: Box<dyn Item>) -> Self {
730 self.items.push(item);
731 self
732 }
733
734 fn scene(mut self, item: Box<dyn Scene>) -> Self {
735 self.scenes.push(item);
736 self
737 }
738
739 fn build(self) -> Result<TestWorld> {
740 Ok(TestWorld {
741 lang: "en-US".into(),
742 characters: self
743 .characters
744 .into_iter()
745 .map(|e| (e.name().into(), e))
746 .collect(),
747 items: self
748 .items
749 .into_iter()
750 .map(|e| (e.name().into(), e))
751 .collect(),
752 scenes: self
753 .scenes
754 .into_iter()
755 .map(|e| (e.name().into(), e))
756 .collect(),
757 ..Default::default()
758 })
759 }
760
761 fn make_world() -> Result<TestWorld> {
762 Self::default().build()
763 }
764 }
765
766 #[test]
767 fn linear() {
768 let world = TestWorldBuilder::default()
769 .character(Box::new(TestCharacter::default()))
770 .character(Box::new(TestCharacter::default()))
771 .item(Box::new(TestItem::default()))
772 .item(Box::new(TestItem::default()))
773 .item(Box::new(TestItem::default()))
774 .item(Box::new(TestItem::default()))
775 .scene(Box::new(TestScene::default()))
776 .scene(Box::new(TestScene::default()))
777 .scene(Box::new(TestScene::default()));
778
779 assert!(world.build().is_ok());
780 }
781}