dnd_character/
abilities.rs

1use std::{
2    iter::Sum,
3    ops::{Add, AddAssign},
4};
5
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Default, Clone)]
9#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
11#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
12pub struct AbilityScore {
13    pub score: u8,
14    pub proficiency: bool,
15}
16
17impl Add for AbilityScore {
18    type Output = Self;
19
20    fn add(self, other: Self) -> Self {
21        Self {
22            score: self.score + other.score,
23            proficiency: self.proficiency || other.proficiency,
24        }
25    }
26}
27
28impl AddAssign for AbilityScore {
29    fn add_assign(&mut self, other: Self) {
30        self.score += other.score;
31        self.proficiency = self.proficiency || other.proficiency;
32    }
33}
34
35impl Sum for AbilityScore {
36    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
37        let mut total = AbilityScore::default();
38
39        for ability in iter {
40            total += ability;
41        }
42
43        total
44    }
45}
46
47impl AbilityScore {
48    pub fn new(score: u8, proficiency: bool) -> Self {
49        Self { score, proficiency }
50    }
51    /// Returns the modifier of the ability score
52    /// if you want to add the proficiency bonus, pass it as an argument otherwise pass 0
53    pub fn modifier(&self, proficiency_bonus: u8) -> i8 {
54        ((self.score as i8 - 10) as f32 / 2f32).floor() as i8
55            + if self.proficiency {
56                proficiency_bonus as i8
57            } else {
58                0
59            }
60    }
61}
62
63pub const ABILITY_NAMES: [&str; 6] = [
64    "strength",
65    "dexterity",
66    "constitution",
67    "intelligence",
68    "wisdom",
69    "charisma",
70];
71
72#[derive(Debug, Default, Clone)]
73#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
74#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
75#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
76pub struct Abilities {
77    pub strength: AbilityScore,
78    pub dexterity: AbilityScore,
79    pub constitution: AbilityScore,
80    pub intelligence: AbilityScore,
81    pub wisdom: AbilityScore,
82    pub charisma: AbilityScore,
83}
84
85impl Add for Abilities {
86    type Output = Self;
87
88    fn add(self, other: Self) -> Self {
89        Self {
90            strength: self.strength + other.strength,
91            dexterity: self.dexterity + other.dexterity,
92            constitution: self.constitution + other.constitution,
93            intelligence: self.intelligence + other.intelligence,
94            wisdom: self.wisdom + other.wisdom,
95            charisma: self.charisma + other.charisma,
96        }
97    }
98}
99
100impl AddAssign for Abilities {
101    fn add_assign(&mut self, other: Self) {
102        self.strength += other.strength;
103        self.dexterity += other.dexterity;
104        self.constitution += other.constitution;
105        self.intelligence += other.intelligence;
106        self.wisdom += other.wisdom;
107        self.charisma += other.charisma;
108    }
109}
110
111impl Sum for Abilities {
112    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
113        let mut total = Abilities::default();
114
115        for abilities_set in iter {
116            total += abilities_set; // Uses AddAssign
117        }
118
119        total
120    }
121}