diff --git a/src/game/character_sheet.rs b/src/game/character_sheet.rs index 1e89eba..773c61a 100644 --- a/src/game/character_sheet.rs +++ b/src/game/character_sheet.rs @@ -2,24 +2,27 @@ use std::fmt::Debug; use serde::{Deserialize, Serialize}; -use super::{entry::{ActionDefinition, ActionResult, GameEntry}, chat_message::ChatMessage}; +use super::{ + chat_message::ChatMessage, + entry::{ActionDefinition, ActionResult, GameEntry}, +}; -pub trait Character : CharacterSheet { +pub trait Character: CharacterSheet { /// types of actions that can be done on the specified entry (e.g. cast for spells and wear for armor) fn actions(&self, entry: &E) -> Vec; /// uses an action for a specific character, some actions should be split into multiple - /// + /// /// for example, an attack sequence will be of: - /// + /// /// - `Attack` invoked on a weapon entry, which will have the `roll damage` option in the chat /// - `roll damage` will be done on the attacking character, which show the `damage` and `double` actions /// - `damage` will be used on the target character (which could apply reductions as well) fn use_action(&mut self, entry: &E, action: &ActionResult) -> ChatMessage; /// character short display, containing basic info like name(title) level and health - fn short(&self) -> CharacterShort; + fn short(&self, id: usize) -> CharacterShort; } -pub trait CharacterSheet : Default { +pub trait CharacterSheet: Default { /// Character sheet inputs (stuff that are not calculated from different items), such as Name, Age, Strength fn inputs(&self, access: AccessLevel) -> Vec<(String, EntryType)>; /// All fields in the character sheet, maybe change it to only a vec of strings? @@ -34,7 +37,10 @@ pub trait CharacterSheet : Default { #[derive(Debug, Copy, Clone)] pub enum AccessLevel { - Admin = 0, Owner = 1, PartyMember = 2, World = 3, + Admin = 0, + Owner = 1, + PartyMember = 2, + World = 3, } impl AccessLevel { pub fn has_access(self, other: Self) -> bool { @@ -44,10 +50,10 @@ impl AccessLevel { /// Short character description to be shown in a simple small card, /// any of the fields can be empty apart from title (as it makes no sense to omit that) -/// +/// /// following is a diagram of what it should look like (dots are part of title), tho actual looks depend /// on the clients themselves -/// +/// /// ```text /// _______________________ /// | TITLE ... level | @@ -66,12 +72,6 @@ pub struct CharacterShort { pub health: Option, pub level: Option, } -impl CharacterShort { - pub fn with_id(mut self, id: usize) -> Self { - self.id = id; - self - } -} #[derive(Debug, Serialize, Deserialize)] pub enum EntryType { @@ -87,28 +87,17 @@ impl Default for EntryType { } impl EntryType { pub fn as_num(&self) -> i32 { - if let EntryType::Number(n) = *self { - n - } - else { - 0 - } + if let EntryType::Number(n) = *self { n } else { 0 } } pub fn as_text(&self) -> String { if let EntryType::Text(t) = self { t.clone() - } - else { + } else { String::new() } } pub fn as_bool(&self) -> bool { - if let EntryType::Bool(b) = *self { - b - } - else { - false - } + if let EntryType::Bool(b) = *self { b } else { false } } } impl std::fmt::Display for EntryType { @@ -122,11 +111,11 @@ impl std::fmt::Display for EntryType { if v.len() > 0 { for i in v.iter().take(v.len() - 1) { write!(f, "{}, ", i)?; - }; + } write!(f, "{} ", v.iter().last().unwrap())?; }; write!(f, "]") - }, + } } } -} \ No newline at end of file +} diff --git a/src/game/mod.rs b/src/game/mod.rs index d9471de..1cf4e50 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -164,9 +164,7 @@ impl<'a, C: Character + Serialize + Deserialize<'a>, A: entry::GameEntry + Se } fn character_short(&self, character_id: usize) -> Option { - self.characters - .get(character_id) - .map(|c| c.0.short().with_id(character_id)) + self.characters.get(character_id).map(|c| c.0.short(character_id)) } fn scenes(&self) -> Vec { @@ -179,7 +177,7 @@ impl<'a, C: Character + Serialize + Deserialize<'a>, A: entry::GameEntry + Se s.characters .iter() .filter(|c| party.can_see(c.1)) - .map(|c| self.characters.get(c.0).map(|e| e.0.short().with_id(c.0))) + .map(|c| self.characters.get(c.0).map(|e| e.0.short(c.0))) .flatten() .collect() }) diff --git a/src/pathfinder2r_impl/mod.rs b/src/pathfinder2r_impl/mod.rs index 5246a62..4f324cc 100644 --- a/src/pathfinder2r_impl/mod.rs +++ b/src/pathfinder2r_impl/mod.rs @@ -1,4 +1,8 @@ -use crate::game::{character_sheet::*, chat_message::ChatMessage, entry::{ActionDefinition, ActionResult, DiceRoll, GameEntry}}; +use crate::game::{ + character_sheet::*, + chat_message::ChatMessage, + entry::{ActionDefinition, ActionResult, DiceRoll, GameEntry}, +}; use serde::{Deserialize, Serialize}; use tavern_macros::CharacterSheet; @@ -58,11 +62,7 @@ pub struct Pathfinder2rCharacterSheet { impl Pathfinder2rCharacterSheet { fn set_items(&mut self, entry: EntryType) { if let EntryType::Array(a) = entry { - let ws: Vec = a - .iter() - .map(|e| Entry::load(&e.as_text())) - .flatten() - .collect(); + let ws: Vec = a.iter().map(|e| Entry::load(&e.as_text())).flatten().collect(); self.weapon = [None, None]; for w in ws { if let Entry::Weapon(w) = w { @@ -74,8 +74,7 @@ impl Pathfinder2rCharacterSheet { } } } - } - else { + } else { let s = entry.as_text(); if let Some(Entry::Weapon(w)) = Entry::load(&s) { self.weapon[0] = Some(w); @@ -97,46 +96,61 @@ impl Character for Pathfinder2rCharacterSheet { fn use_action(&mut self, entry: &Entry, action: &ActionResult) -> ChatMessage { match entry { Entry::Weapon(_) => ChatMessage::new("Attack".to_string()) - .with_action( - ActionDefinition::new("Attack".to_string()) - .with_roll(DiceRoll::new("Piercing".to_string(), 12, 1)) - ) - .with_action( - ActionDefinition::new("Double".to_string()) - .with_roll(DiceRoll::new("Piercing".to_string(), 12, 2)) - ), - Entry::Consumable(_consumable) => if action.name == "consume" { - ChatMessage::new("Heal".to_string()) - .with_action( + .with_action(ActionDefinition::new("Attack".to_string()).with_roll(DiceRoll::new( + "Piercing".to_string(), + 12, + 1, + ))) + .with_action(ActionDefinition::new("Double".to_string()).with_roll(DiceRoll::new( + "Piercing".to_string(), + 12, + 2, + ))), + Entry::Consumable(_consumable) => { + if action.name == "consume" { + ChatMessage::new("Heal".to_string()).with_action( ActionDefinition::new("Heal".to_string()) - .with_roll(DiceRoll::new("Heal".to_string(), 6, 0).constant(6)) + .with_roll(DiceRoll::new("Heal".to_string(), 6, 0).constant(6)), ) - } else { todo!() }, + } else { + todo!() + } + } Entry::Spell(_spell) => todo!(), } } - + fn actions(&self, entry: &Entry) -> Vec { let v; match entry { - Entry::Weapon(_) => - // should technically check if the item is in the user's packpack or something - // but for now just return a constant list - v = vec![ ("wield", 0), ("attack", 1), ("drop", 0), ("stow", 0) ], + Entry::Weapon(_) => + // should technically check if the item is in the user's packpack or something + // but for now just return a constant list + { + v = vec![("wield", 0), ("attack", 1), ("drop", 0), ("stow", 0)] + } Entry::Consumable(_) => v = vec![("consume", 0), ("stow", 0), ("drop", 0)], Entry::Spell(_) => v = vec![("cast", 1)], }; v.iter() - .map(|s| ActionDefinition { name: s.0.to_string(), targets: s.1, display_name: None, source: None, rolls: None }) + .map(|s| ActionDefinition { + name: s.0.to_string(), + targets: s.1, + display_name: None, + source: None, + rolls: None, + }) .collect() } - - fn short(&self) -> CharacterShort { + + fn short(&self, id: usize) -> CharacterShort { CharacterShort { - id: 0, + id, title: self.name.clone(), sub_title: Some("A Character!".to_string()), - health: Some([ "Dying", "Hurt", "Harmed", "Unharmed" ][((self.health * 4) / self.max_health) as usize].to_string()), + health: Some( + ["Dying", "Hurt", "Harmed", "Unharmed"][((self.health * 4) / self.max_health) as usize].to_string(), + ), level: Some(1), } }