Updated query parameters for spells

This commit is contained in:
Benjamin Sherriff
2023-10-04 13:09:04 -04:00
parent 4d3e8ae981
commit 8da46fdd5e
8 changed files with 422 additions and 199 deletions

View File

@@ -6,7 +6,7 @@
"ritual": false,
"casting_time": {
"amount": 1,
"type": "action"
"unit": "action"
},
"range": {
"type": "point",
@@ -49,7 +49,7 @@
"ritual": false,
"casting_time": {
"amount": 1,
"type": "action"
"unit": "action"
},
"range": {
"type": "self"
@@ -88,7 +88,7 @@
"ritual": false,
"casting_time": {
"amount": 1,
"type": "action"
"unit": "action"
},
"range": {
"type": "touch"
@@ -134,7 +134,7 @@
"ritual": false,
"casting_time": {
"amount": 1,
"type": "action"
"unit": "action"
},
"range": {
"type": "point",
@@ -177,7 +177,7 @@
"ritual": false,
"casting_time": {
"amount": 1,
"type": "action"
"unit": "action"
},
"range": {
"type": "point",
@@ -232,7 +232,7 @@
"ritual": false,
"casting_time": {
"amount": 1,
"type": "action"
"unit": "action"
},
"range": {
"type": "point",
@@ -276,7 +276,7 @@
"ritual": false,
"casting_time": {
"amount": 1,
"type": "action"
"unit": "action"
},
"range": {
"type": "point",
@@ -315,7 +315,7 @@
"ritual": false,
"casting_time": {
"amount": 1,
"type": "action"
"unit": "action"
},
"range": {
"type": "point",
@@ -359,7 +359,7 @@
"ritual": false,
"casting_time": {
"amount": 1,
"type": "action"
"unit": "action"
},
"range": {
"type": "point",
@@ -391,5 +391,41 @@
"The spell creates more than one beam when you reach higher levels: two beams at 5th level, three beams at 11th level, and four beams at 17th level. You can direct the beams at the same target or at different ones. Make a separate attack roll for each beam."
]
}
},
{
"name": "Encode Thoughts",
"school": "enchantment",
"level": 0,
"ritual": true,
"casting_time": {
"amount": 1,
"unit": "action"
},
"range": {
"type": "self"
},
"components": {
"verbal": false,
"somatic": true,
"material": false
},
"durations": [
{
"type": "timed",
"amount": 8,
"unit": "hours"
}
],
"classes": ["wizard"],
"sources": [
{ "source": "GGR", "page": 47 }
],
"description": {
"entries": [
"Putting a finger to your head, you pull a memory, an idea, or a message from your mind and transform it into a tangible string of glowing energy called a thought strand, which persists for the duration or until you cast this spell again. The thought strand appears in an unoccupied space within 5 feet of you as a Tiny, weightless, semisolid object that can be held and carried like a ribbon. It is otherwise stationary.",
"If you cast this spell while concentrating on a spell or an ability that allows you to read or manipulate the thoughts of others (such as {@spell detect thoughts} or {@spell modify memory}), you can transform the thoughts or memories you read, rather than your own, into a thought strand.",
"Casting this spell while holding a thought strand allows you to instantly receive whatever memory, idea, or message the thought strand contains. (Casting {@spell detect thoughts} on the strand has the same effect.)"
]
}
}
]

View File

@@ -1,5 +1,15 @@
CREATE TABLE IF NOT EXISTS spells (
id INTEGER GENERATED ALWAYS AS IDENTITY,
name TEXT NOT NULL,
school TEXT NOT NULL,
level INTEGER NOT NULL,
ritual BOOLEAN DEFAULT FALSE,
concentration BOOLEAN DEFAULT FALSE,
classes TEXT[] NOT NULL,
damage_inflict TEXT[] NOT NULL,
damage_resist TEXT[] NOT NULL,
conditions TEXT[] NOT NULL,
saving_throw TEXT[] NOT NULL,
attack_type TEXT,
data JSONB NOT NULL
);

View File

@@ -1,4 +1,4 @@
// use std::str::FromStr;
use std::str::FromStr;
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
@@ -17,30 +17,30 @@ pub enum AbilityType {
Charisma
}
// impl AbilityType {
// pub fn to_string(&self) -> String {
// match self {
// AbilityType::Strength => "Strength".to_string(),
// AbilityType::Dexterity => "Dexterity".to_string(),
// AbilityType::Constitution => "Constitution".to_string(),
// AbilityType::Intelligence => "Intelligence".to_string(),
// AbilityType::Wisdom => "Wisdom".to_string(),
// AbilityType::Charisma => "Charisma".to_string()
// }
// }
// }
impl AbilityType {
pub fn to_string(&self) -> String {
match self {
AbilityType::Strength => "Strength".to_string(),
AbilityType::Dexterity => "Dexterity".to_string(),
AbilityType::Constitution => "Constitution".to_string(),
AbilityType::Intelligence => "Intelligence".to_string(),
AbilityType::Wisdom => "Wisdom".to_string(),
AbilityType::Charisma => "Charisma".to_string()
}
}
}
// impl FromStr for AbilityType {
// type Err = ();
// fn from_str(s: &str) -> Result<Self, Self::Err> {
// match s {
// "Strength" => Ok(AbilityType::Strength),
// "Dexterity" => Ok(AbilityType::Dexterity),
// "Constitution" => Ok(AbilityType::Constitution),
// "Intelligence" => Ok(AbilityType::Intelligence),
// "Wisdom" => Ok(AbilityType::Wisdom),
// "Charisma" => Ok(AbilityType::Charisma),
// _ => Err(())
// }
// }
// }
impl FromStr for AbilityType {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Strength" => Ok(AbilityType::Strength),
"Dexterity" => Ok(AbilityType::Dexterity),
"Constitution" => Ok(AbilityType::Constitution),
"Intelligence" => Ok(AbilityType::Intelligence),
"Wisdom" => Ok(AbilityType::Wisdom),
"Charisma" => Ok(AbilityType::Charisma),
_ => Err(())
}
}
}

View File

@@ -1,4 +1,4 @@
// use std::str::FromStr;
use std::str::FromStr;
use serde::{Deserialize, Serialize};
@@ -36,48 +36,48 @@ pub enum ConditionType {
Unconscious
}
// impl ConditionType {
// pub fn to_string(&self) -> String {
// match self {
// ConditionType::Blinded => "Blinded".to_string(),
// ConditionType::Charmed => "Charmed".to_string(),
// ConditionType::Deafened => "Deafened".to_string(),
// ConditionType::Exhaustion => "Exhaustion".to_string(),
// ConditionType::Frightened => "Frightened".to_string(),
// ConditionType::Grappled => "Grappled".to_string(),
// ConditionType::Incapacitated => "Incapacitated".to_string(),
// ConditionType::Invisible => "Invisible".to_string(),
// ConditionType::Paralyzed => "Paralyzed".to_string(),
// ConditionType::Petrified => "Petrified".to_string(),
// ConditionType::Poisoned => "Poisoned".to_string(),
// ConditionType::Prone => "Prone".to_string(),
// ConditionType::Restrained => "Restrained".to_string(),
// ConditionType::Stunned => "Stunned".to_string(),
// ConditionType::Unconscious => "Unconscious".to_string()
// }
// }
// }
impl ConditionType {
pub fn to_string(&self) -> String {
match self {
ConditionType::Blinded => "Blinded".to_string(),
ConditionType::Charmed => "Charmed".to_string(),
ConditionType::Deafened => "Deafened".to_string(),
ConditionType::Exhaustion => "Exhaustion".to_string(),
ConditionType::Frightened => "Frightened".to_string(),
ConditionType::Grappled => "Grappled".to_string(),
ConditionType::Incapacitated => "Incapacitated".to_string(),
ConditionType::Invisible => "Invisible".to_string(),
ConditionType::Paralyzed => "Paralyzed".to_string(),
ConditionType::Petrified => "Petrified".to_string(),
ConditionType::Poisoned => "Poisoned".to_string(),
ConditionType::Prone => "Prone".to_string(),
ConditionType::Restrained => "Restrained".to_string(),
ConditionType::Stunned => "Stunned".to_string(),
ConditionType::Unconscious => "Unconscious".to_string()
}
}
}
// impl FromStr for ConditionType {
// type Err = ();
// fn from_str(s: &str) -> Result<Self, Self::Err> {
// match s {
// "Blinded" => Ok(ConditionType::Blinded),
// "Charmed" => Ok(ConditionType::Charmed),
// "Deafened" => Ok(ConditionType::Deafened),
// "Exhaustion" => Ok(ConditionType::Exhaustion),
// "Frightened" => Ok(ConditionType::Frightened),
// "Grappled" => Ok(ConditionType::Grappled),
// "Incapacitated" => Ok(ConditionType::Incapacitated),
// "Invisible" => Ok(ConditionType::Invisible),
// "Paralyzed" => Ok(ConditionType::Paralyzed),
// "Petrified" => Ok(ConditionType::Petrified),
// "Poisoned" => Ok(ConditionType::Poisoned),
// "Prone" => Ok(ConditionType::Prone),
// "Restrained" => Ok(ConditionType::Restrained),
// "Stunned" => Ok(ConditionType::Stunned),
// "Unconscious" => Ok(ConditionType::Unconscious),
// _ => Err(())
// }
// }
// }
impl FromStr for ConditionType {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Blinded" => Ok(ConditionType::Blinded),
"Charmed" => Ok(ConditionType::Charmed),
"Deafened" => Ok(ConditionType::Deafened),
"Exhaustion" => Ok(ConditionType::Exhaustion),
"Frightened" => Ok(ConditionType::Frightened),
"Grappled" => Ok(ConditionType::Grappled),
"Incapacitated" => Ok(ConditionType::Incapacitated),
"Invisible" => Ok(ConditionType::Invisible),
"Paralyzed" => Ok(ConditionType::Paralyzed),
"Petrified" => Ok(ConditionType::Petrified),
"Poisoned" => Ok(ConditionType::Poisoned),
"Prone" => Ok(ConditionType::Prone),
"Restrained" => Ok(ConditionType::Restrained),
"Stunned" => Ok(ConditionType::Stunned),
"Unconscious" => Ok(ConditionType::Unconscious),
_ => Err(())
}
}
}

View File

@@ -17,6 +17,16 @@ diesel::table! {
spells (id) {
id -> Integer,
name -> Text,
school -> Text,
level -> Integer,
ritual -> Bool,
concentration -> Bool,
classes -> Array<Text>,
damage_inflict -> Array<Text>,
damage_resist -> Array<Text>,
conditions -> Array<Text>,
saving_throw -> Array<Text>,
attack_type -> Nullable<Text>,
data -> Jsonb
}
}

View File

@@ -3,29 +3,39 @@ use serde::{Deserialize, Serialize};
use crate::{db::{schema::spells::{self}, classes::AbilityType, conditions::ConditionType}, error_handler::ServiceError};
use super::{SchoolType, CastingTime, CastingType, SpellAttackType, SpellDamageType, Range, Area, Components, Duration, Source, Description};
use super::{SchoolType, CastingTime, CastingType, SpellAttackType, SpellDamageType, Range, Area, Components, Duration, Source, Description, DurationType};
#[derive(Queryable, QueryableByName)]
#[diesel(table_name = spells)]
pub struct QuerySpell {
pub id: i32,
pub name: String,
pub school: String,
pub level: i32,
pub ritual: bool,
pub concentration: bool,
pub classes: Vec<String>,
pub damage_inflict: Vec<String>,
pub damage_resist: Vec<String>,
pub conditions: Vec<String>,
pub saving_throw: Vec<String>,
pub attack_type: Option<String>,
pub data: serde_json::Value,
}
#[derive(Debug)]
pub struct QueryFilters {
pub by_name: Option<String>,
pub by_schools: Option<Vec<SchoolType>>,
pub by_schools: Option<Vec<String>>,
pub by_levels: Option<Vec<i32>>,
pub by_ritual: Option<bool>,
pub by_concentration: Option<bool>,
pub by_classes: Option<Vec<String>>,
pub by_damage_inflict: Option<Vec<SpellDamageType>>,
pub by_damage_resist: Option<Vec<SpellDamageType>>,
pub by_conditions: Option<Vec<ConditionType>>,
pub by_saving_throw: Option<Vec<AbilityType>>,
pub by_attack_type: Option<SpellAttackType>,
pub by_damage_inflict: Option<Vec<String>>,
pub by_damage_resist: Option<Vec<String>>,
pub by_conditions: Option<Vec<String>>,
pub by_saving_throw: Option<Vec<String>>,
pub by_attack_type: Option<String>,
}
impl Default for QueryFilters {
@@ -53,15 +63,85 @@ impl QuerySpell {
// Limit query to page and limit
let offset = (page - 1) * limit;
query = query.offset(offset as i64);
// Apply filters
if let Some(name) = filters.by_name.to_owned() {
if let Some(name) = &filters.by_name {
query = query.filter(spells::name.ilike(format!("%{}%", name)));
}
if let Some(schools) = &filters.by_schools {
query = query.filter(spells::school.eq_any(schools.iter().map(|school| school.to_string()).collect::<Vec<String>>()));
}
if let Some(levels) = &filters.by_levels {
query = query.filter(spells::level.eq_any(levels));
}
if let Some(ritual) = filters.by_ritual {
query = query.filter(spells::ritual.eq(ritual));
}
if let Some(concentration) = filters.by_concentration {
query = query.filter(spells::concentration.eq(concentration));
}
if let Some(classes) = &filters.by_classes {
query = query.filter(spells::classes.overlaps_with(classes));
}
if let Some(damage_inflict) = &filters.by_damage_inflict {
query = query.filter(spells::damage_inflict.overlaps_with(damage_inflict.iter().map(|damage_inflict| damage_inflict.to_string()).collect::<Vec<String>>()));
}
if let Some(damage_resist) = &filters.by_damage_resist {
query = query.filter(spells::damage_resist.overlaps_with(damage_resist.iter().map(|damage_resist| damage_resist.to_string()).collect::<Vec<String>>()));
}
if let Some(conditions) = &filters.by_conditions {
query = query.filter(spells::conditions.overlaps_with(conditions.iter().map(|condition| condition.to_string()).collect::<Vec<String>>()));
}
if let Some(saving_throw) = &filters.by_saving_throw {
query = query.filter(spells::saving_throw.overlaps_with(saving_throw.iter().map(|saving_throw| saving_throw.to_string()).collect::<Vec<String>>()));
}
if let Some(attack_type) = &filters.by_attack_type {
query = query.filter(spells::attack_type.eq(attack_type.to_string()));
}
let spells = query.load::<QuerySpell>(&mut conn)?;
Ok(spells)
}
pub fn get_count(filters: &QueryFilters) -> Result<i64, ServiceError> {
let mut conn = crate::db::connection()?;
let mut query = spells::table.count().into_boxed();
if let Some(name) = &filters.by_name {
query = query.filter(spells::name.ilike(format!("%{}%", name)));
}
if let Some(schools) = &filters.by_schools {
query = query.filter(spells::school.eq_any(schools.iter().map(|school| school.to_string()).collect::<Vec<String>>()));
}
if let Some(levels) = &filters.by_levels {
query = query.filter(spells::level.eq_any(levels));
}
if let Some(ritual) = filters.by_ritual {
query = query.filter(spells::ritual.eq(ritual));
}
if let Some(concentration) = filters.by_concentration {
query = query.filter(spells::concentration.eq(concentration));
}
if let Some(classes) = &filters.by_classes {
query = query.filter(spells::classes.overlaps_with(classes));
}
if let Some(damage_inflict) = &filters.by_damage_inflict {
query = query.filter(spells::damage_inflict.overlaps_with(damage_inflict.iter().map(|damage_inflict| damage_inflict.to_string()).collect::<Vec<String>>()));
}
if let Some(damage_resist) = &filters.by_damage_resist {
query = query.filter(spells::damage_resist.overlaps_with(damage_resist.iter().map(|damage_resist| damage_resist.to_string()).collect::<Vec<String>>()));
}
if let Some(conditions) = &filters.by_conditions {
query = query.filter(spells::conditions.overlaps_with(conditions.iter().map(|condition| condition.to_string()).collect::<Vec<String>>()));
}
if let Some(saving_throw) = &filters.by_saving_throw {
query = query.filter(spells::saving_throw.overlaps_with(saving_throw.iter().map(|saving_throw| saving_throw.to_string()).collect::<Vec<String>>()));
}
if let Some(attack_type) = &filters.by_attack_type {
query = query.filter(spells::attack_type.eq(attack_type.to_string()));
}
let count = query.get_result(&mut conn)?;
Ok(count)
}
pub fn get_by_id(id: i32) -> Result<Self, ServiceError> {
let mut conn = crate::db::connection()?;
let spell = spells::table
@@ -70,17 +150,6 @@ impl QuerySpell {
Ok(spell)
}
pub fn get_count(filters: &QueryFilters) -> Result<i64, ServiceError> {
let mut conn = crate::db::connection()?;
let mut query = spells::table.count().into_boxed();
if let Some(name) = filters.by_name.to_owned() {
query = query.filter(spells::name.ilike(format!("%{}%", name)));
}
let count = query.get_result(&mut conn)?;
Ok(count)
}
pub fn delete(id: i32) -> Result<Self, ServiceError> {
let mut conn = crate::db::connection()?;
let spell = diesel::delete(spells::table.filter(spells::id.eq(id))).get_result(&mut conn)?;
@@ -92,6 +161,16 @@ impl QuerySpell {
#[diesel(table_name = spells)]
pub struct InsertSpell {
pub name: String,
pub school: String,
pub level: i32,
pub ritual: bool,
pub concentration: bool,
pub classes: Vec<String>,
pub damage_inflict: Vec<String>,
pub damage_resist: Vec<String>,
pub conditions: Vec<String>,
pub saving_throw: Vec<String>,
pub attack_type: Option<String>,
pub data: serde_json::Value
}
@@ -174,13 +253,38 @@ impl Into<InsertSpell> for Spell {
fn into(self) -> InsertSpell {
return InsertSpell {
name: self.name.to_string(),
school: self.school.to_string(),
level: self.level,
ritual: self.ritual,
concentration: self.durations.iter().any(|duration| match duration.duration_type {
DurationType::Concentration => true,
_ => false
}),
classes: self.classes.iter().map(|class| class.to_string()).collect::<Vec<String>>(),
damage_inflict: match &self.damage_inflict {
Some(damage_inflict) => damage_inflict.iter().map(|damage_inflict| damage_inflict.to_string()).collect(),
None => vec![]
},
damage_resist: match &self.damage_resist {
Some(damage_resist) => damage_resist.iter().map(|damage_resist| damage_resist.to_string()).collect(),
None => vec![]
},
conditions: match &self.conditions {
Some(conditions) => conditions.iter().map(|condition| condition.to_string()).collect(),
None => vec![]
},
saving_throw: match &self.saving_throw {
Some(saving_throw) => saving_throw.iter().map(|saving_throw| saving_throw.to_string()).collect(),
None => vec![]
},
attack_type: self.attack_type.as_ref().map(|attack_type| attack_type.to_string()),
data: match serde_json::to_value(&self) {
Ok(data) => data,
Err(err) => {
log::error!("Failed to serialize spell description: {}", err);
log::error!("Failed to serialize spell: {}", err);
serde_json::Value::Null
}
},
}
}
}
}

View File

@@ -1,4 +1,5 @@
use actix_web::{get, post, put, delete, web, HttpResponse, HttpRequest, ResponseError};
use log::error;
use serde::{Serialize, Deserialize};
use crate::{db::{spells::{QuerySpell, QueryFilters}, GetResponse, Metadata}, error_handler::ServiceError};
@@ -8,6 +9,16 @@ use super::{Spell, InsertSpell};
#[derive(Serialize, Deserialize)]
struct GetAllParams {
name: Option<String>,
schools: Option<String>,
levels: Option<String>,
ritual: Option<bool>,
concentration: Option<bool>,
classes: Option<String>,
damage_inflict: Option<String>,
damage_resist: Option<String>,
conditions: Option<String>,
saving_throw: Option<String>,
attack_type: Option<String>,
limit: Option<i32>,
page: Option<i32>,
}
@@ -23,6 +34,43 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
};
let mut filters = QueryFilters::default();
filters.by_name = params.name.clone();
filters.by_schools = match &params.schools {
Some(schools) => Some(schools.split(",").map(|s| s.to_string()).collect()),
None => None
};
filters.by_levels = match &params.levels {
Some(levels) => Some(levels.split(",").map(|s| match s.to_string().parse::<i32>() {
Ok(level) => level,
Err(_) => 0
}).collect()),
None => None
};
filters.by_ritual = params.ritual;
filters.by_concentration = params.concentration;
filters.by_classes = match &params.classes {
Some(classes) => Some(classes.split(",").map(|s| s.to_string()).collect()),
None => None
};
filters.by_damage_inflict = match &params.damage_inflict {
Some(damage_inflict) => Some(damage_inflict.split(",").map(|s| s.to_string()).collect()),
None => None
};
filters.by_damage_resist = match &params.damage_resist {
Some(damage_resist) => Some(damage_resist.split(",").map(|s| s.to_string()).collect()),
None => None
};
filters.by_conditions = match &params.conditions {
Some(conditions) => Some(conditions.split(",").map(|s| s.to_string()).collect()),
None => None
};
filters.by_saving_throw = match &params.saving_throw {
Some(saving_throw) => Some(saving_throw.split(",").map(|s| s.to_string()).collect()),
None => None
};
filters.by_attack_type = match &params.attack_type {
Some(attack_type) => Some(attack_type.split(",").map(|s| s.to_string()).collect()),
None => None
};
// Limit must be between 1 and 100
let limit = std::cmp::min(std::cmp::max(params.limit.unwrap_or(20), 1), 100);
let total_count = QuerySpell::get_count(&filters).unwrap();
@@ -46,7 +94,10 @@ async fn get_all(req: HttpRequest) -> HttpResponse {
})
})
},
Err(err) => ResponseError::error_response(&err)
Err(err) => {
error!("{:?}", err.message);
ResponseError::error_response(&err)
}
}
}
@@ -64,7 +115,10 @@ async fn get_by_id(id: web::Path<String>) -> HttpResponse {
data: Spell::from(spell),
metadata: None
}),
Err(err) => ResponseError::error_response(&err)
Err(err) => {
error!("{:?}", err.message);
ResponseError::error_response(&err)
}
}
}
@@ -72,7 +126,10 @@ async fn get_by_id(id: web::Path<String>) -> HttpResponse {
async fn create(spell: web::Json<Spell>) -> HttpResponse {
match InsertSpell::insert(spell.into_inner().into()) {
Ok(spell) => HttpResponse::Created().json(Spell::from(spell)),
Err(err) => ResponseError::error_response(&err)
Err(err) => {
error!("{:?}", err.message);
ResponseError::error_response(&err)
}
}
}
@@ -87,7 +144,10 @@ async fn update(id: web::Path<String>, spell: web::Json<Spell>) -> HttpResponse
};
match web::block(move || InsertSpell::update(id, spell.into_inner().into())).await.unwrap() {
Ok(spell) => HttpResponse::Ok().json(Spell::from(spell)),
Err(err) => ResponseError::error_response(&err)
Err(err) => {
error!("{:?}", err.message);
ResponseError::error_response(&err)
}
}
}
@@ -102,7 +162,10 @@ async fn delete(id: web::Path<String>) -> HttpResponse {
};
match web::block(move || QuerySpell::delete(id)).await.unwrap() {
Ok(spell) => HttpResponse::Ok().json(Spell::from(spell)),
Err(err) => ResponseError::error_response(&err)
Err(err) => {
error!("{:?}", err.message);
ResponseError::error_response(&err)
}
}
}

