use std::collections::{HashMap};
use std::hash::Hash;
use serde::{Deserialize, Serialize};
use crate::abilities::Abilities;
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub enum ClassSpellCasting {
KnowledgePrepared {
spells_index: Vec<Vec<String>>,
spells_prepared_index: Vec<Vec<String>>,
pending_preparation: bool,
},
AlreadyKnowPrepared {
spells_prepared_index: Vec<Vec<String>>,
pending_preparation: bool,
},
KnowledgeAlreadyPrepared {
spells_index: Vec<Vec<String>>,
usable_slots: UsableSlots,
},
}
#[derive(Debug, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct UsableSlots {
pub level_1: u8,
pub level_2: u8,
pub level_3: u8,
pub level_4: u8,
pub level_5: u8,
pub level_6: u8,
pub level_7: u8,
pub level_8: u8,
pub level_9: u8,
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct ClassProperties {
pub level: u8,
pub subclass: Option<String>,
pub spell_casting: Option<ClassSpellCasting>,
pub fighting_style: Option<String>,
pub abilities_modifiers: Abilities,
}
impl Default for ClassProperties {
fn default() -> Self {
Self {
level: 1,
subclass: None,
spell_casting: None,
fighting_style: None,
abilities_modifiers: Abilities::default(),
}
}
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct Class(String, pub ClassProperties);
impl Hash for Class {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl PartialEq for Class {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl Eq for Class {}
impl Class {
pub fn index(&self) -> &str {
&self.0
}
pub fn hit_dice(&self) -> u8 {
match self.index() {
"barbarian" => 12,
"bard" => 8,
"cleric" => 8,
"druid" => 8,
"fighter" => 10,
"monk" => 8,
"paladin" => 10,
"ranger" => 10,
"rogue" => 8,
"sorcerer" => 6,
"warlock" => 8,
"wizard" => 6,
_ => 6,
}
}
}
#[derive(Default, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct Classes(pub HashMap<String, Class>);
impl Classes {
pub fn new(class_index: String) -> Self {
let mut classes = Self::default();
let spell_casting = match class_index.as_str() {
"cleric" | "paladin" | "druid" => {
Some(ClassSpellCasting::AlreadyKnowPrepared {
spells_prepared_index: Vec::new(),
pending_preparation: true,
})
}
_ => {
None
}
};
let class_properties = ClassProperties {
spell_casting,
..ClassProperties::default()
};
classes.0.insert(class_index.clone(), Class(class_index, class_properties));
classes
}
}