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#[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}