View File

@@ -1,4 +1,4 @@
// use std::str::FromStr;
use std::str::FromStr;
use serde::{Deserialize, Serialize, ser::SerializeMap};
#[derive(Debug, Serialize, Deserialize)]
@@ -21,43 +21,43 @@ pub enum SchoolType {
Transmutation
}
// impl SchoolType {
// pub fn to_string(&self) -> String {
// match self {
// SchoolType::Abjuration => "abjuration".to_string(),
// SchoolType::Conjuration => "conjuration".to_string(),
// SchoolType::Divination => "divination".to_string(),
// SchoolType::Enchantment => "enchantment".to_string(),
// SchoolType::Evocation => "evocation".to_string(),
// SchoolType::Illusion => "illusion".to_string(),
// SchoolType::Necromancy => "necromancy".to_string(),
// SchoolType::Transmutation => "transmutation".to_string()
// }
// }
// }
impl SchoolType {
pub fn to_string(&self) -> String {
match self {
SchoolType::Abjuration => "abjuration".to_string(),
SchoolType::Conjuration => "conjuration".to_string(),
SchoolType::Divination => "divination".to_string(),
SchoolType::Enchantment => "enchantment".to_string(),
SchoolType::Evocation => "evocation".to_string(),
SchoolType::Illusion => "illusion".to_string(),
SchoolType::Necromancy => "necromancy".to_string(),
SchoolType::Transmutation => "transmutation".to_string()
}
}
}
// impl FromStr for SchoolType {
// type Err = ();
impl FromStr for SchoolType {
type Err = ();
// fn from_str(s: &str) -> Result<Self, Self::Err> {
// match s {
// "abjuration" => Ok(SchoolType::Abjuration),
// "conjuration" => Ok(SchoolType::Conjuration),
// "divination" => Ok(SchoolType::Divination),
// "enchantment" => Ok(SchoolType::Enchantment),
// "evocation" => Ok(SchoolType::Evocation),
// "illusion" => Ok(SchoolType::Illusion),
// "necromancy" => Ok(SchoolType::Necromancy),
// "transmutation" => Ok(SchoolType::Transmutation),
// _ => Err(())
// }
// }
// }
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"abjuration" => Ok(SchoolType::Abjuration),
"conjuration" => Ok(SchoolType::Conjuration),
"divination" => Ok(SchoolType::Divination),
"enchantment" => Ok(SchoolType::Enchantment),
"evocation" => Ok(SchoolType::Evocation),
"illusion" => Ok(SchoolType::Illusion),
"necromancy" => Ok(SchoolType::Necromancy),
"transmutation" => Ok(SchoolType::Transmutation),
_ => Err(())
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CastingTime {
pub amount: i32,
#[serde(rename = "type")]
#[serde(rename = "unit")]
pub casting_type: CastingType
}
@@ -110,26 +110,26 @@ pub enum SpellAttackType {
Ranged,
}
// impl SpellAttackType {
// pub fn to_string(&self) -> String {
// match self {
// SpellAttackType::Melee => "melee".to_string(),
// SpellAttackType::Ranged => "ranged".to_string()
// }
// }
// }
impl SpellAttackType {
pub fn to_string(&self) -> String {
match self {
SpellAttackType::Melee => "melee".to_string(),
SpellAttackType::Ranged => "ranged".to_string()
}
}
}
// impl FromStr for SpellAttackType {
// type Err = ();
impl FromStr for SpellAttackType {
type Err = ();
// fn from_str(s: &str) -> Result<Self, Self::Err> {
// match s {
// "melee" => Ok(SpellAttackType::Melee),
// "ranged" => Ok(SpellAttackType::Ranged),
// _ => Err(())
// }
// }
// }
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"melee" => Ok(SpellAttackType::Melee),
"ranged" => Ok(SpellAttackType::Ranged),
_ => Err(())
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub enum SpellDamageType {
@@ -161,48 +161,48 @@ pub enum SpellDamageType {
Thunder
}
// impl SpellDamageType {
// pub fn to_string(&self) -> String {
// match self {
// SpellDamageType::Acid => "acid".to_string(),
// SpellDamageType::Bludgeoning => "bludgeoning".to_string(),
// SpellDamageType::Cold => "cold".to_string(),
// SpellDamageType::Fire => "fire".to_string(),
// SpellDamageType::Force => "force".to_string(),
// SpellDamageType::Lightning => "lightning".to_string(),
// SpellDamageType::Necrotic => "necrotic".to_string(),
// SpellDamageType::Piercing => "piercing".to_string(),
// SpellDamageType::Poison => "poison".to_string(),
// SpellDamageType::Psychic => "psychic".to_string(),
// SpellDamageType::Radiant => "radiant".to_string(),
// SpellDamageType::Slashing => "slashing".to_string(),
// SpellDamageType::Thunder => "thunder".to_string()
// }
// }
// }
impl SpellDamageType {
pub fn to_string(&self) -> String {
match self {
SpellDamageType::Acid => "acid".to_string(),
SpellDamageType::Bludgeoning => "bludgeoning".to_string(),
SpellDamageType::Cold => "cold".to_string(),
SpellDamageType::Fire => "fire".to_string(),
SpellDamageType::Force => "force".to_string(),
SpellDamageType::Lightning => "lightning".to_string(),
SpellDamageType::Necrotic => "necrotic".to_string(),
SpellDamageType::Piercing => "piercing".to_string(),
SpellDamageType::Poison => "poison".to_string(),
SpellDamageType::Psychic => "psychic".to_string(),
SpellDamageType::Radiant => "radiant".to_string(),
SpellDamageType::Slashing => "slashing".to_string(),
SpellDamageType::Thunder => "thunder".to_string()
}
}
}
// impl FromStr for SpellDamageType {
// type Err = ();
impl FromStr for SpellDamageType {
type Err = ();
// fn from_str(s: &str) -> Result<Self, Self::Err> {
// match s {
// "acid" => Ok(SpellDamageType::Acid),
// "bludgeoning" => Ok(SpellDamageType::Bludgeoning),
// "cold" => Ok(SpellDamageType::Cold),
// "fire" => Ok(SpellDamageType::Fire),
// "force" => Ok(SpellDamageType::Force),
// "lightning" => Ok(SpellDamageType::Lightning),
// "necrotic" => Ok(SpellDamageType::Necrotic),
// "piercing" => Ok(SpellDamageType::Piercing),
// "poison" => Ok(SpellDamageType::Poison),
// "psychic" => Ok(SpellDamageType::Psychic),
// "radiant" => Ok(SpellDamageType::Radiant),
// "slashing" => Ok(SpellDamageType::Slashing),
// "thunder" => Ok(SpellDamageType::Thunder),
// _ => Err(())
// }
// }
// }
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"acid" => Ok(SpellDamageType::Acid),
"bludgeoning" => Ok(SpellDamageType::Bludgeoning),
"cold" => Ok(SpellDamageType::Cold),
"fire" => Ok(SpellDamageType::Fire),
"force" => Ok(SpellDamageType::Force),
"lightning" => Ok(SpellDamageType::Lightning),
"necrotic" => Ok(SpellDamageType::Necrotic),
"piercing" => Ok(SpellDamageType::Piercing),
"poison" => Ok(SpellDamageType::Poison),
"psychic" => Ok(SpellDamageType::Psychic),
"radiant" => Ok(SpellDamageType::Radiant),
"slashing" => Ok(SpellDamageType::Slashing),
"thunder" => Ok(SpellDamageType::Thunder),
_ => Err(())
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Range {