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}