dsmsg/
lib.rs

1//! DSMSG: Random generator for Messages that would be found in the Dark Souls
2//!     series.
3
4#[cfg(not(any(
5    feature = "bloodborne", feature = "demons",
6    feature = "ds1", feature = "ds2", feature = "ds3",
7    feature = "eldenring",
8    feature = "sekiro",
9)))]
10compile_error!("Cannot compile without any Message Sets enabled. Enable \
11at least one of the following Features:\
12\n- bloodborne\n- demons\n- ds1\n- ds2\n- ds3\n- eldenring\n- sekiro");
13
14#[cfg(feature = "ds2")]
15#[macro_use]
16extern crate lazy_static;
17extern crate rand;
18#[macro_use]
19extern crate static_assertions;
20
21#[cfg(feature = "bloodborne")]
22mod bb;
23#[cfg(feature = "demons")]
24mod des;
25#[cfg(feature = "ds1")]
26mod ds1;
27#[cfg(feature = "ds2")]
28mod ds2;
29#[cfg(feature = "ds3")]
30mod ds3;
31#[cfg(feature = "sekiro")]
32mod sek;
33#[cfg(feature = "eldenring")]
34mod er1;
35
36#[cfg(feature = "bloodborne")]
37pub use bb::MessageBB;
38#[cfg(feature = "demons")]
39pub use des::MessageDeS;
40#[cfg(feature = "ds1")]
41pub use ds1::MessageDkS1;
42#[cfg(feature = "ds2")]
43pub use ds2::MessageDkS2;
44#[cfg(feature = "ds3")]
45pub use ds3::MessageDkS3;
46#[cfg(feature = "sekiro")]
47pub use sek::MessageSek;
48#[cfg(feature = "eldenring")]
49pub use er1::MessageEr1;
50
51use rand::prelude::{Rng, SliceRandom, thread_rng, ThreadRng};
52use std::fmt::Display;
53
54
55/// Percentage chance for a Message to have multiple clauses, joined by a
56///     Conjunction.
57const COMPOUND_CHANCE: f64 = 0.5;
58
59
60/// Indicates that a Struct can be used to generate and represent a Message.
61pub trait DsMsg: Display {
62    fn random(rng: &mut ThreadRng) -> Self
63        where Self: Sized;
64}
65
66
67/// A special case of `DsMsg` which may contain a second segment. The two parts
68///     will be joined by a Conjunction string.
69pub trait DsMulti: Display {
70    /// Create a Message with two parts.
71    fn double(rng: &mut ThreadRng) -> Self
72        where Self: Sized;
73
74    /// Create a Message with one part.
75    fn single(rng: &mut ThreadRng) -> Self
76        where Self: Sized;
77}
78
79
80impl<M: DsMulti> DsMsg for M {
81    /// Create a new Message, with at least one randomized string. There is a
82    ///     chance it will also contain a second part, joined to the first by a
83    ///     Conjunction.
84    fn random(rng: &mut ThreadRng) -> Self {
85        if rng.gen_bool(COMPOUND_CHANCE) {
86            Self::double(rng)
87        } else {
88            Self::single(rng)
89        }
90    }
91}
92
93
94/// A Closure that takes an RNG State and returns a dynamic type that
95///     implements `DsMsg`.
96pub type Generator = fn(&mut ThreadRng) -> Box<dyn DsMsg>;
97
98
99/// A constant slice of small closures that each return a `Box<dyn DsMsg>` of a
100///     random generation of their respective messages.
101pub const GENERATORS: &[fn(&mut ThreadRng) -> Box<dyn DsMsg>] = &[
102    #[cfg(feature = "bloodborne")]  |r| Box::new(MessageBB::random(r)),
103    #[cfg(feature = "demons")]      |r| Box::new(MessageDeS::random(r)),
104    #[cfg(feature = "ds1")]         |r| Box::new(MessageDkS1::random(r)),
105    #[cfg(feature = "ds2")]         |r| Box::new(MessageDkS2::random(r)),
106    #[cfg(feature = "ds3")]         |r| Box::new(MessageDkS3::random(r)),
107    #[cfg(feature = "eldenring")]   |r| Box::new(MessageEr1::random(r)),
108    #[cfg(feature = "sekiro")]      |r| Box::new(MessageSek::random(r)),
109];
110
111
112//  Double check to make ***absolutely certain*** that this cannot be empty.
113const_assert_ne!(GENERATORS.len(), 0);
114
115
116/// Randomly select from the `GENERATORS` slice, and run it, producing a random
117///     message from a random source.
118pub fn random_message() -> Box<dyn DsMsg> {
119    let mut rng: ThreadRng = thread_rng();
120
121    //  SAFETY: This should be safe because `GENERATORS` is ensured to not be
122    //      empty by compile-time checks.
123    GENERATORS.choose(&mut rng)
124        .unwrap_or_else(|| unsafe { std::hint::unreachable_unchecked() })
125        (&mut rng)
126}