critfail/
check.rs

1use rand::Rng;
2
3use crate::Damage;
4use crate::RollExpression;
5
6pub use checkoutcome::{CheckOutcome, CheckOutcomeBuilder, CritScore};
7
8mod checkoutcome;
9mod checkparse;
10
11/// The advantage state of an ability check.
12#[derive(PartialEq, Debug, Clone, Copy)]
13pub enum AdvState {
14    /// Check rolled with advantage (roll twice, take the higher value).
15    Advantage,
16    /// Check rolled with no advantage (only roll once).
17    Neutral,
18    /// Check rolled with disadvantage (roll twice, take the lower value).
19    Disadvantage,
20}
21
22impl Default for AdvState {
23    fn default() -> Self {
24        Self::Neutral
25    }
26}
27
28/// An ability check - roll a d20, potentially with modifiers or
29/// advantage.
30///
31/// ```
32/// use critfail::{RollExpression, Check};
33///
34/// let check = Check::new("r+4").unwrap();
35///
36/// let outcome = check.roll();
37///
38/// print!("{}", outcome);   // Prints something like "16"
39/// print!("{:?}", outcome); // Prints something like "(12)+4"
40/// ```
41#[derive(PartialEq, Debug, Clone)]
42pub struct Check {
43    adv: AdvState,
44    // TODO: the modifier should be a Vec<Modifier> instead of a Damage
45    modifier: Damage,
46}
47
48impl Check {
49    /// Roll this check using `adv` to override the advantage state.
50    ///
51    /// ```
52    /// use critfail::{RollExpression, Check, AdvState};
53    /// let check = Check::new("r+3").unwrap();
54    ///
55    /// check.roll(); // Roll without advantage
56    /// check.roll_with_advantage(AdvState::Advantage); // Roll with advantage
57    /// check.roll_with_advantage(AdvState::Neutral); // Roll without advantage
58    /// check.roll_with_advantage(AdvState::Disadvantage); // Roll with disadvantage
59    /// ```
60    pub fn roll_with_advantage(&self, adv: AdvState) -> CheckOutcome {
61        let r1 = rand::thread_rng().gen_range(1, 21);
62        let r2 = rand::thread_rng().gen_range(1, 21);
63        let mods = self.modifier.roll();
64        CheckOutcome::new(adv, r1, r2, mods.into_modifiers().into_inner())
65    }
66}
67
68impl RollExpression for Check {
69    type Outcome = CheckOutcome;
70
71    fn roll(&self) -> Self::Outcome {
72        self.roll_with_advantage(self.adv)
73    }
74}