gamemstr_common/
creature.rs

1use core::fmt;
2use std::collections::HashMap;
3
4use serde::{Deserialize, Serialize};
5use uuid::Uuid;
6
7use crate::{
8    action::Action, monster::MonsterType, Alignment, AttributeInfo, ConditionType, DamageType, Die,
9    DieStat, OtherAttribute,
10};
11
12#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
13pub struct Creature {
14    pub id: String,
15    pub name: String,
16    pub attributes: HashMap<AttributeType, Attribute>,
17}
18
19impl Creature {
20    pub fn new(name: String, attributes: HashMap<AttributeType, Attribute>) -> Self {
21        Self {
22            id: Uuid::new_v4().to_string(),
23            name,
24            attributes,
25        }
26    }
27}
28
29#[derive(Serialize, Deserialize, Debug)]
30pub struct CreatureRequest {
31    pub name: Option<String>,
32    pub attributes: Option<HashMap<AttributeType, Attribute>>,
33}
34
35impl CreatureRequest {
36    pub fn to_creature(&self) -> Option<Creature> {
37        match &self.name {
38            Some(name) => Some(Creature::new(
39                name.to_string(),
40                self.attributes.clone().expect("No attributes provided"),
41            )),
42            None => None,
43        }
44    }
45}
46
47#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
48pub enum AttributeType {
49    CreatureType(AttributeInfo),
50    Alignment(AttributeInfo),
51    ArmorClass(AttributeInfo),
52    HealthPoints(AttributeInfo),
53    Speed(AttributeInfo),
54    Stats(AttributeInfo),
55    SavingThrows(AttributeInfo),
56    DamageResistances(AttributeInfo),
57    DamageImmunities(AttributeInfo),
58    DamageVulnerabilities(AttributeInfo),
59    ConditionImmunities(AttributeInfo),
60    Skills(AttributeInfo),
61    Senses(AttributeInfo),
62    Languages(AttributeInfo),
63    ChallengeRating(AttributeInfo),
64    RacialTraits(AttributeInfo),
65    Description(AttributeInfo),
66    Actions(AttributeInfo),
67    Lair(AttributeInfo),
68    Other(AttributeInfo),
69}
70
71impl fmt::Display for AttributeType {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        match &self {
74            AttributeType::ArmorClass(i) => write!(f, "{}", i.to_string()),
75            AttributeType::HealthPoints(i) => write!(f, "{}", i.to_string()),
76            AttributeType::SavingThrows(i) => write!(f, "{}", i.to_string()),
77            AttributeType::DamageResistances(i) => write!(f, "{}", i.to_string()),
78            AttributeType::DamageImmunities(i) => write!(f, "{}", i.to_string()),
79            AttributeType::DamageVulnerabilities(i) => write!(f, "{}", i.to_string()),
80            AttributeType::ConditionImmunities(i) => write!(f, "{}", i.to_string()),
81            AttributeType::ChallengeRating(i) => write!(f, "{}", i.to_string()),
82            AttributeType::RacialTraits(i) => write!(f, "{}", i.to_string()),
83            AttributeType::CreatureType(i) => write!(f, "{}", i.to_string()),
84            AttributeType::Alignment(i) => write!(f, "{}", i.to_string()),
85            AttributeType::Speed(i) => write!(f, "{}", i.to_string()),
86            AttributeType::Stats(i) => write!(f, "{}", i.to_string()),
87            AttributeType::Skills(i) => write!(f, "{}", i.to_string()),
88            AttributeType::Senses(i) => write!(f, "{}", i.to_string()),
89            AttributeType::Languages(i) => write!(f, "{}", i.to_string()),
90            AttributeType::Description(i) => write!(f, "{}", i.to_string()),
91            AttributeType::Actions(i) => write!(f, "{}", i.to_string()),
92            AttributeType::Lair(i) => write!(f, "{}", i.to_string()),
93            AttributeType::Other(i) => write!(f, "{}", i.to_string()),
94        }
95    }
96}
97
98#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
99pub enum Attribute {
100    CreatureType(CreatureType),
101    Alignment(Alignment),
102    ArmorClass(i32),
103    HealthPoints(Health),
104    Speed(MovementSpeed),
105    Stat(Stat),
106    SavingThrow(Stat),
107    DamageResistance(DamageType),
108    DamageImmunity(DamageType),
109    DamageVulnerability(DamageType),
110    ConditionImmunity(ConditionType),
111    Skill(Skill),
112    Sense(Sense),
113    Language(Language),
114    ChallengeRating(String),
115    RacialTrait(RacialTrait),
116    Description(String),
117    Action(Action),
118    Lair(Lair),
119    Other(OtherAttribute),
120}
121
122#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
123pub enum MovementSpeed {
124    Walk(u8),
125    Swim(u8),
126    Fly { speed: u8, hover: bool },
127    Burrow(u8),
128    Climb(u8),
129}
130
131impl fmt::Display for MovementSpeed {
132    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
133        match &self {
134            MovementSpeed::Walk(x) => write!(f, "{}ft.", x),
135            MovementSpeed::Burrow(x) => write!(f, "burrow {}ft.", x),
136            MovementSpeed::Swim(x) => write!(f, "swim {}ft.", x),
137            MovementSpeed::Climb(x) => write!(f, "climb {}ft.", x),
138            MovementSpeed::Fly { speed, hover } => {
139                write!(
140                    f,
141                    "fly {}ft.{}",
142                    speed,
143                    if *hover { " (hover)" } else { "" }
144                )
145            }
146        }
147    }
148}
149
150#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
151pub struct Stat {
152    pub stat_type: StatType,
153    pub value: i32,
154    pub modifier: i32,
155}
156
157impl Stat {
158    pub fn from_value(stat_type: StatType, value: i32) -> Self {
159        Self {
160            stat_type,
161            value,
162            modifier: ((value - 10) as f64 / 2_f64).floor() as i32,
163        }
164    }
165}
166
167#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
168pub enum StatType {
169    Strength,
170    Dexterity,
171    Constitution,
172    Intelligence,
173    Wisdom,
174    Charisma,
175}
176
177#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
178pub struct Health {
179    pub health: DieStat,
180}
181
182impl Health {
183    pub fn from_dice(die_count: i32, die_type: Die, extra: i32) -> Self {
184        Self {
185            health: DieStat {
186                die_count,
187                die_type,
188                extra,
189            },
190        }
191    }
192}
193
194impl fmt::Display for Health {
195    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196        write!(f, "{} ({})", self.health.value(), self.health.to_string(),)
197    }
198}
199
200#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
201pub struct Skill {
202    pub skill_type: SkillType,
203    pub modifier: i32,
204}
205
206impl fmt::Display for Skill {
207    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
208        write!(f, "{} {}", self.skill_type.to_string(), self.modifier)
209    }
210}
211
212#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
213pub enum SkillType {
214    Acrobatics,
215    AnimalHandling,
216    Arcana,
217    Athletics,
218    Deception,
219    History,
220    Insight,
221    Intimidation,
222    Investigation,
223    Medicine,
224    Nature,
225    Perception,
226    Performance,
227    Persuasion,
228    Religion,
229    SleightOfHand,
230    Stealth,
231    Survival,
232}
233
234impl fmt::Display for SkillType {
235    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236        match &self {
237            SkillType::Acrobatics => write!(f, "{}", "Acrobatics (Dex)"),
238            SkillType::AnimalHandling => write!(f, "{}", "Animal Handling (Wis)"),
239            SkillType::Arcana => write!(f, "{}", "Arcana (Int)"),
240            SkillType::Athletics => write!(f, "{}", "Athletics (Str)"),
241            SkillType::Deception => write!(f, "{}", "Deception (Cha)"),
242            SkillType::History => write!(f, "{}", "History (Int)"),
243            SkillType::Insight => write!(f, "{}", "Insight (Wis)"),
244            SkillType::Intimidation => write!(f, "{}", "Intimidation (Cha)"),
245            SkillType::Investigation => write!(f, "{}", "Investigation (Int)"),
246            SkillType::Medicine => write!(f, "{}", "Medicine (Wis)"),
247            SkillType::Nature => write!(f, "{}", "Nature (Int)"),
248            SkillType::Perception => write!(f, "{}", "Perception (Wis)"),
249            SkillType::Performance => write!(f, "{}", "Performance (Cha)"),
250            SkillType::Persuasion => write!(f, "{}", "Persuasion (Cha)"),
251            SkillType::Religion => write!(f, "{}", "Religion (Int)"),
252            SkillType::SleightOfHand => write!(f, "{}", "Sleight of Hand (Dex)"),
253            SkillType::Stealth => write!(f, "{}", "Stealth (Dex)"),
254            SkillType::Survival => write!(f, "{}", "Survival (Wis)"),
255        }
256    }
257}
258
259#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
260pub enum Sense {
261    Blindsight(u32),
262    Darkvision(u32),
263    Tremorsense(u32),
264    Truesight(u32),
265}
266
267impl fmt::Display for Sense {
268    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
269        match &self {
270            Sense::Blindsight(x) => write!(f, "Blindsight {} ft.", x),
271            Sense::Darkvision(x) => write!(f, "Darkvision {} ft.", x),
272            Sense::Tremorsense(x) => write!(f, "Tremorsense {} ft.", x),
273            Sense::Truesight(x) => write!(f, "Truesight {} ft.", x),
274        }
275    }
276}
277
278#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
279pub enum Language {
280    Abanasinia,
281    Abyssal,
282    Aquan,
283    Auran,
284    Celestial,
285    Common,
286    DeepSpeech,
287    Draconic,
288    Dwarvish,
289    Elvish,
290    Ergot,
291    Giant,
292    Gnomish,
293    Goblin,
294    Hadozee,
295    Halfling,
296    Ignan,
297    Infernal,
298    Istarian,
299    Kenderspeak,
300    Kharolian,
301    Khur,
302    Kothian,
303    Kraul,
304    Leonin,
305    Loxodon,
306    Marquesian,
307    Merfolk,
308    Minotaur,
309    Naush,
310    Narakese,
311    Nordmaarian,
312    Orc,
313    Primordial,
314    Quori,
315    Riedran,
316    Solamnic,
317    Sphinx,
318    Sylvan,
319    Terran,
320    ThriKreen,
321    Undercommon,
322    Vedalken,
323    Zemnian,
324}
325
326impl fmt::Display for Language {
327    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
328        match &self {
329            Language::DeepSpeech => write!(f, "{}", String::from("Deep Speech")),
330            Language::ThriKreen => write!(f, "{}", String::from("Thri-Kreen")),
331            other => write!(f, "{:?}", other),
332        }
333    }
334}
335
336// TODO:
337#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
338pub enum CreatureType {
339    Monster(MonsterType),
340}
341
342#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
343pub struct RacialTrait {
344    pub name: String,
345    pub description: String,
346}
347
348#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
349pub struct Lair {
350    pub name: String,
351    pub description: String,
352    pub lair_actions: Vec<Paragraph>,
353    pub regional_effects: Vec<Paragraph>,
354}
355
356#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
357pub struct Paragraph {
358    pub paragraph: String,
359    pub bullet: bool,
360}